From 5133a92e42947f7106f7ff807b54886f63e8f705 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Mon, 13 May 2013 16:50:30 +0200 Subject: [PATCH] Add worldmap chart --- MANIFEST.in | 3 -- demo/moulinrouge/tests.py | 11 ++++++- pygal/css/style.css | 24 ++++++++++++++++ pygal/graph/__init__.py | 3 +- pygal/graph/worldmap.py | 60 +++++++++++++++++++++++++++++++++++++++ pygal/style.py | 1 + setup.py | 2 +- 7 files changed, 98 insertions(+), 6 deletions(-) delete mode 100644 MANIFEST.in create mode 100644 pygal/graph/worldmap.py diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 74b68dd..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include pygal/css/*.css -include pygal/js/*.js -include pygal_gen.py diff --git a/demo/moulinrouge/tests.py b/demo/moulinrouge/tests.py index 166071c..d89c9cb 100644 --- a/demo/moulinrouge/tests.py +++ b/demo/moulinrouge/tests.py @@ -2,7 +2,7 @@ # This file is part of pygal from pygal import ( Bar, Gauge, Pyramid, Funnel, Dot, StackedBar, XY, - CHARTS_BY_NAME, Config, Line, DateY) + CHARTS_BY_NAME, Config, Line, DateY, Worldmap) from pygal.style import styles @@ -261,4 +261,13 @@ def get_test_routes(app): datey.x_label_rotation = 25 return datey.render_response() + @app.route('/test/worldmap') + def test_worldmap(): + map = Worldmap() + map.add('fr', [13]) + map.add('us', [10]) + map.add('jp', [1]) + map.add('ru', [7]) + return map.render_response() + return filter(lambda x: x.startswith('test'), locals()) diff --git a/pygal/css/style.css b/pygal/css/style.css index b8bcb07..5571457 100644 --- a/pygal/css/style.css +++ b/pygal/css/style.css @@ -109,4 +109,28 @@ text.no_data { fill: {{ style.foreground_light }}; } +.country { + fill: {{ style.primary }}; + stroke: {{ style.primary }}; + fill-opacity: .1; + opacity: {{ style.opacity }}; +} + +.country:hover { + opacity: {{ style.opacity_hover }}; +} + +.lake { + fill: {{ style.foreground_dark }}; +} + +.borders { + fill: none; + stroke: {{ style.foreground_light }}; + stroke-width: 0.3; + stroke-linecap: round; + stroke-linejoin: round; +} + {{ style.colors }} + diff --git a/pygal/graph/__init__.py b/pygal/graph/__init__.py index d26bd31..aca578a 100644 --- a/pygal/graph/__init__.py +++ b/pygal/graph/__init__.py @@ -36,5 +36,6 @@ CHARTS_NAMES = [ 'VerticalPyramid', 'Dot', 'Gauge', - 'DateY' + 'DateY', + 'Worldmap' ] diff --git a/pygal/graph/worldmap.py b/pygal/graph/worldmap.py new file mode 100644 index 0000000..6fdbcb6 --- /dev/null +++ b/pygal/graph/worldmap.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# This file is part of pygal +# +# A python svg graph plotting library +# Copyright © 2012 Kozea +# +# This library is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with pygal. If not, see . +""" +Worldmap chart + +""" + +from __future__ import division +from pygal.util import cut +from pygal.graph.graph import Graph +from pygal.adapters import positive, none_to_zero +from lxml import etree +import os + +with open(os.path.join( + os.path.dirname(__file__), + 'worldmap.svg')) as file: + MAP = file.read() + + +class Worldmap(Graph): + """Worldmap graph""" + _adapters = [positive, none_to_zero] + + def _plot(self): + map = etree.fromstring(MAP) + map.set('width', str(self.view.width)) + map.set('height', str(self.view.height)) + sum_ = sum(cut(cut(self.series, 'values'))) + + for i, serie in enumerate(self.series): + ratio = serie.values[0] / self._max + perc = serie.values[0] / sum_ if sum_ != 0 else 0 + country = map.find('.//*[@id="%s"]' % serie.title) + if country is None: + continue + country.set( + 'style', 'fill-opacity: %f' % ( + ratio)) + title = country[0] + title.text = (title.text or '?') + ': %d (%s)' % ( + serie.values[0], '{0:.2%}'.format(perc)) + + self.nodes['plot'].append(map) diff --git a/pygal/style.py b/pygal/style.py index 2611566..633a144 100644 --- a/pygal/style.py +++ b/pygal/style.py @@ -48,6 +48,7 @@ class Style(object): self.opacity_hover = opacity_hover self.transition = transition self._colors = colors + self.primary = colors[0] @property def colors(self): diff --git a/setup.py b/setup.py index cff5326..16d1051 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ setup( keywords=[ "svg", "chart", "graph", "diagram", "plot", "histogram", "kiviat"], tests_require=["pytest", "pyquery", "flask", "cairosvg"], - package_data={'pygal': ['css/*', 'js/*']}, + package_data={'pygal': ['css/*', 'graph/worldmap.svg']}, install_requires=['lxml'], use_2to3=True, classifiers=[