diff --git a/.gitignore b/.gitignore index 000c541..be4c767 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ dist .coverage *.pyc *.egg-info +.cov-py* +coverage-py* +junit-py* diff --git a/CHANGELOG b/CHANGELOG index 1ff7b68..c4e1780 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +V 1.6.3 UNRELEASED + Add show_x_labels option to remove them and the x axis. + Set print_values to False by default. + Fix secondary serie text values when None in data. (#192) + V 1.6.2 Add margin_top, margin_right, margin_bottom, margin_left options which defaults to margin. (thanks djt) Update django mime parameter from mimetype to content_type. (thanks kswiat) diff --git a/demo/moulinrouge/tests.py b/demo/moulinrouge/tests.py index 9d10abd..83d63a3 100644 --- a/demo/moulinrouge/tests.py +++ b/demo/moulinrouge/tests.py @@ -305,9 +305,9 @@ def get_test_routes(app): chart.y_label_rotation = 50 chart.add('1', [30, 20, -2]) chart.add(10 * '1b', [-4, 50, 6], secondary=True) - chart.add(10 * '2b', [3, 30, -1], secondary=True) + chart.add(10 * '2b', [None, 10, 20], secondary=True) chart.add('2', [8, 21, -0]) - chart.add('3', [1, 2, 3]) + chart.add('3', [None, 20, 10]) chart.add('3b', [-1, 2, -3], secondary=True) return chart.render_response() @@ -548,4 +548,25 @@ def get_test_routes(app): 6]) return c.render_response() + @app.route('/test/sparkline/') + def test_sparkline_for(chart): + graph = CHARTS_BY_NAME[chart](**dict( + width=200, + height=50, + show_dots=False, + show_legend=False, + show_y_labels=False, + show_x_labels=False, + spacing=0, + margin=5, + explicit_size=True + )) + graph.add('1', [1, 3, 12, 3, 4, None, 9]) + graph.add('2', [7, -4, 10, None, 8, 3, 1]) + graph.add('3', [7, -14, -10, None, 8, 3, 1]) + graph.add('4', [7, 4, -10, None, 8, 3, 1]) + graph.x_labels = ('a', 'b', 'c', 'd', 'e', 'f', 'g') + graph.legend_at_bottom = True + return graph.render_response() + return list(sorted(filter(lambda x: x.startswith('test'), locals()))) diff --git a/pygal/__init__.py b/pygal/__init__.py index 0c320cf..fbb9b56 100644 --- a/pygal/__init__.py +++ b/pygal/__init__.py @@ -21,7 +21,7 @@ Pygal - A python svg graph plotting library """ -__version__ = '1.6.2' +__version__ = '1.6.3' import sys from pygal.config import Config from pygal.ghost import Ghost, REAL_CHARTS diff --git a/pygal/config.py b/pygal/config.py index 8a0a807..f85bf3a 100644 --- a/pygal/config.py +++ b/pygal/config.py @@ -285,6 +285,9 @@ class Config(CommonConfig): None, int, "Label", "Mark n evenly distributed labels as major.") + show_x_labels = Key( + True, bool, "Label", "Set to false to hide x-labels") + show_minor_x_labels = Key( True, bool, "Label", "Set to false to hide x-labels not marked major") @@ -324,7 +327,9 @@ class Config(CommonConfig): missing_value_fill_truncation = Key( "x", str, "Look", - "Filled series with missing x and/or y values at the end of a series are closed at the first value with a missing 'x' (default), 'y' or 'either'") + "Filled series with missing x and/or y values at the end of a series " + "are closed at the first value with a missing " + "'x' (default), 'y' or 'either'") # Value # human_readable = Key( @@ -351,7 +356,8 @@ class Config(CommonConfig): "{'type': 'cardinal', 'c': .5}", int) mode = Key( - None, str, "Value", "Sets the mode to be used. (Currently only supported on box plot)", + None, str, "Value", "Sets the mode to be used. " + "(Currently only supported on box plot)", "May be %s" % ' or '.join(["1.5IQR", "extremes"])) order_min = Key( @@ -388,7 +394,7 @@ class Config(CommonConfig): no_data_font_size = Key(64, int, "Text", "No data text font size") print_values = Key( - True, bool, + False, bool, "Text", "Print values when graph is in non interactive mode") print_zeroes = Key( diff --git a/pygal/ghost.py b/pygal/ghost.py index b191400..27019d8 100644 --- a/pygal/ghost.py +++ b/pygal/ghost.py @@ -191,6 +191,7 @@ class Ghost(object): height=50, show_dots=False, show_legend=False, + show_x_labels=False, show_y_labels=False, spacing=0, margin=5, diff --git a/pygal/graph/base.py b/pygal/graph/base.py index d9d3e95..8d6d68c 100644 --- a/pygal/graph/base.py +++ b/pygal/graph/base.py @@ -110,24 +110,24 @@ class BaseGraph(object): self.margin.right += ( self.spacing + w + self.legend_box_size) - for xlabels in (self._x_labels, self._x_2nd_labels): - if xlabels: - h, w = get_texts_box( - map(lambda x: truncate(x, self.truncate_label or 25), - cut(xlabels)), - self.label_font_size) - self._x_labels_height = self.spacing + max( - w * sin(rad(self.x_label_rotation)), h) - if xlabels is self._x_labels: - self.margin.bottom += self._x_labels_height - else: - self.margin.top += self._x_labels_height - if self.x_label_rotation: - self.margin.right = max( - w * cos(rad(self.x_label_rotation)), - self.margin.right) - if not self._x_labels: - self._x_labels_height = 0 + self._x_labels_height = 0 + if (self._x_labels or self._x_2nd_labels) and self.show_x_labels: + for xlabels in (self._x_labels, self._x_2nd_labels): + if xlabels: + h, w = get_texts_box( + map(lambda x: truncate(x, self.truncate_label or 25), + cut(xlabels)), + self.label_font_size) + self._x_labels_height = self.spacing + max( + w * sin(rad(self.x_label_rotation)), h) + if xlabels is self._x_labels: + self.margin.bottom += self._x_labels_height + else: + self.margin.top += self._x_labels_height + if self.x_label_rotation: + self.margin.right = max( + w * cos(rad(self.x_label_rotation)), + self.margin.right) if self.show_y_labels: for ylabels in (self._y_labels, self._y_2nd_labels): diff --git a/pygal/graph/graph.py b/pygal/graph/graph.py index 9ddadd6..5a26986 100644 --- a/pygal/graph/graph.py +++ b/pygal/graph/graph.py @@ -118,7 +118,7 @@ class Graph(BaseGraph): def _x_axis(self): """Make the x axis: labels and guides""" - if not self._x_labels: + if not self._x_labels or not self.show_x_labels: return axis = self.svg.node(self.nodes['plot'], class_="axis x%s" % ( ' always_show' if self.show_x_guides else '' @@ -423,8 +423,9 @@ class Graph(BaseGraph): def _rescale(self, points): return [ - (x, self._scale_diff + (y - self._scale_min_2nd) * self._scale) - for x, y in points if y is not None] + (x, self._scale_diff + (y - self._scale_min_2nd) * self._scale + if y is not None else None) + for x, y in points] def _tooltip_data(self, node, value, x, y, classes=None): self.svg.node(node, 'desc', class_="value").text = value