diff --git a/demo/moulinrouge/__init__.py b/demo/moulinrouge/__init__.py index c922067..b801144 100644 --- a/demo/moulinrouge/__init__.py +++ b/demo/moulinrouge/__init__.py @@ -144,7 +144,7 @@ def create_app(): config.style = styles['neon'] data = random.randrange(1, 10) order = random.randrange(1, 10) - series = b64encode(pickle.dumps(_random(type, data, order))) + series = b64encode(pickle.dumps(_random_series(type, data, order))) labels = [random_label() for i in range(data)] svgs = [] config.show_legend = bool(random.randrange(0, 1)) diff --git a/demo/simple_test.py b/demo/simple_test.py index b4e79eb..cf797df 100755 --- a/demo/simple_test.py +++ b/demo/simple_test.py @@ -55,7 +55,6 @@ config.x_labels = map(lambda x: '%s / %s / %s' % x, map(str, rng3))) config.title = "Stacked Bar test" config.style = NeonStyle -config.horizontal = True stackedbar = StackedBar(config) stackedbar.add('@@@@@@@', rng) @@ -73,7 +72,7 @@ with open('out-horizontalstackedbar.svg', 'w') as f: f.write(hstackedbar.render()) line = Line(Config(y_scale=.0005, fill=True, style=NeonStyle, - interpolate='univariate')) + interpolate='univariate', show_dots=False)) rng = range(-30, 31, 10) line.add('test1', [cos(x / 10.) for x in rng]) line.add('test2', [sin(x / 10.) for x in rng]) @@ -103,11 +102,11 @@ with open('out-xy.svg', 'w') as f: f.write(xy.render()) pie = Pie(Config(style=NeonStyle)) -pie.add('test', [11, 7, 12]) -pie.add('test2', [29, 21, 9]) -pie.add('test3', [24, 10, 32]) -pie.add('test4', [20, 18, 9]) -pie.add('test5', [17, 5, 10]) +pie.add('test', [11]) +# pie.add('test2', [29, 21, 9]) +# pie.add('test3', [24, 10, 32]) +# pie.add('test4', [20, 18, 9]) +# pie.add('test5', [17, 5, 10]) pie.title = "Pie test" with open('out-pie.svg', 'w') as f: f.write(pie.render()) diff --git a/pygal/__init__.py b/pygal/__init__.py index 3b389b9..087b2cf 100644 --- a/pygal/__init__.py +++ b/pygal/__init__.py @@ -16,7 +16,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with pygal. If not, see . -__version__ = '0.9.3' +__version__ = '0.9.5' from collections import namedtuple from pygal.graph.bar import Bar diff --git a/pygal/config.py b/pygal/config.py index b8e924f..d656983 100644 --- a/pygal/config.py +++ b/pygal/config.py @@ -25,6 +25,7 @@ class FontSizes(object): class Config(object): """Class holding config values""" + _horizontal = False # Graph width and height width, height = 800, 600 @@ -45,6 +46,8 @@ class Config(object): y_label_rotation = 0 # Set to false to remove legend show_legend = True + # Set to false to remove dots + show_dots = True # Size of legend boxes legend_box_size = 12 # X labels, must have same len than data. @@ -75,6 +78,10 @@ class Config(object): """Can be instanciated with config kwargs""" self.__dict__.update(kwargs) + def __call__(self, **kwargs): + """Can be updated with kwargs""" + self.__dict__.update(kwargs) + @property def font_sizes(self): fs = FontSizes() diff --git a/pygal/css/graph.css b/pygal/css/graph.css index f5d8117..db2ce39 100644 --- a/pygal/css/graph.css +++ b/pygal/css/graph.css @@ -134,7 +134,7 @@ svg * { opacity: 1; } -.series .bar:hover .rect, .series .slice:hover path{ +.series .bar:hover .rect, .series .slice:hover path, .series .slice:hover circle{ fill-opacity: 1; } diff --git a/pygal/graph/bar.py b/pygal/graph/bar.py index e14c7be..87e57c8 100644 --- a/pygal/graph/bar.py +++ b/pygal/graph/bar.py @@ -30,19 +30,19 @@ class Bar(Graph): def view(rng): """Project range""" t, T = rng - fun = swap if self.horizontal else ident + fun = swap if self._horizontal else ident return (self.view(fun(t)), self.view(fun(T))) bars = self.svg.node(serie_node, class_="bars") view_values = map(view, values) for i, ((x, y), (X, Y)) in enumerate(view_values): # x and y are left range coords and X, Y right ones - if self.horizontal: + if self._horizontal: x, y, X, Y = Y, X, y, x width = X - x padding = .1 * width inner_width = width - 2 * padding - if self.horizontal: + if self._horizontal: height = self.view.x(0) - y else: height = self.view.y(0) - y @@ -63,7 +63,6 @@ class Bar(Graph): y = y + height height = -height - y_txt = y + height / 2 + .3 * self.values_font_size bar = self.svg.node(bars, class_='bar') self.svg.transposable_node(bar, 'rect', x=x, @@ -73,9 +72,14 @@ class Bar(Graph): width=bar_inner_width, height=height, class_='rect') + if self._horizontal: + x += .3 * self.values_font_size + y += height / 2 + else: + y += height / 2 + .3 * self.values_font_size self.svg.transposable_node(bar, 'text', x=x + bar_inner_width / 2, - y=y_txt - shift, + y=y - shift, ).text = str(values[i][1][1]) return stack_vals diff --git a/pygal/graph/base.py b/pygal/graph/base.py index 23d58a4..32d95b8 100644 --- a/pygal/graph/base.py +++ b/pygal/graph/base.py @@ -10,9 +10,9 @@ from math import log10, sin, cos class BaseGraph(object): """Graphs commons""" - def __init__(self, config=None, horizontal=False): - self.horizontal = horizontal + def __init__(self, config=None, **kwargs): self.config = config or Config() + self.config(**kwargs) self.svg = Svg(self) self.series = [] self.margin = Margin(*([20] * 4)) diff --git a/pygal/graph/horizontal.py b/pygal/graph/horizontal.py index 4fdf9e8..483e5e6 100644 --- a/pygal/graph/horizontal.py +++ b/pygal/graph/horizontal.py @@ -24,7 +24,7 @@ from pygal.graph.stackedbar import StackedBar class HorizontalGraph(Graph): """Horizontal graph""" def __init__(self, *args, **kwargs): - kwargs['horizontal'] = True + kwargs['_horizontal'] = True super(HorizontalGraph, self).__init__(*args, **kwargs) def _compute(self): diff --git a/pygal/graph/line.py b/pygal/graph/line.py index 868c81d..8c597a8 100644 --- a/pygal/graph/line.py +++ b/pygal/graph/line.py @@ -45,12 +45,13 @@ class Line(Graph): def line(self, serie_node, serie): view_values = map(self.view, serie.points) - dots = self.svg.node(serie_node, class_="dots") - for i, (x, y) in enumerate(view_values): - dot = self.svg.node(dots, class_='dot') - self.svg.node(dot, 'circle', cx=x, cy=y, r=2.5) - self.svg.node(dot, 'text', x=x, y=y - ).text = self._get_value(serie.points, i) + if self.show_dots: + dots = self.svg.node(serie_node, class_="dots") + for i, (x, y) in enumerate(view_values): + dot = self.svg.node(dots, class_='dot') + self.svg.node(dot, 'circle', cx=x, cy=y, r=2.5) + self.svg.node(dot, 'text', x=x, y=y + ).text = self._get_value(serie.points, i) if self.stroke: if self.interpolate: diff --git a/pygal/graph/pie.py b/pygal/graph/pie.py index 5899d1f..1afe9fa 100644 --- a/pygal/graph/pie.py +++ b/pygal/graph/pie.py @@ -33,17 +33,24 @@ class Pie(Graph): if small: r *= .9 center_str = '%f %f' % center - rxy = '%f %f' % tuple([r] * 2) - to = '%f %f' % (r * sin(angle), r * (1 - cos(angle))) - self.svg.node(slice_, 'path', - d='M%s v%f a%s 0 %d 1 %s z' % ( - center_str, -r, - rxy, - 1 if angle > pi else 0, - to), - transform='rotate(%f %s)' % ( - start_angle * 180 / pi, center_str), - class_='slice') + if perc == 1: + self.svg.node(slice_, 'circle', + cx=center[0], + cy=center[1], + r=r, + class_='slice') + else: + rxy = '%f %f' % tuple([r] * 2) + to = '%f %f' % (r * sin(angle), r * (1 - cos(angle))) + self.svg.node(slice_, 'path', + d='M%s v%f a%s 0 %d 1 %s z' % ( + center_str, -r, + rxy, + 1 if angle > pi else 0, + to), + transform='rotate(%f %s)' % ( + start_angle * 180 / pi, center_str), + class_='slice') text_angle = pi / 2. - (start_angle + angle / 2.) text_r = min(center) * .8 self.svg.node(slice_, 'text', diff --git a/pygal/style.py b/pygal/style.py index 5151ab1..f33147d 100644 --- a/pygal/style.py +++ b/pygal/style.py @@ -97,7 +97,7 @@ LightSolarizedStyle = Style( plot_background='#eee8d5', foreground='#657b83', foreground_light='#586e75', - foreground_dark='#839496', + foreground_dark='#073642', opacity='.6', opacity_hover='.9', transition='500ms ease-in', diff --git a/pygal/svg.py b/pygal/svg.py index a93d499..51f6a2d 100644 --- a/pygal/svg.py +++ b/pygal/svg.py @@ -49,7 +49,7 @@ class Svg(object): f.read(), style=self.graph.style, font_sizes=self.graph.font_sizes, - hidden='y' if self.graph.horizontal else 'x', + hidden='y' if self.graph._horizontal else 'x', fill_opacity=self.graph.style.opacity if self.graph.fill else 0, fill_opacity_hover=self.graph.style.opacity_hover @@ -72,7 +72,7 @@ class Svg(object): return etree.SubElement(parent, tag, attrib) def transposable_node(self, parent=None, tag='g', attrib=None, **extras): - if self.graph.horizontal: + if self.graph._horizontal: for key1, key2 in (('x', 'y'), ('width', 'height')): attr1 = extras.get(key1, None) attr2 = extras.get(key2, None)