diff --git a/docs/documentation/types/line.rst b/docs/documentation/types/line.rst index 6109c4d..287aec1 100644 --- a/docs/documentation/types/line.rst +++ b/docs/documentation/types/line.rst @@ -16,6 +16,20 @@ Basic simple line graph: line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + + Interruptions + ^^^^^^^^^^^^^ + + If you happen to want a break in the middle of a plot, you can pass None values. Additionally, + you will need to specify allow_interruptions=True in the constructor, in order for the behaviour + to be supported correctly + + .. pygal-code:: + + interrupted_chart = pygal.Line(allow_interruptions=True) + interrupted_chart.add('Temperature', [22, 34, 43, 12, None, 12, 55, None, 56]) + + Stacked ~~~~~~~ diff --git a/docs/documentation/types/xy.rst b/docs/documentation/types/xy.rst index 9d03de6..b804688 100644 --- a/docs/documentation/types/xy.rst +++ b/docs/documentation/types/xy.rst @@ -63,6 +63,9 @@ DateTime Date ++++ +If you want to plot date/time-series with breaks inside the plot, pass allow_interruptions=True to +the constructor. See Line on how to do it + .. pygal-code:: from datetime import date diff --git a/pygal/graph/line.py b/pygal/graph/line.py index bb0951a..37fbd8c 100644 --- a/pygal/graph/line.py +++ b/pygal/graph/line.py @@ -35,6 +35,7 @@ class Line(Graph): def __init__(self, *args, **kwargs): """Set _self_close as False, it's True for Radar like Line""" self._self_close = False + self.allow_interruptions = kwargs.get('allow_interruptions', False) super(Line, self).__init__(*args, **kwargs) @cached_property @@ -141,9 +142,35 @@ class Line(Graph): view_values = list(map(self.view, points)) if serie.fill: view_values = self._fill(view_values) - self.svg.line( - serie_node['plot'], view_values, close=self._self_close, - class_='line reactive' + (' nofill' if not serie.fill else '')) + + if self.allow_interruptions: + # view_values are in form [(x1, y1), (x2, y2)]. We + # need to split that into multiple sequences if a + # None is present here + + sequences = [] + cur_sequence = [] + for x, y in view_values: + if y is None and len(cur_sequence) > 0: + # emit current subsequence + sequences.append(cur_sequence) + cur_sequence = [] + elif y is None: # just discard + continue + else: + cur_sequence.append((x, y)) # append the element + + if len(cur_sequence) > 0: # emit last possible sequence + sequences.append(cur_sequence) + else: + # plain vanilla rendering + sequences = [view_values] + + for seq in sequences: + self.svg.line( + serie_node['plot'], seq, close=self._self_close, + class_='line reactive' + + (' nofill' if not serie.fill else '')) def _compute(self): """Compute y min and max and y scale and set labels"""