Skip to content

Commit

Permalink
Fix radar axis behaviour (Kozea#247)
Browse files Browse the repository at this point in the history
  • Loading branch information
paradoxxxzero committed Jul 28, 2015
1 parent c175c08 commit 6e91e71
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 77 deletions.
25 changes: 24 additions & 1 deletion demo/moulinrouge/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pygal import (
Bar, Gauge, Pyramid, Funnel, Dot, StackedBar, StackedLine, XY,
CHARTS_BY_NAME, Config, Line, Histogram, Box,
Pie, Treemap, TimeLine, DateLine,
Pie, Treemap, TimeLine, DateLine, Radar,
DateTimeLine)

try:
Expand Down Expand Up @@ -675,6 +675,29 @@ def test_stroke_config():
'lol6', 'lol7', 'lol8', 'lol9', 'lol10', 'lol11']
return line.render_response()

@app.route('/test/radar')
def test_radar():
radar = Radar()
for i in range(10):
radar.add(str(i), [i * j for j in range(8)])
radar.x_labels = range(8)
radar.x_label_rotation = 35
radar.y_label_rotation = 35
radar.y_labels = [{
'label': '500',
'value': 10
}, {
'label': '1000',
'value': 20
}, {
'label': '5000',
'value': 30
}, {
'label': '10000',
'value': 40
}]
return radar.render_response()

@app.route('/test/pie_serie_radius')
def test_pie_serie_radius():
pie = Pie()
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Changelog
* Default ``print_zeroes`` to True
* (Re)Add xlink in desc to show on tooltip
* Activate element on tooltip hovering. (#106)
* Fix radar axis behaviour (#247)

2.0.0
=====
Expand Down
2 changes: 1 addition & 1 deletion pygal/css/graph.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
}

{{ id }}.guide.line {
fill-opacity: 0;
fill: none;
}

{{ id }}.centered {
Expand Down
24 changes: 10 additions & 14 deletions pygal/graph/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,12 @@ def prepare_values(self, raw, offset=0):
adapters.remove(fun)
adapters = adapters + [positive, not_zero]
adapters = adapters + [decimal_to_float]
adapter = reduce(compose, adapters) if not self.strict else ident

if adapter and self.y_labels:
self.y_labels = list(map(adapter, self.y_labels))

x_adapter = reduce(
self._adapt = reduce(compose, adapters) if not self.strict else ident
self._x_adapt = reduce(
compose, self._x_adapters) if not self.strict and getattr(
self, '_x_adapters', None) else ident

if x_adapter and self.x_labels:
self.x_labels = list(map(x_adapter, self.x_labels))

series = []

raw = [(
Expand Down Expand Up @@ -151,20 +145,22 @@ def prepare_values(self, raw, offset=0):
value = (value, self.zero, self.zero)
elif len(value) == 2:
value = (1, value[0], value[1])
value = list(map(adapter, value))
value = list(map(self._adapt, value))
elif self._dual:
if value is None:
value = (None, None)
elif not is_list_like(value):
value = (value, self.zero)
if x_adapter:
value = (x_adapter(value[0]), adapter(value[1]))
if self._x_adapt:
value = (
self._x_adapt(value[0]),
self._adapt(value[1]))
if isinstance(self, BaseMap):
value = (adapter(value[0]), value[1])
value = (self._adapt(value[0]), value[1])
else:
value = list(map(adapter, value))
value = list(map(self._adapt, value))
else:
value = adapter(value)
value = self._adapt(value)

values.append(value)
serie_config = SerieConfig()
Expand Down
3 changes: 2 additions & 1 deletion pygal/graph/dot.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from math import log10

from pygal._compat import to_str
from pygal.graph.graph import Graph
from pygal.util import alter, cached_property, decorate, safe_enumerate
from pygal.view import ReverseView, View
Expand Down Expand Up @@ -90,7 +91,7 @@ def _compute(self):

def _compute_y_labels(self):
self._y_labels = list(zip(
self.y_labels or [
self.y_labels and map(to_str, self.y_labels) or [
serie.title['title']
if isinstance(serie.title, dict)
else serie.title for serie in self.series],
Expand Down
2 changes: 1 addition & 1 deletion pygal/graph/dual.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def _compute_x_labels(self):
pos = x_pos[i]
title = x_label
else:
pos = float(x_label)
pos = self._x_adapt(float(x_label))
title = self._x_format(x_label)

self._x_labels.append((title, pos))
Expand Down
6 changes: 3 additions & 3 deletions pygal/graph/funnel.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ def _compute_x_labels(self):
self._x_labels = list(
zip(self.x_labels and
map(to_str, self.x_labels) or [
serie.title['title']
if isinstance(serie.title, dict)
else serie.title for serie in self.series],
serie.title['title']
if isinstance(serie.title, dict)
else serie.title for serie in self.series],
map(self._center, self._x_pos)))

def _plot(self):
Expand Down
2 changes: 1 addition & 1 deletion pygal/graph/gauge.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def _compute_y_labels(self):
else:
pos = float(y_label)
title = self._format(y_label)
self._y_labels.append((title, pos))
self._y_labels.append((title, self._adapt(pos)))
self.min_ = min(self.min_, min(cut(self._y_labels, 1)))
self.max_ = max(self.max_, max(cut(self._y_labels, 1)))
self._box.set_polar_box(
Expand Down
2 changes: 1 addition & 1 deletion pygal/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ def _compute_y_labels(self):
else:
pos = float(y_label)
title = self._format(y_label)
self._y_labels.append((title, pos))
self._y_labels.append((title, self._adapt(pos)))
self._box.ymin = min(self._box.ymin, min(cut(self._y_labels, 1)))
self._box.ymax = max(self._box.ymax, max(cut(self._y_labels, 1)))
else:
Expand Down
111 changes: 59 additions & 52 deletions pygal/graph/radar.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
from pygal._compat import is_str
from pygal.adapters import none_to_zero, positive
from pygal.graph.line import Line
from pygal.util import cached_property, compute_scale, cut, deg, majorize
from pygal.util import (
cached_property, compute_scale, cut, deg, truncate,
reverse_text_len)
from pygal.view import PolarLogView, PolarView


Expand Down Expand Up @@ -75,96 +77,101 @@ def _set_view(self):

def _x_axis(self, draw_axes=True):
"""Override x axis to make it polar"""
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 web")
axis = self.svg.node(self.nodes['plot'], class_="axis x web%s" % (
' always_show' if self.show_x_guides else ''
))
format_ = lambda x: '%f %f' % x
center = self.view((0, 0))
r = self._rmax
if self.x_labels_major:
x_labels_major = self.x_labels_major
elif self.x_labels_major_every:
x_labels_major = [self._x_labels[i][0] for i in range(
0, len(self._x_labels), self.x_labels_major_every)]
elif self.x_labels_major_count:
label_count = len(self._x_labels)
major_count = self.x_labels_major_count
if (major_count >= label_count):
x_labels_major = [label[0] for label in self._x_labels]
truncation = self.truncate_label
if not truncation:
if self.x_label_rotation or len(self._x_labels) <= 1:
truncation = 25
else:
x_labels_major = [self._x_labels[
int(i * label_count / major_count)][0]
for i in range(major_count)]
else:
x_labels_major = []
first_label_position = self.view.x(self._x_labels[0][1]) or 0
last_label_position = self.view.x(self._x_labels[-1][1]) or 0
available_space = (
last_label_position - first_label_position) / (
len(self._x_labels) - 1)
truncation = reverse_text_len(
available_space, self.style.label_font_size)
truncation = max(truncation, 1)

for label, theta in self._x_labels:
major = label in x_labels_major
major = label in self._x_major_labels
if not (self.show_minor_x_labels or major):
continue
guides = self.svg.node(axis, class_='guides')
end = self.view((r, theta))

self.svg.node(
guides, 'path',
d='M%s L%s' % (format_(center), format_(end)),
class_='%sline' % ('major ' if major else ''))
class_='%s%sline' % (
'axis ' if label == "0" else '',
'major ' if major else ''))

r_txt = (1 - self._box.__class__.margin) * self._box.ymax
pos_text = self.view((r_txt, theta))
text = self.svg.node(
guides, 'text',
x=pos_text[0],
y=pos_text[1],
class_='major' if major else '')
text.text = label
text.text = truncate(label, truncation)
if text.text != label:
self.svg.node(guides, 'title').text = label
else:
self.svg.node(
guides, 'title',
).text = self._x_format(theta)

angle = - theta + pi / 2
if cos(angle) < 0:
angle -= pi
text.attrib['transform'] = 'rotate(%f %s)' % (
deg(angle), format_(pos_text))
self.x_label_rotation or deg(angle), format_(pos_text))

def _y_axis(self, draw_axes=True):
"""Override y axis to make it polar"""
if not self._y_labels:
if not self._y_labels or not self.show_y_labels:
return

axis = self.svg.node(self.nodes['plot'], class_="axis y web")

if self.y_labels_major:
y_labels_major = self.y_labels_major
elif self.y_labels_major_every:
y_labels_major = [self._y_labels[i][1] for i in range(
0, len(self._y_labels), self.y_labels_major_every)]
elif self.y_labels_major_count:
label_count = len(self._y_labels)
major_count = self.y_labels_major_count
if (major_count >= label_count):
y_labels_major = [label[1] for label in self._y_labels]
else:
y_labels_major = [self._y_labels[
int(i * (label_count - 1) / (major_count - 1))][1]
for i in range(major_count)]
else:
y_labels_major = majorize(
cut(self._y_labels, 1)
)
for label, r in reversed(self._y_labels):
major = r in y_labels_major
major = r in self._y_major_labels
if not (self.show_minor_y_labels or major):
continue
guides = self.svg.node(axis, class_='guides')
self.svg.line(
guides, [self.view((r, theta)) for theta in self._x_pos],
close=True,
class_='%sguide line' % (
'major ' if major else ''))
guides = self.svg.node(axis, class_='%sguides' % (
'logarithmic ' if self.logarithmic else ''
))
if self.show_y_guides:
self.svg.line(
guides, [self.view((r, theta)) for theta in self._x_pos],
close=True,
class_='%sguide line' % (
'major ' if major else ''))
x, y = self.view((r, self._x_pos[0]))
self.svg.node(
x -= 5
text = self.svg.node(
guides, 'text',
x=x - 5,
x=x,
y=y,
class_='major' if major else ''
).text = label
)
text.text = label

if self.y_label_rotation:
text.attrib['transform'] = "rotate(%d %f %f)" % (
self.y_label_rotation, x, y)

self.svg.node(
guides, 'title',
).text = self._format(r)

def _compute(self):
"""Compute r min max and labels position"""
Expand Down Expand Up @@ -209,7 +216,7 @@ def _compute_y_labels(self):
else:
pos = float(y_label)
title = self._format(y_label)
self._y_labels.append((title, pos))
self._y_labels.append((title, self._adapt(pos)))
self._rmin = min(self._rmin, min(cut(self._y_labels, 1)))
self._rmax = max(self._rmax, max(cut(self._y_labels, 1)))
self._box.set_polar_box(self._rmin, self._rmax)
Expand Down
5 changes: 3 additions & 2 deletions pygal/graph/stackedbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
"""

from __future__ import division
from pygal.graph.bar import Bar
from pygal.util import compute_scale, swap, ident

from pygal.adapters import none_to_zero
from pygal.graph.bar import Bar
from pygal.util import ident, swap


class StackedBar(Bar):
Expand Down

0 comments on commit 6e91e71

Please sign in to comment.