|
|
@ -16,17 +16,19 @@ |
|
|
|
# |
|
|
|
# |
|
|
|
# You should have received a copy of the GNU Lesser General Public License |
|
|
|
# You should have received a copy of the GNU Lesser General Public License |
|
|
|
# along with pygal. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
# along with pygal. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
""" |
|
|
|
|
|
|
|
Projection and bounding helpers |
|
|
|
"""Projection and bounding helpers""" |
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import division |
|
|
|
from __future__ import division |
|
|
|
from math import sin, cos, log10, pi |
|
|
|
from math import sin, cos, log10, pi |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Margin(object): |
|
|
|
class Margin(object): |
|
|
|
"""Graph margin""" |
|
|
|
|
|
|
|
|
|
|
|
"""Class reprensenting a margin (top, right, left, bottom)""" |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, top, right, bottom, left): |
|
|
|
def __init__(self, top, right, bottom, left): |
|
|
|
|
|
|
|
"""Create the margin object from the top, right, left, bottom margin""" |
|
|
|
self.top = top |
|
|
|
self.top = top |
|
|
|
self.right = right |
|
|
|
self.right = right |
|
|
|
self.bottom = bottom |
|
|
|
self.bottom = bottom |
|
|
@ -44,16 +46,23 @@ class Margin(object): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Box(object): |
|
|
|
class Box(object): |
|
|
|
|
|
|
|
|
|
|
|
"""Chart boundings""" |
|
|
|
"""Chart boundings""" |
|
|
|
|
|
|
|
|
|
|
|
margin = .02 |
|
|
|
margin = .02 |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, xmin=0, ymin=0, xmax=1, ymax=1): |
|
|
|
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._xmin = xmin |
|
|
|
self._ymin = ymin |
|
|
|
self._ymin = ymin |
|
|
|
self._xmax = xmax |
|
|
|
self._xmax = xmax |
|
|
|
self._ymax = ymax |
|
|
|
self._ymax = ymax |
|
|
|
|
|
|
|
|
|
|
|
def set_polar_box(self, rmin=0, rmax=1, tmin=0, tmax=2 * pi): |
|
|
|
def set_polar_box(self, rmin=0, rmax=1, tmin=0, tmax=2 * pi): |
|
|
|
|
|
|
|
"""Helper for polar charts""" |
|
|
|
self._rmin = rmin |
|
|
|
self._rmin = rmin |
|
|
|
self._rmax = rmax |
|
|
|
self._rmax = rmax |
|
|
|
self._tmin = tmin |
|
|
|
self._tmin = tmin |
|
|
@ -63,37 +72,45 @@ class Box(object): |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def xmin(self): |
|
|
|
def xmin(self): |
|
|
|
|
|
|
|
"""X minimum getter""" |
|
|
|
return self._xmin |
|
|
|
return self._xmin |
|
|
|
|
|
|
|
|
|
|
|
@xmin.setter |
|
|
|
@xmin.setter |
|
|
|
def xmin(self, value): |
|
|
|
def xmin(self, value): |
|
|
|
|
|
|
|
"""X minimum setter""" |
|
|
|
if value: |
|
|
|
if value: |
|
|
|
self._xmin = value |
|
|
|
self._xmin = value |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def ymin(self): |
|
|
|
def ymin(self): |
|
|
|
|
|
|
|
"""Y minimum getter""" |
|
|
|
return self._ymin |
|
|
|
return self._ymin |
|
|
|
|
|
|
|
|
|
|
|
@ymin.setter |
|
|
|
@ymin.setter |
|
|
|
def ymin(self, value): |
|
|
|
def ymin(self, value): |
|
|
|
|
|
|
|
"""Y minimum setter""" |
|
|
|
if value: |
|
|
|
if value: |
|
|
|
self._ymin = value |
|
|
|
self._ymin = value |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def xmax(self): |
|
|
|
def xmax(self): |
|
|
|
|
|
|
|
"""X maximum getter""" |
|
|
|
return self._xmax |
|
|
|
return self._xmax |
|
|
|
|
|
|
|
|
|
|
|
@xmax.setter |
|
|
|
@xmax.setter |
|
|
|
def xmax(self, value): |
|
|
|
def xmax(self, value): |
|
|
|
|
|
|
|
"""X maximum setter""" |
|
|
|
if value: |
|
|
|
if value: |
|
|
|
self._xmax = value |
|
|
|
self._xmax = value |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def ymax(self): |
|
|
|
def ymax(self): |
|
|
|
|
|
|
|
"""Y maximum getter""" |
|
|
|
return self._ymax |
|
|
|
return self._ymax |
|
|
|
|
|
|
|
|
|
|
|
@ymax.setter |
|
|
|
@ymax.setter |
|
|
|
def ymax(self, value): |
|
|
|
def ymax(self, value): |
|
|
|
|
|
|
|
"""Y maximum setter""" |
|
|
|
if value: |
|
|
|
if value: |
|
|
|
self._ymax = value |
|
|
|
self._ymax = value |
|
|
|
|
|
|
|
|
|
|
@ -129,8 +146,11 @@ class Box(object): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class View(object): |
|
|
|
class View(object): |
|
|
|
|
|
|
|
|
|
|
|
"""Projection base class""" |
|
|
|
"""Projection base class""" |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, width, height, box): |
|
|
|
def __init__(self, width, height, box): |
|
|
|
|
|
|
|
"""Create the view with a width an height and a box bounds""" |
|
|
|
self.width = width |
|
|
|
self.width = width |
|
|
|
self.height = height |
|
|
|
self.height = height |
|
|
|
self.box = box |
|
|
|
self.box = box |
|
|
@ -156,14 +176,22 @@ class View(object): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ReverseView(View): |
|
|
|
class ReverseView(View): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Same as view but reversed vertically""" |
|
|
|
|
|
|
|
|
|
|
|
def y(self, y): |
|
|
|
def y(self, y): |
|
|
|
|
|
|
|
"""Project reversed y""" |
|
|
|
if y is None: |
|
|
|
if y is None: |
|
|
|
return None |
|
|
|
return None |
|
|
|
return (self.height * (y - self.box.ymin) / self.box.height) |
|
|
|
return (self.height * (y - self.box.ymin) / self.box.height) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class HorizontalView(View): |
|
|
|
class HorizontalView(View): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Same as view but transposed""" |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, width, height, box): |
|
|
|
def __init__(self, width, height, box): |
|
|
|
|
|
|
|
"""Create the view with a width an height and a box bounds""" |
|
|
|
self._force_vertical = None |
|
|
|
self._force_vertical = None |
|
|
|
self.width = width |
|
|
|
self.width = width |
|
|
|
self.height = height |
|
|
|
self.height = height |
|
|
@ -173,7 +201,7 @@ class HorizontalView(View): |
|
|
|
self.box.swap() |
|
|
|
self.box.swap() |
|
|
|
|
|
|
|
|
|
|
|
def x(self, x): |
|
|
|
def x(self, x): |
|
|
|
"""Project x""" |
|
|
|
"""Project x as y""" |
|
|
|
if x is None: |
|
|
|
if x is None: |
|
|
|
return None |
|
|
|
return None |
|
|
|
if self._force_vertical: |
|
|
|
if self._force_vertical: |
|
|
@ -181,6 +209,7 @@ class HorizontalView(View): |
|
|
|
return super(HorizontalView, self).y(x) |
|
|
|
return super(HorizontalView, self).y(x) |
|
|
|
|
|
|
|
|
|
|
|
def y(self, y): |
|
|
|
def y(self, y): |
|
|
|
|
|
|
|
"""Project y as x""" |
|
|
|
if y is None: |
|
|
|
if y is None: |
|
|
|
return None |
|
|
|
return None |
|
|
|
if self._force_vertical: |
|
|
|
if self._force_vertical: |
|
|
@ -189,6 +218,7 @@ class HorizontalView(View): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PolarView(View): |
|
|
|
class PolarView(View): |
|
|
|
|
|
|
|
|
|
|
|
"""Polar projection for pie like graphs""" |
|
|
|
"""Polar projection for pie like graphs""" |
|
|
|
|
|
|
|
|
|
|
|
def __call__(self, rhotheta): |
|
|
|
def __call__(self, rhotheta): |
|
|
@ -201,9 +231,11 @@ class PolarView(View): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PolarLogView(View): |
|
|
|
class PolarLogView(View): |
|
|
|
|
|
|
|
|
|
|
|
"""Logarithmic polar projection""" |
|
|
|
"""Logarithmic polar projection""" |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, width, height, box): |
|
|
|
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) |
|
|
|
super(PolarLogView, self).__init__(width, height, box) |
|
|
|
if not hasattr(box, '_rmin') or not hasattr(box, '_rmax'): |
|
|
|
if not hasattr(box, '_rmin') or not hasattr(box, '_rmax'): |
|
|
|
raise Exception( |
|
|
|
raise Exception( |
|
|
@ -230,9 +262,11 @@ class PolarLogView(View): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PolarThetaView(View): |
|
|
|
class PolarThetaView(View): |
|
|
|
|
|
|
|
|
|
|
|
"""Logarithmic polar projection""" |
|
|
|
"""Logarithmic polar projection""" |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, width, height, box, aperture=pi / 3): |
|
|
|
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) |
|
|
|
super(PolarThetaView, self).__init__(width, height, box) |
|
|
|
self.aperture = aperture |
|
|
|
self.aperture = aperture |
|
|
|
if not hasattr(box, '_tmin') or not hasattr(box, '_tmax'): |
|
|
|
if not hasattr(box, '_tmin') or not hasattr(box, '_tmax'): |
|
|
@ -253,9 +287,11 @@ class PolarThetaView(View): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PolarThetaLogView(View): |
|
|
|
class PolarThetaLogView(View): |
|
|
|
|
|
|
|
|
|
|
|
"""Logarithmic polar projection""" |
|
|
|
"""Logarithmic polar projection""" |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, width, height, box, aperture=pi / 3): |
|
|
|
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) |
|
|
|
super(PolarThetaLogView, self).__init__(width, height, box) |
|
|
|
self.aperture = aperture |
|
|
|
self.aperture = aperture |
|
|
|
if not hasattr(box, '_tmin') or not hasattr(box, '_tmax'): |
|
|
|
if not hasattr(box, '_tmin') or not hasattr(box, '_tmax'): |
|
|
@ -288,9 +324,12 @@ class PolarThetaLogView(View): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LogView(View): |
|
|
|
class LogView(View): |
|
|
|
"""Logarithmic projection """ |
|
|
|
|
|
|
|
|
|
|
|
"""Y Logarithmic projection""" |
|
|
|
|
|
|
|
|
|
|
|
# Do not want to call the parent here |
|
|
|
# Do not want to call the parent here |
|
|
|
def __init__(self, width, height, box): |
|
|
|
def __init__(self, width, height, box): |
|
|
|
|
|
|
|
"""Create the view with a width an height and a box bounds""" |
|
|
|
self.width = width |
|
|
|
self.width = width |
|
|
|
self.height = height |
|
|
|
self.height = height |
|
|
|
self.box = box |
|
|
|
self.box = box |
|
|
@ -310,9 +349,12 @@ class LogView(View): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class XLogView(View): |
|
|
|
class XLogView(View): |
|
|
|
"""Logarithmic projection """ |
|
|
|
|
|
|
|
|
|
|
|
"""X logarithmic projection""" |
|
|
|
|
|
|
|
|
|
|
|
# Do not want to call the parent here |
|
|
|
# Do not want to call the parent here |
|
|
|
def __init__(self, width, height, box): |
|
|
|
def __init__(self, width, height, box): |
|
|
|
|
|
|
|
"""Create the view with a width an height and a box bounds""" |
|
|
|
self.width = width |
|
|
|
self.width = width |
|
|
|
self.height = height |
|
|
|
self.height = height |
|
|
|
self.box = box |
|
|
|
self.box = box |
|
|
@ -330,7 +372,11 @@ class XLogView(View): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class XYLogView(XLogView, LogView): |
|
|
|
class XYLogView(XLogView, LogView): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""X and Y logarithmic projection""" |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, width, height, box): |
|
|
|
def __init__(self, width, height, box): |
|
|
|
|
|
|
|
"""Create the view with a width an height and a box bounds""" |
|
|
|
self.width = width |
|
|
|
self.width = width |
|
|
|
self.height = height |
|
|
|
self.height = height |
|
|
|
self.box = box |
|
|
|
self.box = box |
|
|
@ -342,9 +388,12 @@ class XYLogView(XLogView, LogView): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class HorizontalLogView(XLogView): |
|
|
|
class HorizontalLogView(XLogView): |
|
|
|
"""Logarithmic projection """ |
|
|
|
|
|
|
|
|
|
|
|
"""Transposed Logarithmic projection""" |
|
|
|
|
|
|
|
|
|
|
|
# Do not want to call the parent here |
|
|
|
# Do not want to call the parent here |
|
|
|
def __init__(self, width, height, box): |
|
|
|
def __init__(self, width, height, box): |
|
|
|
|
|
|
|
"""Create the view with a width an height and a box bounds""" |
|
|
|
self._force_vertical = None |
|
|
|
self._force_vertical = None |
|
|
|
self.width = width |
|
|
|
self.width = width |
|
|
|
self.height = height |
|
|
|
self.height = height |
|
|
@ -357,7 +406,7 @@ class HorizontalLogView(XLogView): |
|
|
|
self.box.swap() |
|
|
|
self.box.swap() |
|
|
|
|
|
|
|
|
|
|
|
def x(self, x): |
|
|
|
def x(self, x): |
|
|
|
"""Project x""" |
|
|
|
"""Project x as y""" |
|
|
|
if x is None: |
|
|
|
if x is None: |
|
|
|
return None |
|
|
|
return None |
|
|
|
if self._force_vertical: |
|
|
|
if self._force_vertical: |
|
|
@ -365,6 +414,7 @@ class HorizontalLogView(XLogView): |
|
|
|
return super(XLogView, self).y(x) |
|
|
|
return super(XLogView, self).y(x) |
|
|
|
|
|
|
|
|
|
|
|
def y(self, y): |
|
|
|
def y(self, y): |
|
|
|
|
|
|
|
"""Project y as x""" |
|
|
|
if y is None: |
|
|
|
if y is None: |
|
|
|
return None |
|
|
|
return None |
|
|
|
if self._force_vertical: |
|
|
|
if self._force_vertical: |
|
|
|