|
|
|
@ -25,9 +25,10 @@ from __future__ import division
|
|
|
|
|
from pygal.interpolate import interpolation |
|
|
|
|
from pygal.graph.base import BaseGraph |
|
|
|
|
from pygal.view import View, LogView, XYLogView |
|
|
|
|
from pygal.util import is_major, truncate, reverse_text_len, get_texts_box, cut, rad |
|
|
|
|
from pygal.util import ( |
|
|
|
|
is_major, truncate, reverse_text_len, get_texts_box, cut, rad) |
|
|
|
|
from math import isnan, pi, sqrt, ceil, cos |
|
|
|
|
from itertools import repeat, izip, chain, count |
|
|
|
|
from itertools import repeat, izip, chain |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Graph(BaseGraph): |
|
|
|
@ -142,8 +143,7 @@ class Graph(BaseGraph):
|
|
|
|
|
d='M%f %f v%f' % (x, 0, self.view.height), |
|
|
|
|
class_='%s%sline' % ( |
|
|
|
|
'major ' if major else '', |
|
|
|
|
'guide ' if position != 0 and not last_guide |
|
|
|
|
else '')) |
|
|
|
|
'guide ' if position != 0 and not last_guide else '')) |
|
|
|
|
y += .5 * self.label_font_size + 5 |
|
|
|
|
text = self.svg.node( |
|
|
|
|
guides, 'text', |
|
|
|
@ -197,24 +197,25 @@ class Graph(BaseGraph):
|
|
|
|
|
self.y_label_rotation, x, y) |
|
|
|
|
|
|
|
|
|
if self._y_2nd_labels: |
|
|
|
|
secondary_ax = self.svg.node(self.nodes['plot'], class_="axis y2") |
|
|
|
|
secondary_ax = self.svg.node( |
|
|
|
|
self.nodes['plot'], class_="axis y2") |
|
|
|
|
for label, position in self._y_2nd_labels: |
|
|
|
|
major = is_major(position) |
|
|
|
|
# it is needed, to have the same structure as primary axis |
|
|
|
|
guides = self.svg.node(secondary_ax, class_='guides') |
|
|
|
|
x = self.view.width + 5 |
|
|
|
|
y = self.view.y(position) |
|
|
|
|
text = self.svg.node(guides, 'text', |
|
|
|
|
x = x, |
|
|
|
|
y = y + .35 * self.label_font_size, |
|
|
|
|
class_ = 'major' if major else '' |
|
|
|
|
text = self.svg.node( |
|
|
|
|
guides, 'text', |
|
|
|
|
x=x, |
|
|
|
|
y=y + .35 * self.label_font_size, |
|
|
|
|
class_='major' if major else '' |
|
|
|
|
) |
|
|
|
|
text.text = label |
|
|
|
|
if self.y_label_rotation: |
|
|
|
|
text.attrib['transform'] = "rotate(%d %f %f)" % ( |
|
|
|
|
self.y_label_rotation, x, y) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _legend(self): |
|
|
|
|
"""Make the legend box""" |
|
|
|
|
if not self.show_legend: |
|
|
|
@ -242,25 +243,23 @@ class Graph(BaseGraph):
|
|
|
|
|
self.nodes['graph'], class_='legends', |
|
|
|
|
transform='translate(%d, %d)' % (x, y)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
h = max(self.legend_box_size, self.legend_font_size) |
|
|
|
|
x_step = self.view.width / cols |
|
|
|
|
if self.legend_at_bottom: |
|
|
|
|
# if legends at the bottom, we dont split the windows |
|
|
|
|
counter = count() |
|
|
|
|
# gen structure - (i, (j, (l, tf))) |
|
|
|
|
# i - global serie number - used for coloring and identification |
|
|
|
|
# j - position within current legend box |
|
|
|
|
# l - label |
|
|
|
|
# tf - whether it is secondary label |
|
|
|
|
gen = enumerate(enumerate(chain( |
|
|
|
|
izip(self._legends, repeat(False)), |
|
|
|
|
izip(self._secondary_legends, repeat(True))))) |
|
|
|
|
secondary_legends = legends # svg node is the same |
|
|
|
|
izip(self._legends, repeat(False)), |
|
|
|
|
izip(self._secondary_legends, repeat(True))))) |
|
|
|
|
secondary_legends = legends # svg node is the same |
|
|
|
|
else: |
|
|
|
|
gen = enumerate(chain( |
|
|
|
|
enumerate(izip(self._legends, repeat(False))), |
|
|
|
|
enumerate(izip(self._secondary_legends, repeat(True))))) |
|
|
|
|
enumerate(izip(self._legends, repeat(False))), |
|
|
|
|
enumerate(izip(self._secondary_legends, repeat(True))))) |
|
|
|
|
|
|
|
|
|
# draw secondary axis on right |
|
|
|
|
x = self.margin.left + self.view.width + 10 |
|
|
|
@ -383,7 +382,7 @@ class Graph(BaseGraph):
|
|
|
|
|
return self._format(values[i][1]) |
|
|
|
|
|
|
|
|
|
def _points(self, x_pos): |
|
|
|
|
for serie in self.series + self.secondary_series: |
|
|
|
|
for serie in self.all_series: |
|
|
|
|
serie.points = [ |
|
|
|
|
(x_pos[i], v) |
|
|
|
|
for i, v in enumerate(serie.values)] |
|
|
|
|