diff --git a/demo/moulinrouge/tests.py b/demo/moulinrouge/tests.py index 15e7870..e051aaa 100644 --- a/demo/moulinrouge/tests.py +++ b/demo/moulinrouge/tests.py @@ -379,7 +379,6 @@ def get_test_routes(app): @app.route('/test/dateline') def test_dateline(): - from datetime import date datey = DateLine(show_dots=False) datey.add('1', [ (datetime(2013, 1, 2), 300), @@ -427,8 +426,8 @@ def get_test_routes(app): (time(21, 2, 29), 10), (time(12, 30, 59), 7) ]) - datey.add('2', - [(time(12, 12, 12), 4), (time(), 8), (time(23, 59, 59), 6)]) + datey.add( + '2', [(time(12, 12, 12), 4), (time(), 8), (time(23, 59, 59), 6)]) datey.x_label_rotation = 25 return datey.render_response() @@ -624,4 +623,10 @@ def get_test_routes(app): graph.legend_at_bottom = True return graph.render_response() + @app.route('/test/inverse_y_axis/') + def test_inverse_y_axis(chart): + graph = CHARTS_BY_NAME[chart](**dict(inverse_y_axis=True)) + graph.add('inverse', [1, 2, 3, 12, 24, 36]) + return graph.render_response() + return list(sorted(filter(lambda x: x.startswith('test'), locals()))) diff --git a/pygal/config.py b/pygal/config.py index 9e91fad..489618d 100644 --- a/pygal/config.py +++ b/pygal/config.py @@ -446,6 +446,8 @@ class Config(CommonConfig): False, bool, "Misc", "Don't prefix css") + inverse_y_axis = Key(False, bool, "Misc", "Inverse Y axis direction") + class SerieConfig(CommonConfig): """Class holding serie config values""" diff --git a/pygal/graph/graph.py b/pygal/graph/graph.py index 5a26986..c4d4215 100644 --- a/pygal/graph/graph.py +++ b/pygal/graph/graph.py @@ -24,7 +24,7 @@ Commmon graphing functions from __future__ import division from pygal.interpolate import INTERPOLATIONS from pygal.graph.base import BaseGraph -from pygal.view import View, LogView, XYLogView +from pygal.view import View, LogView, XYLogView, ReverseView from pygal.util import ( truncate, reverse_text_len, get_texts_box, cut, rad, decorate) from math import sqrt, ceil, cos @@ -58,7 +58,7 @@ class Graph(BaseGraph): else: view_class = LogView else: - view_class = View + view_class = ReverseView if self.inverse_y_axis else View self.view = view_class( self.width - self.margin.x, @@ -211,7 +211,9 @@ class Graph(BaseGraph): self.show_y_guides): self.svg.node( axis, 'path', - d='M%f %f h%f' % (0, self.view.height, self.view.width), + d='M%f %f h%f' % ( + 0, 0 if self.inverse_y_axis else self.view.height, + self.view.width), class_='line' ) diff --git a/pygal/view.py b/pygal/view.py index 0de1e48..e0a6ff5 100644 --- a/pygal/view.py +++ b/pygal/view.py @@ -155,6 +155,13 @@ class View(object): return (self.x(x), self.y(y)) +class ReverseView(View): + def y(self, y): + if y is None: + return None + return (self.height * (y - self.box.ymin) / self.box.height) + + class HorizontalView(View): def __init__(self, width, height, box): self._force_vertical = None