Skip to content

Commit

Permalink
Refactor maps
Browse files Browse the repository at this point in the history
  • Loading branch information
paradoxxxzero committed May 4, 2015
1 parent 4817b8e commit a61384f
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 3,332 deletions.
5 changes: 2 additions & 3 deletions pygal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from pygal.graph.box import Box
from pygal.graph.dot import Dot
from pygal.graph.frenchmap import FrenchMapDepartments, FrenchMapRegions
from pygal.graph.swissmap import SwissMapCantons
from pygal.graph.funnel import Funnel
from pygal.graph.gauge import Gauge
from pygal.graph.histogram import Histogram
Expand All @@ -39,11 +38,11 @@
from pygal.graph.radar import Radar
from pygal.graph.stackedbar import StackedBar
from pygal.graph.stackedline import StackedLine
from pygal.graph.supranationalworldmap import SupranationalWorldmap
from pygal.graph.swissmap import SwissMapCantons
from pygal.graph.time import DateLine, DateTimeLine, TimeLine, TimeDeltaLine
from pygal.graph.treemap import Treemap
from pygal.graph.verticalpyramid import VerticalPyramid
from pygal.graph.worldmap import Worldmap
from pygal.graph.worldmap import Worldmap, SupranationalWorldmap
from pygal.graph.xy import XY
from pygal.graph.graph import Graph
from pygal.config import Config
Expand Down
17 changes: 6 additions & 11 deletions pygal/graph/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,10 @@ def add_xml_filter(self, callback):

def prepare_values(self, raw, offset=0):
"""Prepare the values to start with sane values"""
from pygal import (
Worldmap, FrenchMapDepartments, Histogram, SwissMapCantons)
# TODO: Generalize these conditions
if self.zero == 0 and isinstance(
self, (Worldmap, FrenchMapDepartments, SwissMapCantons)):
from pygal.graph.map import BaseMap
from pygal import Histogram

if self.zero == 0 and isinstance(self, BaseMap):
self.zero = 1

for key in ('x_labels', 'y_labels'):
Expand Down Expand Up @@ -126,8 +125,7 @@ def prepare_values(self, raw, offset=0):
metadata = {}
values = []
if isinstance(raw_values, dict):
if isinstance(self, (
Worldmap, FrenchMapDepartments, SwissMapCantons)):
if isinstance(self, BaseMap):
raw_values = list(raw_values.items())
else:
value_list = [None] * width
Expand Down Expand Up @@ -161,10 +159,7 @@ def prepare_values(self, raw, offset=0):
value = (value, self.zero)
if x_adapter:
value = (x_adapter(value[0]), adapter(value[1]))
if isinstance(
self, (
Worldmap, FrenchMapDepartments,
SwissMapCantons)):
if isinstance(self, BaseMap):
value = (adapter(value[0]), value[1])
else:
value = list(map(adapter, value))
Expand Down
91 changes: 0 additions & 91 deletions pygal/graph/ch.cantons.svg

This file was deleted.

328 changes: 0 additions & 328 deletions pygal/graph/fr.departments.svg

This file was deleted.

91 changes: 0 additions & 91 deletions pygal/graph/fr.regions.svg

This file was deleted.

97 changes: 7 additions & 90 deletions pygal/graph/frenchmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@

from __future__ import division
from collections import defaultdict
from pygal.util import cut, cached_property, decorate
from pygal.graph.graph import Graph
from pygal.graph.map import BaseMap
from pygal._compat import u
from pygal.etree import etree
from numbers import Number
import os


Expand Down Expand Up @@ -177,102 +174,22 @@
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):
class FrenchMapDepartments(BaseMap):
"""French department map"""
_dual = True
x_labels = list(DEPARTMENTS.keys())
area_names = DEPARTMENTS
area_prefix = 'z'
kind = 'departement'
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_)
try:
areae = map.findall(
".//*[@class='%s%s %s map-element']" % (
self.area_prefix, area_code,
self.kind))
except SyntaxError:
# Python 2.6 (you'd better install lxml)
areae = []
for g in map:
for e in g:
if '%s%s' % (
self.area_prefix, area_code
) in e.attrib.get('class', ''):
areae.append(e)

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:
node = decorate(self.svg, area, metadata)
if node != area:
area.remove(node)
for g in map:
if area not in g:
continue
index = list(g).index(area)
g.remove(area)
node.append(area)
g.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: %s' % (
serie.title,
self.area_names[area_code], self._format(value))

self.nodes['plot'].append(map)
with open(os.path.join(
os.path.dirname(__file__),
'fr.regions.svg')) as file:
REG_MAP = file.read()


class FrenchMapRegions(FrenchMapDepartments):
class FrenchMapRegions(BaseMap):
"""French regions map"""
x_labels = list(REGIONS.keys())
area_names = REGIONS
Expand Down
113 changes: 113 additions & 0 deletions pygal/graph/map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# -*- 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/>.

from __future__ import division
from pygal.graph.graph import Graph
from pygal.util import cut, cached_property, decorate
from pygal.etree import etree
from numbers import Number


class BaseMap(Graph):
"""Base map."""
_dual = True

@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 get_values(self, serie):
return serie.values

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(self.get_values(serie)):
# TODO: Generalize
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_)
try:
areae = map.findall(
".//*[@class='%s%s %s map-element']" % (
self.area_prefix, area_code,
self.kind))
except SyntaxError:
# Python 2.6 (you'd better install lxml)
areae = []
for g in map:
for e in g:
if '%s%s' % (
self.area_prefix, area_code
) in e.attrib.get('class', ''):
areae.append(e)

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:
node = decorate(self.svg, area, metadata)
if node != area:
area.remove(node)
for g in map:
if area not in g:
continue
index = list(g).index(area)
g.remove(area)
node.append(area)
g.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: %s' % (
serie.title,
self.area_names[area_code], self._format(value))

self.nodes['plot'].append(map)
Loading

0 comments on commit a61384f

Please sign in to comment.