mirror of https://github.com/Kozea/pygal.git
Florian Mounier
11 years ago
10 changed files with 947 additions and 205 deletions
After Width: | Height: | Size: 584 KiB |
After Width: | Height: | Size: 370 KiB |
@ -0,0 +1,270 @@
|
||||
# -*- coding: utf-8 -*- |
||||
# This file is part of pygal |
||||
# |
||||
# A python svg graph plotting library |
||||
# Copyright © 2012-2014 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 <http://www.gnu.org/licenses/>. |
||||
""" |
||||
Worldmap chart |
||||
|
||||
""" |
||||
|
||||
from __future__ import division |
||||
from pygal.ghost import ChartCollection |
||||
from pygal.util import cut, cached_property, decorate |
||||
from pygal.graph.graph import Graph |
||||
from pygal._compat import u |
||||
from numbers import Number |
||||
from lxml import etree |
||||
import os |
||||
|
||||
|
||||
DEPARTMENTS = { |
||||
'01': u("Ain"), |
||||
'02': u("Aisne"), |
||||
'03': u("Allier"), |
||||
'04': u("Alpes-de-Haute-Provence"), |
||||
'05': u("Hautes-Alpes"), |
||||
'06': u("Alpes-Maritimes"), |
||||
'07': u("Ardèche"), |
||||
'08': u("Ardennes"), |
||||
'09': u("Ariège"), |
||||
'10': u("Aube"), |
||||
'11': u("Aude"), |
||||
'12': u("Aveyron"), |
||||
'13': u("Bouches-du-RhĂ´ne"), |
||||
'14': u("Calvados"), |
||||
'15': u("Cantal"), |
||||
'16': u("Charente"), |
||||
'17': u("Charente-Maritime"), |
||||
'18': u("Cher"), |
||||
'19': u("Corrèze"), |
||||
'2A': u("Corse-du-Sud"), |
||||
'2B': u("Haute-Corse"), |
||||
'21': u("CĂ´te-d'Or"), |
||||
'22': u("CĂ´tes-d'Armor"), |
||||
'23': u("Creuse"), |
||||
'24': u("Dordogne"), |
||||
'25': u("Doubs"), |
||||
'26': u("DrĂ´me"), |
||||
'27': u("Eure"), |
||||
'28': u("Eure-et-Loir"), |
||||
'29': u("Finistère"), |
||||
'30': u("Gard"), |
||||
'31': u("Haute-Garonne"), |
||||
'32': u("Gers"), |
||||
'33': u("Gironde"), |
||||
'34': u("HĂ©rault"), |
||||
'35': u("Ille-et-Vilaine"), |
||||
'36': u("Indre"), |
||||
'37': u("Indre-et-Loire"), |
||||
'38': u("Isère"), |
||||
'39': u("Jura"), |
||||
'40': u("Landes"), |
||||
'41': u("Loir-et-Cher"), |
||||
'42': u("Loire"), |
||||
'43': u("Haute-Loire"), |
||||
'44': u("Loire-Atlantique"), |
||||
'45': u("Loiret"), |
||||
'46': u("Lot"), |
||||
'47': u("Lot-et-Garonne"), |
||||
'48': u("Lozère"), |
||||
'49': u("Maine-et-Loire"), |
||||
'50': u("Manche"), |
||||
'51': u("Marne"), |
||||
'52': u("Haute-Marne"), |
||||
'53': u("Mayenne"), |
||||
'54': u("Meurthe-et-Moselle"), |
||||
'55': u("Meuse"), |
||||
'56': u("Morbihan"), |
||||
'57': u("Moselle"), |
||||
'58': u("Nièvre"), |
||||
'59': u("Nord"), |
||||
'60': u("Oise"), |
||||
'61': u("Orne"), |
||||
'62': u("Pas-de-Calais"), |
||||
'63': u("Puy-de-DĂ´me"), |
||||
'64': u("Pyrénées-Atlantiques"), |
||||
'65': u("Hautes-Pyrénées"), |
||||
'66': u("Pyrénées-Orientales"), |
||||
'67': u("Bas-Rhin"), |
||||
'68': u("Haut-Rhin"), |
||||
'69': u("RhĂ´ne"), |
||||
'70': u("Haute-SaĂ´ne"), |
||||
'71': u("SaĂ´ne-et-Loire"), |
||||
'72': u("Sarthe"), |
||||
'73': u("Savoie"), |
||||
'74': u("Haute-Savoie"), |
||||
'75': u("Paris"), |
||||
'76': u("Seine-Maritime"), |
||||
'77': u("Seine-et-Marne"), |
||||
'78': u("Yvelines"), |
||||
'79': u("Deux-Sèvres"), |
||||
'80': u("Somme"), |
||||
'81': u("Tarn"), |
||||
'82': u("Tarn-et-Garonne"), |
||||
'83': u("Var"), |
||||
'84': u("Vaucluse"), |
||||
'85': u("Vendée"), |
||||
'86': u("Vienne"), |
||||
'87': u("Haute-Vienne"), |
||||
'88': u("Vosges"), |
||||
'89': u("Yonne"), |
||||
'90': u("Territoire de Belfort"), |
||||
'91': u("Essonne"), |
||||
'92': u("Hauts-de-Seine"), |
||||
'93': u("Seine-Saint-Denis"), |
||||
'94': u("Val-de-Marne"), |
||||
'95': u("Val-d'Oise"), |
||||
'971': u("Guadeloupe"), |
||||
'972': u("Martinique"), |
||||
'973': u("Guyane"), |
||||
'974': u("RĂ©union"), |
||||
# Not a area anymore but in case of... |
||||
'975': u("Saint Pierre et Miquelon"), |
||||
'976': u("Mayotte") |
||||
} |
||||
|
||||
|
||||
REGIONS = { |
||||
'11': u("ĂŽle-de-France"), |
||||
'21': u("Champagne-Ardenne"), |
||||
'22': u("Picardie"), |
||||
'23': u("Haute-Normandie"), |
||||
'24': u("Centre"), |
||||
'25': u("Basse-Normandie"), |
||||
'26': u("Bourgogne"), |
||||
'31': u("Nord-Pas-de-Calais"), |
||||
'41': u("Lorraine"), |
||||
'42': u("Alsace"), |
||||
'43': u("Franche-Comté"), |
||||
'52': u("Pays-de-la-Loire"), |
||||
'53': u("Bretagne"), |
||||
'54': u("Poitou-Charentes"), |
||||
'72': u("Aquitaine"), |
||||
'73': u("Midi-Pyrénées"), |
||||
'74': u("Limousin"), |
||||
'82': u("RhĂ´ne-Alpes"), |
||||
'83': u("Auvergne"), |
||||
'91': u("Languedoc-Roussillon"), |
||||
'93': u("Provence-Alpes-CĂ´te d'Azur"), |
||||
'94': u("Corse"), |
||||
'01': u("Guadeloupe"), |
||||
'02': u("Martinique"), |
||||
'03': u("Guyane"), |
||||
'04': u("RĂ©union"), |
||||
# Not a region anymore but in case of... |
||||
'05': u("Saint Pierre et Miquelon"), |
||||
'06': u("Mayotte") |
||||
} |
||||
|
||||
|
||||
with open(os.path.join( |
||||
os.path.dirname(__file__), |
||||
'fr.departments.svg')) as file: |
||||
DPT_MAP = file.read() |
||||
|
||||
|
||||
with open(os.path.join( |
||||
os.path.dirname(__file__), |
||||
'fr.regions.svg')) as file: |
||||
REG_MAP = file.read() |
||||
|
||||
|
||||
class FrenchMapDepartments(Graph): |
||||
"""French department map""" |
||||
_dual = True |
||||
x_labels = list(DEPARTMENTS.keys()) |
||||
area_names = DEPARTMENTS |
||||
area_prefix = 'z' |
||||
svg_map = DPT_MAP |
||||
|
||||
|
||||
@cached_property |
||||
def _values(self): |
||||
"""Getter for series values (flattened)""" |
||||
return [val[1] |
||||
for serie in self.series |
||||
for val in serie.values |
||||
if val[1] is not None] |
||||
|
||||
def _plot(self): |
||||
map = etree.fromstring(self.svg_map) |
||||
map.set('width', str(self.view.width)) |
||||
map.set('height', str(self.view.height)) |
||||
|
||||
for i, serie in enumerate(self.series): |
||||
safe_vals = list(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, (area_code, value) in enumerate(serie.values): |
||||
if isinstance(area_code, Number): |
||||
area_code = '%2d' % area_code |
||||
if value is None: |
||||
continue |
||||
if max_ == min_: |
||||
ratio = 1 |
||||
else: |
||||
ratio = .3 + .7 * (value - min_) / (max_ - min_) |
||||
areae = map.xpath( |
||||
"//*[contains(concat(' ', normalize-space(@class), ' ')," |
||||
" ' %s%s ')]" % (self.area_prefix, area_code)) |
||||
if not areae: |
||||
continue |
||||
for area in areae: |
||||
cls = area.get('class', '').split(' ') |
||||
cls.append('color-%d' % i) |
||||
area.set('class', ' '.join(cls)) |
||||
area.set('style', 'fill-opacity: %f' % (ratio)) |
||||
|
||||
metadata = serie.metadata.get(j) |
||||
if metadata: |
||||
parent = area.getparent() |
||||
node = decorate(self.svg, area, metadata) |
||||
if node != area: |
||||
area.remove(node) |
||||
index = parent.index(area) |
||||
parent.remove(area) |
||||
node.append(area) |
||||
parent.insert(index, node) |
||||
|
||||
last_node = len(area) > 0 and area[-1] |
||||
if last_node is not None and last_node.tag == 'title': |
||||
title_node = last_node |
||||
text = title_node.text + '\n' |
||||
else: |
||||
title_node = self.svg.node(area, 'title') |
||||
text = '' |
||||
title_node.text = text + '[%s] %s: %d' % ( |
||||
serie.title, |
||||
self.area_names[area_code], value) |
||||
|
||||
self.nodes['plot'].append(map) |
||||
|
||||
|
||||
class FrenchMapRegions(FrenchMapDepartments): |
||||
"""French regions map""" |
||||
x_labels = list(REGIONS.keys()) |
||||
area_names = REGIONS |
||||
area_prefix = 'a' |
||||
svg_map = REG_MAP |
||||
|
||||
|
||||
class FrenchMap(ChartCollection): |
||||
Regions = FrenchMapRegions |
||||
Departments = FrenchMapDepartments |
Before Width: | Height: | Size: 752 KiB After Width: | Height: | Size: 754 KiB |
Loading…
Reference in new issue