diff --git a/pygal/graph/line.py~ b/pygal/graph/line.py~
deleted file mode 100644
index 3544d20..0000000
--- a/pygal/graph/line.py~
+++ /dev/null
@@ -1,215 +0,0 @@
-# -*- coding: utf-8 -*-
-# This file is part of pygal
-#
-# A python svg graph plotting library
-# Copyright © 2012-2016 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 .
-
-"""
-Line chart: Display series of data as markers (dots)
-connected by straight segments
-"""
-
-from __future__ import division
-
-from pygal.graph.graph import Graph
-from pygal.util import alter, cached_property, decorate
-
-
-class Line(Graph):
-
- """Line graph class"""
-
- def __init__(self, *args, **kwargs):
- """Set _self_close as False, it's True for Radar like Line"""
- self._self_close = False
- super(Line, self).__init__(*args, **kwargs)
-
- @cached_property
- def _values(self):
- """Getter for series values (flattened)"""
- return [
- val[1]
- for serie in self.series
- for val in (serie.interpolated
- if self.interpolate else serie.points)
- if val[1] is not None and (not self.logarithmic or val[1] > 0)]
-
- @cached_property
- def _secondary_values(self):
- """Getter for secondary series values (flattened)"""
- return [
- val[1]
- for serie in self.secondary_series
- for val in (serie.interpolated
- if self.interpolate else serie.points)
- if val[1] is not None and (not self.logarithmic or val[1] > 0)]
-
- def _fill(self, values):
- """Add extra values to fill the line"""
- zero = self.view.y(min(max(self.zero, self._box.ymin), self._box.ymax))
-
- # Check to see if the data has been padded with "none's"
- # Fill doesn't work correctly otherwise
- end = len(values) - 1
- while end > 0:
- x, y = values[end]
- if self.missing_value_fill_truncation == "either":
- if x is not None and y is not None:
- break
- elif self.missing_value_fill_truncation == "x":
- if x is not None:
- break
- elif self.missing_value_fill_truncation == "y":
- if y is not None:
- break
- else:
- raise ValueError(
- "Invalid value ({}) for config key "
- "'missing_value_fill_truncation';"
- " Use 'x', 'y' or 'either'".format(
- self.missing_value_fill_truncation))
- end -= 1
-
- return ([(values[0][0], zero)] +
- values +
- [(values[end][0], zero)])
-
- def line(self, serie, rescale=False):
- """Draw the line serie"""
- serie_node = self.svg.serie(serie)
- if rescale and self.secondary_series:
- points = self._rescale(serie.points)
- else:
- points = serie.points
- view_values = list(map(self.view, points))
- if serie.show_dots:
- for i, (x, y) in enumerate(view_values):
- if None in (x, y):
- continue
-
- #modified
- if self.logarithmic:
- if points[i][1] == None or points[i][1] <= 0:
- continue
-
- if (serie.show_only_major_dots and
- self.x_labels and i < len(self.x_labels) and
- self.x_labels[i] not in self._x_labels_major):
- continue
-
- metadata = serie.metadata.get(i)
- classes = []
- if x > self.view.width / 2:
- classes.append('left')
- if y > self.view.height / 2:
- classes.append('top')
- classes = ' '.join(classes)
-
- self._confidence_interval(
- serie_node['overlay'], x, y, serie.values[i], metadata)
-
- dots = decorate(
- self.svg,
- self.svg.node(serie_node['overlay'], class_="dots"),
- metadata)
-
- val = self._format(serie, i)
- alter(self.svg.transposable_node(
- dots, 'circle', cx=x, cy=y, r=serie.dots_size,
- class_='dot reactive tooltip-trigger'), metadata)
- self._tooltip_data(
- dots, val, x, y,
- xlabel=self._get_x_label(i))
- self._static_value(
- serie_node, val,
- x + self.style.value_font_size,
- y + self.style.value_font_size,
- metadata)
-
- if serie.stroke:
- if self.interpolate:
- points = serie.interpolated
- if rescale and self.secondary_series:
- points = self._rescale(points)
- view_values = list(map(self.view, points))
- if serie.fill:
- view_values = self._fill(view_values)
-
- if serie.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]
-
- #modified
- if self.logarithmic:
- for seq in sequences:
- for ele in seq[::-1]:
- if points[seq.index(ele)][1]==None or points[seq.index(ele)][1] <= 0:
- del seq[seq.index(ele)]
-
- 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"""
- # X Labels
- if self.horizontal:
- self._x_pos = [
- x / (self._len - 1) for x in range(self._len)
- ][::-1] if self._len != 1 else [.5] # Center if only one value
- else:
- self._x_pos = [
- x / (self._len - 1) for x in range(self._len)
- ] if self._len != 1 else [.5] # Center if only one value
-
- self._points(self._x_pos)
-
- if self.include_x_axis:
- # Y Label
- self._box.ymin = min(self._min or 0, 0)
- self._box.ymax = max(self._max or 0, 0)
- else:
- self._box.ymin = self._min
- self._box.ymax = self._max
-
- def _plot(self):
- """Plot the serie lines and secondary serie lines"""
- for serie in self.series:
- self.line(serie)
-
- for serie in self.secondary_series:
- self.line(serie, True)
diff --git a/pygal/view.py b/pygal/view.py
index 04f7503..0faa108 100644
--- a/pygal/view.py
+++ b/pygal/view.py
@@ -343,7 +343,7 @@ class LogView(View):
def y(self, y):
"""Project y"""
if y is None or y <= 0 or self.log10_ymax - self.log10_ymin == 0:
- return 0.00001
+ return 0
return (self.height - self.height *
(log10(y) - self.log10_ymin) / (
self.log10_ymax - self.log10_ymin))
diff --git a/pygal/view.py~ b/pygal/view.py~
deleted file mode 100644
index f9887db..0000000
--- a/pygal/view.py~
+++ /dev/null
@@ -1,423 +0,0 @@
-# -*- coding: utf-8 -*-
-# This file is part of pygal
-#
-# A python svg graph plotting library
-# Copyright © 2012-2016 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 .
-
-"""Projection and bounding helpers"""
-
-from __future__ import division
-
-from math import cos, log10, pi, sin
-
-
-class Margin(object):
-
- """Class reprensenting a margin (top, right, left, bottom)"""
-
- def __init__(self, top, right, bottom, left):
- """Create the margin object from the top, right, left, bottom margin"""
- self.top = top
- self.right = right
- self.bottom = bottom
- self.left = left
-
- @property
- def x(self):
- """Helper for total x margin"""
- return self.left + self.right
-
- @property
- def y(self):
- """Helper for total y margin"""
- return self.top + self.bottom
-
-
-class Box(object):
-
- """Chart boundings"""
-
- margin = .02
-
- def __init__(self, xmin=0, ymin=0, xmax=1, ymax=1):
- """
- Create the chart bounds with min max horizontal
- and vertical values
- """
- self._xmin = xmin
- self._ymin = ymin
- self._xmax = xmax
- self._ymax = ymax
-
- def set_polar_box(self, rmin=0, rmax=1, tmin=0, tmax=2 * pi):
- """Helper for polar charts"""
- self._rmin = rmin
- self._rmax = rmax
- self._tmin = tmin
- self._tmax = tmax
- self.xmin = self.ymin = rmin - rmax
- self.xmax = self.ymax = rmax - rmin
-
- @property
- def xmin(self):
- """X minimum getter"""
- return self._xmin
-
- @xmin.setter
- def xmin(self, value):
- """X minimum setter"""
- if value is not None:
- self._xmin = value
-
- @property
- def ymin(self):
- """Y minimum getter"""
- return self._ymin
-
- @ymin.setter
- def ymin(self, value):
- """Y minimum setter"""
- if value is not None:
- self._ymin = value
-
- @property
- def xmax(self):
- """X maximum getter"""
- return self._xmax
-
- @xmax.setter
- def xmax(self, value):
- """X maximum setter"""
- if value is not None:
- self._xmax = value
-
- @property
- def ymax(self):
- """Y maximum getter"""
- return self._ymax
-
- @ymax.setter
- def ymax(self, value):
- """Y maximum setter"""
- if value or self.ymin:
- self._ymax = value
-
- @property
- def width(self):
- """Helper for box width"""
- return self.xmax - self.xmin
-
- @property
- def height(self):
- """Helper for box height"""
- return self.ymax - self.ymin
-
- def swap(self):
- """Return the box (for horizontal graphs)"""
- self.xmin, self.ymin = self.ymin, self.xmin
- self.xmax, self.ymax = self.ymax, self.xmax
-
- def fix(self, with_margin=True):
- """Correct box when no values and take margin in account"""
- if not self.width:
- self.xmax = self.xmin + 1
- if not self.height:
- self.ymin /= 2
- self.ymax += self.ymin
- xmargin = self.margin * self.width
- self.xmin -= xmargin
- self.xmax += xmargin
- if with_margin:
- ymargin = self.margin * self.height
- self.ymin -= ymargin
- self.ymax += ymargin
-
-
-class View(object):
-
- """Projection base class"""
-
- def __init__(self, width, height, box):
- """Create the view with a width an height and a box bounds"""
- self.width = width
- self.height = height
- self.box = box
- self.box.fix()
-
- def x(self, x):
- """Project x"""
- if x is None:
- return None
- return self.width * (x - self.box.xmin) / self.box.width
-
- def y(self, y):
- """Project y"""
- if y is None:
- return None
- return (self.height - self.height *
- (y - self.box.ymin) / self.box.height)
-
- def __call__(self, xy):
- """Project x and y"""
- x, y = xy
- return (self.x(x), self.y(y))
-
-
-class ReverseView(View):
-
- """Same as view but reversed vertically"""
-
- def y(self, y):
- """Project reversed y"""
- if y is None:
- return None
- return (self.height * (y - self.box.ymin) / self.box.height)
-
-
-class HorizontalView(View):
-
- """Same as view but transposed"""
-
- def __init__(self, width, height, box):
- """Create the view with a width an height and a box bounds"""
- self._force_vertical = None
- self.width = width
- self.height = height
-
- self.box = box
- self.box.fix()
- self.box.swap()
-
- def x(self, x):
- """Project x as y"""
- if x is None:
- return None
- if self._force_vertical:
- return super(HorizontalView, self).x(x)
- return super(HorizontalView, self).y(x)
-
- def y(self, y):
- """Project y as x"""
- if y is None:
- return None
- if self._force_vertical:
- return super(HorizontalView, self).y(y)
- return super(HorizontalView, self).x(y)
-
-
-class PolarView(View):
-
- """Polar projection for pie like graphs"""
-
- def __call__(self, rhotheta):
- """Project rho and theta"""
- if None in rhotheta:
- return None, None
- rho, theta = rhotheta
- return super(PolarView, self).__call__(
- (rho * cos(theta), rho * sin(theta)))
-
-
-class PolarLogView(View):
-
- """Logarithmic polar projection"""
-
- def __init__(self, width, height, box):
- """Create the view with a width an height and a box bounds"""
- super(PolarLogView, self).__init__(width, height, box)
- if not hasattr(box, '_rmin') or not hasattr(box, '_rmax'):
- raise Exception(
- 'Box must be set with set_polar_box for polar charts')
-
- self.log10_rmax = log10(self.box._rmax)
- self.log10_rmin = log10(self.box._rmin)
- if self.log10_rmin == self.log10_rmax:
- self.log10_rmax = self.log10_rmin + 1
-
- def __call__(self, rhotheta):
- """Project rho and theta"""
- if None in rhotheta:
- return None, None
- rho, theta = rhotheta
- # Center case
- if rho == 0:
- return super(PolarLogView, self).__call__((0, 0))
- rho = (self.box._rmax - self.box._rmin) * (
- log10(rho) - self.log10_rmin) / (
- self.log10_rmax - self.log10_rmin)
- return super(PolarLogView, self).__call__(
- (rho * cos(theta), rho * sin(theta)))
-
-
-class PolarThetaView(View):
-
- """Logarithmic polar projection"""
-
- def __init__(self, width, height, box, aperture=pi / 3):
- """Create the view with a width an height and a box bounds"""
- super(PolarThetaView, self).__init__(width, height, box)
- self.aperture = aperture
- if not hasattr(box, '_tmin') or not hasattr(box, '_tmax'):
- raise Exception(
- 'Box must be set with set_polar_box for polar charts')
-
- def __call__(self, rhotheta):
- """Project rho and theta"""
- if None in rhotheta:
- return None, None
- rho, theta = rhotheta
- start = 3 * pi / 2 + self.aperture / 2
- theta = start + (2 * pi - self.aperture) * (
- theta - self.box._tmin) / (
- self.box._tmax - self.box._tmin)
- return super(PolarThetaView, self).__call__(
- (rho * cos(theta), rho * sin(theta)))
-
-
-class PolarThetaLogView(View):
-
- """Logarithmic polar projection"""
-
- def __init__(self, width, height, box, aperture=pi / 3):
- """Create the view with a width an height and a box bounds"""
- super(PolarThetaLogView, self).__init__(width, height, box)
- self.aperture = aperture
- if not hasattr(box, '_tmin') or not hasattr(box, '_tmax'):
- raise Exception(
- 'Box must be set with set_polar_box for polar charts')
- self.log10_tmax = log10(self.box._tmax) if self.box._tmax > 0 else 0
- self.log10_tmin = log10(self.box._tmin) if self.box._tmin > 0 else 0
- if self.log10_tmin == self.log10_tmax:
- self.log10_tmax = self.log10_tmin + 1
-
- def __call__(self, rhotheta):
- """Project rho and theta"""
- if None in rhotheta:
- return None, None
- rho, theta = rhotheta
- # Center case
- if theta == 0:
- return super(PolarThetaLogView, self).__call__((0, 0))
- theta = self.box._tmin + (self.box._tmax - self.box._tmin) * (
- log10(theta) - self.log10_tmin) / (
- self.log10_tmax - self.log10_tmin)
-
- start = 3 * pi / 2 + self.aperture / 2
- theta = start + (2 * pi - self.aperture) * (
- theta - self.box._tmin) / (
- self.box._tmax - self.box._tmin)
-
- return super(PolarThetaLogView, self).__call__(
- (rho * cos(theta), rho * sin(theta)))
-
-
-class LogView(View):
-
- """Y Logarithmic projection"""
-
- # Do not want to call the parent here
- def __init__(self, width, height, box):
- """Create the view with a width an height and a box bounds"""
- self.width = width
- self.height = height
- self.box = box
- self.log10_ymax = log10(self.box.ymax) if self.box.ymax > 0 else 0
- self.log10_ymin = log10(self.box.ymin) if self.box.ymin > 0 else 0
- if self.log10_ymin == self.log10_ymax:
- self.log10_ymax = self.log10_ymin + 1
- self.box.fix(False)
-
- def y(self, y):
- """Project y"""
- if y is None or y <= 0 or self.log10_ymax - self.log10_ymin == 0:
- return 0.000001
- return (self.height - self.height *
- (log10(y) - self.log10_ymin) / (
- self.log10_ymax - self.log10_ymin))
-
-
-class XLogView(View):
-
- """X logarithmic projection"""
-
- # Do not want to call the parent here
- def __init__(self, width, height, box):
- """Create the view with a width an height and a box bounds"""
- self.width = width
- self.height = height
- self.box = box
- self.log10_xmax = log10(self.box.xmax) if self.box.xmax > 0 else 0
- self.log10_xmin = log10(self.box.xmin) if self.box.xmin > 0 else 0
- self.box.fix(False)
-
- def x(self, x):
- """Project x"""
- if x is None or x <= 0 or self.log10_xmax - self.log10_xmin == 0:
- return None
- return (self.width *
- (log10(x) - self.log10_xmin) /
- (self.log10_xmax - self.log10_xmin))
-
-
-class XYLogView(XLogView, LogView):
-
- """X and Y logarithmic projection"""
-
- def __init__(self, width, height, box):
- """Create the view with a width an height and a box bounds"""
- self.width = width
- self.height = height
- self.box = box
- self.log10_ymax = log10(self.box.ymax) if self.box.ymax > 0 else 0
- self.log10_ymin = log10(self.box.ymin) if self.box.ymin > 0 else 0
- self.log10_xmax = log10(self.box.xmax) if self.box.xmax > 0 else 0
- self.log10_xmin = log10(self.box.xmin) if self.box.xmin > 0 else 0
- self.box.fix(False)
-
-
-class HorizontalLogView(XLogView):
-
- """Transposed Logarithmic projection"""
-
- # Do not want to call the parent here
- def __init__(self, width, height, box):
- """Create the view with a width an height and a box bounds"""
- self._force_vertical = None
- self.width = width
- self.height = height
- self.box = box
- self.log10_xmax = log10(self.box.ymax) if self.box.ymax > 0 else 0
- self.log10_xmin = log10(self.box.ymin) if self.box.ymin > 0 else 0
- if self.log10_xmin == self.log10_xmax:
- self.log10_xmax = self.log10_xmin + 1
- self.box.fix(False)
- self.box.swap()
-
- def x(self, x):
- """Project x as y"""
- if x is None:
- return None
- if self._force_vertical:
- return super(HorizontalLogView, self).x(x)
- return super(XLogView, self).y(x)
-
- def y(self, y):
- """Project y as x"""
- if y is None:
- return None
- if self._force_vertical:
- return super(XLogView, self).y(y)
- return super(HorizontalLogView, self).x(y)