diff --git a/demo/moulinrouge/tests.py b/demo/moulinrouge/tests.py index 0b0b325..3fa19ae 100644 --- a/demo/moulinrouge/tests.py +++ b/demo/moulinrouge/tests.py @@ -437,6 +437,24 @@ def get_test_routes(app): line.x_labels_major = ['lol3'] return line.render_response() + @app.route('/test/x_major_labels/') + def test_x_major_labels_for(chart): + chart = CHARTS_BY_NAME[chart]() + chart.add('test', range(12)) + chart.x_labels = map(str, range(12)) + chart.x_labels_major_count = 4 + # chart.x_labels_major = ['1', '5', '11', '1.0', '5.0', '11.0'] + return chart.render_response() + + @app.route('/test/y_major_labels/') + def test_y_major_labels_for(chart): + chart = CHARTS_BY_NAME[chart]() + chart.add('test', zip(*[range(12), range(12)])) + chart.y_labels = range(12) + # chart.y_labels_major_count = 4 + chart.y_labels_major = [1.0, 5.0, 11.0] + return chart.render_response() + @app.route('/test/stroke_config') def test_stroke_config(): line = Line() diff --git a/pygal/ghost.py b/pygal/ghost.py index e9f5c86..9cd2ad9 100644 --- a/pygal/ghost.py +++ b/pygal/ghost.py @@ -28,7 +28,7 @@ import io import sys from pygal._compat import u, is_list_like from pygal.graph import CHARTS_NAMES -from pygal.config import Config, SerieConfig +from pygal.config import Config, CONFIG_ITEMS from pygal.util import prepare_values from uuid import uuid4 @@ -89,6 +89,12 @@ class Ghost(object): return prepare_values(series, self.config, self.cls) def make_instance(self, overrides=None): + for conf_key in CONFIG_ITEMS: + if conf_key.is_list: + if getattr(self, conf_key.name, None): + setattr(self, conf_key.name, + list(getattr(self, conf_key.name))) + self.config(**self.__dict__) self.config.__dict__.update(overrides or {}) series = self.make_series(self.raw_series) diff --git a/pygal/graph/base.py b/pygal/graph/base.py index 741b61a..9b4a520 100644 --- a/pygal/graph/base.py +++ b/pygal/graph/base.py @@ -82,9 +82,6 @@ class BaseGraph(object): def _compute(self): """Initial computations to draw the graph""" - def _plot(self): - """Actual plotting of the graph""" - def _compute_margin(self): """Compute graph margins from set texts""" self._legend_at_left_width = 0 @@ -202,25 +199,28 @@ class BaseGraph(object): def _secondary_min(self): """Getter for the minimum series value""" return (self.range[0] if (self.range and self.range[0] is not None) - else (min(self._secondary_values) if self._secondary_values else None)) + else (min(self._secondary_values) + if self._secondary_values else None)) @cached_property def _min(self): """Getter for the minimum series value""" - return (self.range[0] if (self.range and self.range[0] is not None) - else (min(self._values) if self._values else None)) + return (self.range[0] if (self.range and self.range[0] is not None) + else (min(self._values) + if self._values else None)) @cached_property def _max(self): """Getter for the maximum series value""" return (self.range[1] if (self.range and self.range[1] is not None) - else (max(self._values) if self._values else None)) + else (max(self._values) if self._values else None)) @cached_property def _secondary_max(self): """Getter for the maximum series value""" return (self.range[1] if (self.range and self.range[1] is not None) - else (max(self._secondary_values) if self._secondary_values else None)) + else (max(self._secondary_values) + if self._secondary_values else None)) @cached_property def _order(self): diff --git a/pygal/graph/box.py b/pygal/graph/box.py index de928e0..cc35dfa 100644 --- a/pygal/graph/box.py +++ b/pygal/graph/box.py @@ -47,8 +47,7 @@ class Box(Graph): def format_maybe_quartile(x): if is_list_like(x): - if len(x) == 5: - return 'Q1: %s Q2: %s Q3: %s' % tuple(map(sup, x[1:4])) + return 'Q1: %s Q2: %s Q3: %s' % tuple(map(sup, x[1:4])) else: return sup(x) return format_maybe_quartile diff --git a/pygal/graph/datey.py b/pygal/graph/datey.py index 51909d2..3476332 100644 --- a/pygal/graph/datey.py +++ b/pygal/graph/datey.py @@ -108,12 +108,10 @@ class DateY(XY): self.yvals = [val[1] for serie in self.all_series for val in serie.interpolated] - if self.xvals: - xmin = min(self.xvals) - xmax = max(self.xvals) - rng = (xmax - xmin) - else: - rng = None + + xmin = min(self.xvals) + xmax = max(self.xvals) + rng = (xmax - xmin) # Calculate/prcoess the x_labels if self.x_labels and all( diff --git a/pygal/graph/dot.py b/pygal/graph/dot.py index 6dc3f5d..fbde56a 100644 --- a/pygal/graph/dot.py +++ b/pygal/graph/dot.py @@ -32,11 +32,6 @@ class Dot(Graph): _adapters = [positive] - # def _axes(self): - # """Draw axes""" - # self._x_axis(False) - # self._y_axis(False) - def dot(self, serie_node, serie, r_max): """Draw a dot line""" view_values = list(map(self.view, serie.points)) diff --git a/pygal/graph/gauge.py b/pygal/graph/gauge.py index 9146a18..13f8019 100644 --- a/pygal/graph/gauge.py +++ b/pygal/graph/gauge.py @@ -66,9 +66,6 @@ class Gauge(Graph): self._static_value(serie_node, value, x, y) def _x_axis(self, draw_axes=True): - if not self._x_labels: - return - axis = self.svg.node(self.nodes['plot'], class_="axis x gauge") for i, (label, theta) in enumerate(self._x_labels): diff --git a/pygal/graph/line.py b/pygal/graph/line.py index cc69bdd..ca7afd3 100644 --- a/pygal/graph/line.py +++ b/pygal/graph/line.py @@ -142,7 +142,7 @@ class Line(Graph): self._x_labels = None if self.include_x_axis: - # Y Label + # Y Label self._box.ymin = min(self._min or 0, 0) self._box.ymax = max(self._max or 0, 0) else: diff --git a/pygal/test/test_config.py b/pygal/test/test_config.py index 48b0303..fb8ee8c 100644 --- a/pygal/test/test_config.py +++ b/pygal/test/test_config.py @@ -19,7 +19,8 @@ from pygal import ( Line, Dot, Pie, Radar, Config, Bar, Funnel, Worldmap, - SupranationalWorldmap, Histogram, Gauge, Box, + SupranationalWorldmap, Histogram, Gauge, Box, XY, + Pyramid, DateY, HorizontalBar, HorizontalStackedBar, FrenchMap_Regions, FrenchMap_Departments) from pygal._compat import u from pygal.test.utils import texts @@ -326,13 +327,14 @@ def test_meta_config(): def test_label_rotation(Chart): - chart = Chart(x_label_rotation=28) + chart = Chart(x_label_rotation=28, y_label_rotation=76) chart.add('1', [4, -5, 123, 59, 38]) chart.add('2', [89, 0, 8, .12, 8]) chart.x_labels = ['one', 'twoooooooooooooooooooooo', 'three', '4'] q = chart.render_pyquery() if Chart in (Line, Bar): - assert len(q('.guides text[transform^="rotate(28"]')) == 4 + assert len(q('.axis.x text[transform^="rotate(28"]')) == 4 + assert len(q('.axis.y text[transform^="rotate(76"]')) == 13 def test_legend_at_bottom(Chart): @@ -354,3 +356,95 @@ def test_x_y_title(Chart): chart.x_labels = ['one', 'twoooooooooooooooooooooo', 'three', '4'] q = chart.render_pyquery() assert len(q('.titles .title')) == 3 + + +def test_x_label_major(Chart): + if Chart in ( + Pie, Radar, Funnel, Dot, Gauge, Worldmap, + SupranationalWorldmap, Histogram, Box, + FrenchMap_Regions, FrenchMap_Departments, + Pyramid, DateY): + return + chart = Chart() + chart.add('test', range(12)) + chart.x_labels = map(str, range(12)) + + q = chart.render_pyquery() + assert len(q(".axis.x text.major")) == 0 + + chart.x_labels_major = ['1', '5', '11', '1.0', '5.0', '11.0'] + q = chart.render_pyquery() + assert len(q(".axis.x text.major")) == 3 + assert len(q(".axis.x text")) == 12 + + chart.show_minor_x_labels = False + q = chart.render_pyquery() + assert len(q(".axis.x text.major")) == 3 + assert len(q(".axis.x text")) == 3 + + chart.show_minor_x_labels = True + chart.x_labels_major = None + chart.x_labels_major_every = 2 + q = chart.render_pyquery() + assert len(q(".axis.x text.major")) == 6 + assert len(q(".axis.x text")) == 12 + + chart.x_labels_major_every = None + chart.x_labels_major_count = 4 + q = chart.render_pyquery() + assert len(q(".axis.x text.major")) == 4 + assert len(q(".axis.x text")) == 12 + + chart.x_labels_major_every = None + chart.x_labels_major_count = 78 + q = chart.render_pyquery() + assert len(q(".axis.x text.major")) == 12 + assert len(q(".axis.x text")) == 12 + + +def test_y_label_major(Chart): + if Chart in ( + Pie, Radar, Funnel, Dot, Gauge, Worldmap, + SupranationalWorldmap, Histogram, Box, + FrenchMap_Regions, FrenchMap_Departments, + HorizontalBar, HorizontalStackedBar, + Pyramid, DateY): + return + chart = Chart() + data = range(12) + if Chart == XY: + data = list(zip(*[range(12), range(12)])) + chart.add('test', data) + chart.y_labels = range(12) + + q = chart.render_pyquery() + assert len(q(".axis.y text.major")) == 3 + + chart.y_labels_major = [1.0, 5.0, 11.0] + q = chart.render_pyquery() + assert len(q(".axis.y text.major")) == 3 + assert len(q(".axis.y text")) == 12 + + chart.show_minor_y_labels = False + q = chart.render_pyquery() + assert len(q(".axis.y text.major")) == 3 + assert len(q(".axis.y text")) == 3 + + chart.show_minor_y_labels = True + chart.y_labels_major = None + chart.y_labels_major_every = 2 + q = chart.render_pyquery() + assert len(q(".axis.y text.major")) == 6 + assert len(q(".axis.y text")) == 12 + + chart.y_labels_major_every = None + chart.y_labels_major_count = 4 + q = chart.render_pyquery() + assert len(q(".axis.y text.major")) == 4 + assert len(q(".axis.y text")) == 12 + + chart.y_labels_major_every = None + chart.y_labels_major_count = 78 + q = chart.render_pyquery() + assert len(q(".axis.y text.major")) == 12 + assert len(q(".axis.y text")) == 12 diff --git a/pygal/test/test_frenchmap.py b/pygal/test/test_frenchmap.py new file mode 100644 index 0000000..1cf9c72 --- /dev/null +++ b/pygal/test/test_frenchmap.py @@ -0,0 +1,42 @@ +# -*- 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 . + +from pygal import ( + FrenchMap_Regions, FrenchMap_Departments) +from pygal.graph.frenchmap import REGIONS, DEPARTMENTS, aggregate_regions + + +def test_frenchmaps(): + datas = {} + for dept in DEPARTMENTS.keys(): + datas[dept] = int(''.join([x for x in dept if x.isdigit()])) * 10 + + fmap = FrenchMap_Departments() + fmap.add('departements', datas) + q = fmap.render_pyquery() + assert len( + q('#departements .departement,#dom-com .departement') + ) == len(DEPARTMENTS) + + fmap = FrenchMap_Regions() + fmap.add('regions', aggregate_regions(datas)) + q = fmap.render_pyquery() + assert len(q('#regions .region,#dom-com .region')) == len(REGIONS) + + assert aggregate_regions(datas.items()) == aggregate_regions(datas) diff --git a/pygal/test/test_graph.py b/pygal/test/test_graph.py index b3b059b..1cfcbd1 100644 --- a/pygal/test/test_graph.py +++ b/pygal/test/test_graph.py @@ -37,6 +37,8 @@ except ImportError: def test_multi_render(Chart, datas): chart = Chart() chart = make_data(chart, datas) + chart.x_labels = (str(a) for a in 'labels') + chart.y_labels = (str(a) for a in range(6)) svg = chart.render() for i in range(2): assert svg == chart.render()