Browse Source

Fix a lot of things in Worldmap

pull/35/head
Florian Mounier 12 years ago
parent
commit
5055c6ccd8
  1. 19
      demo/moulinrouge/tests.py
  2. 13
      pygal/adapters.py
  3. 1
      pygal/css/style.css
  4. 42
      pygal/graph/worldmap.py
  5. 185
      pygal/i18n.py
  6. 4
      pygal/svg.py
  7. 46
      pygal/test/test_graph.py
  8. 22
      pygal/util.py

19
demo/moulinrouge/tests.py

@ -266,8 +266,23 @@ def get_test_routes(app):
import random
map = Worldmap(style=random.choice(styles.values()))
map.add('1st', [('fr', 13), ('us', 10)])
map.add('2nd', [('jp', 1), ('ru', 7)])
map.add('1st', [('fr', 100), ('us', 10)])
map.add('2nd', [('jp', 1), ('ru', 7), ('uk', 0)])
map.add('3rd', ['ch', 'cz', 'ca', 'cn'])
map.add('4th', {'br': 12, 'bo': 1, 'bu': 23})
map.add('5th', [{
'value': ('tw', 10),
'label': 'First label',
'xlink': 'http://google.com?q=tw'
}, {
'value': ('bw', 20),
'label': 'Second one',
'xlink': 'http://google.com?q=bw'
}, {
'value': ('mw', 40),
'label': 'Last'
}])
map.add('6th', [3, 5, 34, 12])
return map.render_response()
return filter(lambda x: x.startswith('test'), locals())

13
pygal/adapters.py

@ -22,6 +22,7 @@ Value adapters to use when a chart doesn't accept all value types
"""
import datetime
from numbers import Number
from pygal.i18n import COUNTRIES
def positive(x):
@ -42,6 +43,18 @@ def none_to_zero(x):
return x or 0
def int_to_country(x):
# This is used for test compatibility
if isinstance(x, Number):
try:
x = int(x)
except:
return x
if x >= 0 and x < len(COUNTRIES):
return COUNTRIES.keys()[x]
return x
def date(x):
# Make int work for date graphs by counting days number from now
if isinstance(x, Number):

1
pygal/css/style.css

@ -122,6 +122,7 @@ text.no_data {
.country:hover {
opacity: 1;
stroke-width: 10;
}
{{ style.colors }}

42
pygal/graph/worldmap.py

@ -22,9 +22,10 @@ Worldmap chart
"""
from __future__ import division
from pygal.util import cut, cached_property
from pygal.util import cut, cached_property, decorate
from pygal.graph.graph import Graph
from pygal.adapters import positive, none_to_zero
from pygal.i18n import COUNTRIES
from pygal.adapters import int_to_country
from lxml import etree
import os
@ -37,6 +38,9 @@ with open(os.path.join(
class Worldmap(Graph):
"""Worldmap graph"""
_dual = True
x_labels = COUNTRIES.keys()
country_names = COUNTRIES
_adapters = [int_to_country]
@cached_property
def countries(self):
@ -59,22 +63,42 @@ class Worldmap(Graph):
map.set('height', str(self.view.height))
for i, serie in enumerate(self.series):
min_ = min(cut(serie.values, 1))
max_ = max(cut(serie.values, 1))
for country, value in serie.values:
safe_vals = filter(lambda x: x is not None, cut(serie.values, 1))
if not safe_vals:
continue
min_ = min(safe_vals)
max_ = max(safe_vals)
for j, (country_code, value) in enumerate(serie.values):
if value is None:
continue
ratio = value / (max_ - min_)
country = map.find('.//*[@id="%s"]' % country)
if max_ == min_:
ratio = 1
else:
ratio = .3 + .7 * value / (max_ - min_)
country = map.find('.//*[@id="%s"]' % country_code)
if country is None:
continue
cls = country.get('class', '').split(' ')
cls.append('color-%d' % i)
cls.append('tooltip-trigger')
cls.append('reactive')
country.set('class', ' '.join(cls))
country.set(
'style', 'fill-opacity: %f' % (
ratio))
title = country[0]
title.text = (title.text or '?') + ': %d' % value
metadata = serie.metadata.get(j)
if metadata:
parent = country.getparent()
node = decorate(self.svg, country, metadata)
if node != country:
country.remove(node)
index = parent.index(country)
parent.remove(country)
node.append(country)
parent.insert(index, node)
self.svg.node(country, 'title').text = '%s: %d' % (
self.country_names[country_code], value)
self.nodes['plot'].append(map)

185
pygal/i18n.py

@ -0,0 +1,185 @@
COUNTRIES = {
'ad': 'Andorra',
'ae': 'United Arab Emirates',
'af': 'Afghanistan',
'al': 'Albania',
'am': 'Armenia',
'ao': 'Angola',
'aq': 'Antarctica',
'ar': 'Argentina',
'at': 'Austria',
'au': 'Australia',
'az': 'Azerbaijan',
'ba': 'Bosnia and Herzegovina',
'bd': 'Bangladesh',
'be': 'Belgium',
'bf': 'Burkina Faso',
'bg': 'Bulgaria',
'bh': 'Bahrain',
'bi': 'Burundi',
'bj': 'Benin',
'bn': 'Brunei Darussalam',
'bo': 'Bolivia, Plurinational State of',
'br': 'Brazil',
'bt': 'Bhutan',
'bw': 'Botswana',
'by': 'Belarus',
'bz': 'Belize',
'ca': 'Canada',
'cd': 'Congo, the Democratic Republic of the',
'cf': 'Central African Republic',
'cg': 'Congo',
'ch': 'Switzerland',
'ci': "Cote d'Ivoire",
'cl': 'Chile',
'cm': 'Cameroon',
'cn': 'China',
'co': 'Colombia',
'cr': 'Costa Rica',
'cu': 'Cuba',
'cv': 'Cape Verde',
'cy': 'Cyprus',
'cz': 'Czech Republic',
'de': 'Germany',
'dj': 'Djibouti',
'dk': 'Denmark',
'do': 'Dominican Republic',
'dz': 'Algeria',
'ec': 'Ecuador',
'ee': 'Estonia',
'eg': 'Egypt',
'eh': 'Western Sahara',
'er': 'Eritrea',
'es': 'Spain',
'et': 'Ethiopia',
'fi': 'Finland',
'fr': 'France',
'ga': 'Gabon',
'gb': 'United Kingdom',
'ge': 'Georgia',
'gf': 'French Guiana',
'gh': 'Ghana',
'gl': 'Greenland',
'gm': 'Gambia',
'gn': 'Guinea',
'gq': 'Equatorial Guinea',
'gr': 'Greece',
'gt': 'Guatemala',
'gu': 'Guam',
'gw': 'Guinea-Bissau',
'gy': 'Guyana',
'hk': 'Hong Kong',
'hn': 'Honduras',
'hr': 'Croatia',
'ht': 'Haiti',
'hu': 'Hungary',
'id': 'Indonesia',
'ie': 'Ireland',
'il': 'Israel',
'in': 'India',
'iq': 'Iraq',
'ir': 'Iran, Islamic Republic of',
'is': 'Iceland',
'it': 'Italy',
'jm': 'Jamaica',
'jo': 'Jordan',
'jp': 'Japan',
'ke': 'Kenya',
'kg': 'Kyrgyzstan',
'kh': 'Cambodia',
'kp': "Korea, Democratic People's Republic of",
'kr': 'Korea, Republic of',
'kw': 'Kuwait',
'kz': 'Kazakhstan',
'la': "Lao People's Democratic Republic",
'lb': 'Lebanon',
'li': 'Liechtenstein',
'lk': 'Sri Lanka',
'lr': 'Liberia',
'ls': 'Lesotho',
'lt': 'Lithuania',
'lu': 'Luxembourg',
'lv': 'Latvia',
'ly': 'Libyan Arab Jamahiriya',
'ma': 'Morocco',
'mc': 'Monaco',
'md': 'Moldova, Republic of',
'me': 'Montenegro',
'mg': 'Madagascar',
'mk': 'Macedonia, the former Yugoslav Republic of',
'ml': 'Mali',
'mm': 'Myanmar',
'mn': 'Mongolia',
'mo': 'Macao',
'mr': 'Mauritania',
'mt': 'Malta',
'mu': 'Mauritius',
'mv': 'Maldives',
'mw': 'Malawi',
'mx': 'Mexico',
'my': 'Malaysia',
'mz': 'Mozambique',
'na': 'Namibia',
'ne': 'Niger',
'ng': 'Nigeria',
'ni': 'Nicaragua',
'nl': 'Netherlands',
'no': 'Norway',
'np': 'Nepal',
'nz': 'New Zealand',
'om': 'Oman',
'pa': 'Panama',
'pe': 'Peru',
'pg': 'Papua New Guinea',
'ph': 'Philippines',
'pk': 'Pakistan',
'pl': 'Poland',
'pr': 'Puerto Rico',
'ps': 'Palestine, State of',
'pt': 'Portugal',
'py': 'Paraguay',
're': 'Reunion',
'ro': 'Romania',
'rs': 'Serbia',
'ru': 'Russian Federation',
'rw': 'Rwanda',
'sa': 'Saudi Arabia',
'sc': 'Seychelles',
'sd': 'Sudan',
'sg': 'Singapore',
'sh': 'Saint Helena, Ascension and Tristan da Cunha',
'si': 'Slovenia',
'sk': 'Slovakia',
'sl': 'Sierra Leone',
'sm': 'San Marino',
'sn': 'Senegal',
'so': 'Somalia',
'sr': 'Suriname',
'st': 'Sao Tome and Principe',
'sv': 'El Salvador',
'sy': 'Syrian Arab Republic',
'sz': 'Swaziland',
'td': 'Chad',
'tg': 'Togo',
'th': 'Thailand',
'tj': 'Tajikistan',
'tl': 'Timor-Leste',
'tm': 'Turkmenistan',
'tn': 'Tunisia',
'tr': 'Turkey',
'tw': 'Taiwan, Province of China',
'tz': 'Tanzania, United Republic of',
'ua': 'Ukraine',
'ug': 'Uganda',
'us': 'United States',
'uy': 'Uruguay',
'uz': 'Uzbekistan',
'va': 'Holy See (Vatican City State)',
've': 'Venezuela, Bolivarian Republic of',
'vn': 'Viet Nam',
'ye': 'Yemen',
'yt': 'Mayotte',
'za': 'South Africa',
'zm': 'Zambia',
'zw': 'Zimbabwe'
}

4
pygal/svg.py

@ -49,11 +49,13 @@ class Svg(object):
'xlink': 'http://www.w3.org/1999/xlink',
})
self.root.append(
etree.Comment(u'Generated with pygal %s ©Kozea 2012 on %s' % (
etree.Comment(u'Generated with pygal %s ©Kozea 2011-2013 on %s' % (
__version__, date.today().isoformat())))
self.root.append(etree.Comment(u'http://pygal.org'))
self.root.append(etree.Comment(u'http://github.com/Kozea/pygal'))
self.defs = self.node(tag='defs')
self.title = self.node(tag='title')
self.title.text = graph.title or 'Pygal'
def add_styles(self):
"""Add the css to the svg"""

46
pygal/test/test_graph.py

@ -89,7 +89,8 @@ def test_metadata(Chart):
if Chart == pygal.Pie:
# Slices with value 0 are not rendered
assert len(v) - 1 == len(q('.tooltip-trigger').siblings('.value'))
else:
elif Chart != pygal.Worldmap:
# Tooltip are not working on worldmap
assert len(v) == len(q('.tooltip-trigger').siblings('.value'))
@ -141,24 +142,33 @@ def test_iterable_types(Chart):
def test_values_by_dict(Chart):
chart = Chart()
chart.add('A', {'red': 10, 'green': 12, 'blue': 14})
chart.add('B', {'green': 11, 'red': 7})
chart.add('C', {'blue': 7})
chart.add('D', {})
chart.add('E', {'blue': 2, 'red': 13})
chart.x_labels = ('red', 'green', 'blue')
chart1 = chart.render()
chart1 = Chart()
chart2 = Chart()
if Chart != pygal.Worldmap:
chart1.add('A', {'red': 10, 'green': 12, 'blue': 14})
chart1.add('B', {'green': 11, 'red': 7})
chart1.add('C', {'blue': 7})
chart1.add('D', {})
chart1.add('E', {'blue': 2, 'red': 13})
chart1.x_labels = ('red', 'green', 'blue')
chart2.add('A', [10, 12, 14])
chart2.add('B', [7, 11])
chart2.add('C', [None, None, 7])
chart2.add('D', [])
chart2.add('E', [13, None, 2])
chart2.x_labels = ('red', 'green', 'blue')
else:
chart1.add('A', {'fr': 10, 'us': 12, 'jp': 14})
chart1.add('B', {'cn': 99})
chart1.add('C', {})
chart = Chart()
chart.add('A', [10, 12, 14])
chart.add('B', [7, 11])
chart.add('C', [None, None, 7])
chart.add('D', [])
chart.add('E', [13, None, 2])
chart.x_labels = ('red', 'green', 'blue')
chart2 = chart.render()
assert chart1 == chart2
chart2.add('A', [('fr', 10), ('us', 12), ('jp', 14)])
chart2.add('B', [('cn', 99)])
chart2.add('C', [None, (None, None)])
assert chart1.render() == chart2.render()
def test_no_data_with_no_values(Chart):

22
pygal/util.py

@ -208,6 +208,7 @@ def decorate(svg, node, metadata):
if not isinstance(xlink, dict):
xlink = {'href': xlink, 'target': '_blank'}
node = svg.node(node, 'a', **xlink)
for key, value in metadata.items():
if key == 'xlink' and isinstance(value, dict):
value = value.get('href', value)
@ -298,6 +299,11 @@ from pygal.serie import Serie
def prepare_values(raw, config, cls):
"""Prepare the values to start with sane values"""
from pygal.graph.datey import DateY
from pygal.graph.worldmap import Worldmap
if config.x_labels is None and hasattr(cls, 'x_labels'):
config.x_labels = cls.x_labels
if config.zero == 0 and issubclass(cls, Worldmap):
config.zero = 1
if not raw:
return
@ -317,14 +323,16 @@ def prepare_values(raw, config, cls):
metadata = {}
values = []
if isinstance(raw_values, dict):
value_list = [None] * width
for k, v in raw_values.items():
if k in config.x_labels:
value_list[config.x_labels.index(k)] = v
raw_values = value_list
if issubclass(cls, Worldmap):
raw_values = raw_values.items()
else:
value_list = [None] * width
for k, v in raw_values.items():
if k in config.x_labels:
value_list[config.x_labels.index(k)] = v
raw_values = value_list
else:
raw_values = list(raw_values)
for index, raw_value in enumerate(
raw_values + (
(width - len(raw_values)) * [None] # aligning values
@ -340,7 +348,7 @@ def prepare_values(raw, config, cls):
value = (None, None)
elif not hasattr(value, '__iter__'):
value = (value, config.zero)
if issubclass(cls, DateY):
if issubclass(cls, DateY) or issubclass(cls, Worldmap):
value = (adapter(value[0]), value[1])
else:
value = map(adapter, value)

Loading…
Cancel
Save