Browse Source

format to private

pull/8/head
Florian Mounier 13 years ago
parent
commit
6ca2500fdf
  1. 1
      .gitignore
  2. 3
      pygal/config.py
  3. 4
      pygal/graph/bar.py
  4. 35
      pygal/graph/base.py
  5. 8
      pygal/graph/graph.py
  6. 4
      pygal/graph/line.py
  7. 4
      pygal/graph/radar.py
  8. 2
      pygal/graph/stackedbar.py
  9. 6
      pygal/graph/xy.py

1
.gitignore vendored

@ -2,3 +2,4 @@
.livereload .livereload
dist dist
.tox .tox
.coverage

3
pygal/config.py

@ -104,6 +104,7 @@ class Config(object):
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
def font_sizes(self, with_unit=True): def font_sizes(self, with_unit=True):
"""Getter for all font size configs"""
fs = FontSizes() fs = FontSizes()
for name in dir(self): for name in dir(self):
if name.endswith('_font_size'): if name.endswith('_font_size'):
@ -111,5 +112,5 @@ class Config(object):
fs, fs,
name.replace('_font_size', ''), name.replace('_font_size', ''),
('%dpx' % getattr(self, name) ('%dpx' % getattr(self, name)
) if with_unit else getattr(self, name)) ) if with_unit else getattr(self, name))
return fs return fs

4
pygal/graph/bar.py

@ -40,7 +40,7 @@ class Bar(Graph):
if None in (x, y): if None in (x, y):
continue continue
# x and y are left range coords and X, Y right ones # x and y are left range coords and X, Y right ones
val = self.format(values[i][1][1]) val = self._format(values[i][1][1])
if self._horizontal: if self._horizontal:
x, y, X, Y = Y, X, y, x x, y, X, Y = Y, X, y, x
width = X - x width = X - x
@ -112,7 +112,7 @@ class Bar(Graph):
self._x_ranges = zip(x_pos, x_pos[1:]) self._x_ranges = zip(x_pos, x_pos[1:])
self._x_labels = self.x_labels and zip(self.x_labels, [ self._x_labels = self.x_labels and zip(self.x_labels, [
sum(x_range) / 2 for x_range in self._x_ranges]) sum(x_range) / 2 for x_range in self._x_ranges])
self._y_labels = zip(map(self.format, y_pos), y_pos) self._y_labels = zip(map(self._format, y_pos), y_pos)
def _plot(self): def _plot(self):
for serie in self.series: for serie in self.series:

35
pygal/graph/base.py

@ -31,26 +31,35 @@ class BaseGraph(object):
"""Graphs commons""" """Graphs commons"""
def __init__(self, config=None, **kwargs): def __init__(self, config=None, **kwargs):
"""Init the graph"""
self.config = config or Config() self.config = config or Config()
self.config(**kwargs) self.config(**kwargs)
self.svg = Svg(self) self.svg = Svg(self)
self.series = [] self.series = []
self._x_labels = self._y_labels = None self._x_labels = self._y_labels = None
def add(self, title, values):
"""Add a serie to this graph"""
self.series.append(Serie(title, values, len(self.series)))
def _init(self): def _init(self):
"""Init the graph"""
self.margin = Margin(*([20] * 4)) self.margin = Margin(*([20] * 4))
self._box = Box() self._box = Box()
def __getattr__(self, attr): def __getattr__(self, attr):
"""Search in config, then in self"""
if attr in dir(self.config): if attr in dir(self.config):
return object.__getattribute__(self.config, attr) return object.__getattribute__(self.config, attr)
return object.__getattribute__(self, attr) return object.__getattribute__(self, attr)
@property @property
def format(self): def _format(self):
"""Return the value formatter for this graph"""
return humanize if self.human_readable else str return humanize if self.human_readable else str
def _compute_logarithmic_scale(self, min_, max_): def _compute_logarithmic_scale(self, min_, max_):
"""Compute an optimal scale for logarithmic"""
min_order = int(floor(log10(min_))) min_order = int(floor(log10(min_)))
max_order = int(ceil(log10(max_))) max_order = int(ceil(log10(max_)))
positions = [] positions = []
@ -71,6 +80,7 @@ class BaseGraph(object):
return positions return positions
def _compute_scale(self, min_, max_, min_scale=4, max_scale=20): def _compute_scale(self, min_, max_, min_scale=4, max_scale=20):
"""Compute an optimal scale between min and max"""
if min_ == 0 and max_ == 0: if min_ == 0 and max_ == 0:
return [0] return [0]
if max_ - min_ == 0: if max_ - min_ == 0:
@ -99,19 +109,26 @@ class BaseGraph(object):
return positions return positions
def _text_len(self, lenght, fs): def _text_len(self, lenght, fs):
"""Approximation of text length"""
return lenght * 0.6 * fs return lenght * 0.6 * fs
def _get_text_box(self, text, fs): def _get_text_box(self, text, fs):
"""Approximation of text bounds"""
return (fs, self._text_len(len(text), fs)) return (fs, self._text_len(len(text), fs))
def _get_texts_box(self, texts, fs): def _get_texts_box(self, texts, fs):
"""Approximation of multiple texts bounds"""
max_len = max(map(len, texts)) max_len = max(map(len, texts))
return (fs, self._text_len(max_len, fs)) return (fs, self._text_len(max_len, fs))
def _compute(self): def _compute(self):
"""Initial computations to draw the graph""" """Initial computations to draw the graph"""
def _plot(self):
"""Actual plotting of the graph"""
def _compute_margin(self): def _compute_margin(self):
"""Compute graph margins from set texts"""
if self.show_legend: if self.show_legend:
h, w = self._get_texts_box( h, w = self._get_texts_box(
cut(self.series, 'title'), self.legend_font_size) cut(self.series, 'title'), self.legend_font_size)
@ -138,10 +155,12 @@ class BaseGraph(object):
@cached_property @cached_property
def _legends(self): def _legends(self):
"""Getter for series title"""
return [serie.title for serie in self.series] return [serie.title for serie in self.series]
@cached_property @cached_property
def _values(self): def _values(self):
"""Getter for series values (flattened)"""
return [val return [val
for serie in self.series for serie in self.series
for val in serie.values for val in serie.values
@ -149,18 +168,18 @@ class BaseGraph(object):
@cached_property @cached_property
def _len(self): def _len(self):
"""Getter for the maximum series size"""
return max([len(serie.values) for serie in self.series]) return max([len(serie.values) for serie in self.series])
def _draw(self): def _draw(self):
"""Draw all the things"""
self._compute() self._compute()
self._compute_margin() self._compute_margin()
self._decorate() self._decorate()
self._plot() self._plot()
def add(self, title, values):
self.series.append(Serie(title, values, len(self.series)))
def _has_data(self): def _has_data(self):
"""Check if there is any data"""
if len(self.series) == 0: if len(self.series) == 0:
return False return False
for serie in self.series: for serie in self.series:
@ -171,6 +190,7 @@ class BaseGraph(object):
return True return True
def _render(self): def _render(self):
"""Make the graph internally"""
self._init() self._init()
self.svg._init() self.svg._init()
if self._has_data(): if self._has_data():
@ -180,30 +200,37 @@ class BaseGraph(object):
self.svg._pre_render(True) self.svg._pre_render(True)
def render(self, is_unicode=False): def render(self, is_unicode=False):
"""Render the graph, and return the svg string"""
self._render() self._render()
return self.svg.render(is_unicode=is_unicode) return self.svg.render(is_unicode=is_unicode)
def render_tree(self): def render_tree(self):
"""Render the graph, and return lxml tree"""
self._render() self._render()
return self.svg.root return self.svg.root
def render_pyquery(self): def render_pyquery(self):
"""Render the graph, and return a pyquery wrapped tree"""
from pyquery import PyQuery as pq from pyquery import PyQuery as pq
return pq(self.render_tree()) return pq(self.render_tree())
def render_in_browser(self): def render_in_browser(self):
"""Render the graph, open it in your browser with black magic"""
from lxml.html import open_in_browser from lxml.html import open_in_browser
open_in_browser(self.render_tree(), encoding='utf-8') open_in_browser(self.render_tree(), encoding='utf-8')
def render_response(self): def render_response(self):
"""Render the graph, and return a Flask response"""
from flask import Response from flask import Response
return Response(self.render(), mimetype='image/svg+xml') return Response(self.render(), mimetype='image/svg+xml')
def render_to_file(self, filename): def render_to_file(self, filename):
"""Render the graph, and write it to filename"""
with io.open(filename, 'w', encoding='utf-8') as f: with io.open(filename, 'w', encoding='utf-8') as f:
f.write(self.render(is_unicode=True)) f.write(self.render(is_unicode=True))
def render_to_png(self, filename): def render_to_png(self, filename):
"""Render the graph, convert it to png and write it to filename"""
import cairosvg import cairosvg
from io import BytesIO from io import BytesIO
fakefile = BytesIO() fakefile = BytesIO()

8
pygal/graph/graph.py

@ -26,6 +26,7 @@ class Graph(BaseGraph):
"""Graph super class containing generic common functions""" """Graph super class containing generic common functions"""
def _decorate(self): def _decorate(self):
"""Draw all decorations"""
self._set_view() self._set_view()
self._make_graph() self._make_graph()
self._x_axis() self._x_axis()
@ -34,12 +35,14 @@ class Graph(BaseGraph):
self._title() self._title()
def _set_view(self): def _set_view(self):
"""Assign a view to current graph"""
self.view = (LogView if self.logarithmic else View)( self.view = (LogView if self.logarithmic else View)(
self.width - self.margin.x, self.width - self.margin.x,
self.height - self.margin.y, self.height - self.margin.y,
self._box) self._box)
def _make_graph(self): def _make_graph(self):
"""Init common graph svg structure"""
self.graph_node = self.svg.node( self.graph_node = self.svg.node(
class_='graph %s-graph' % self.__class__.__name__.lower()) class_='graph %s-graph' % self.__class__.__name__.lower())
self.svg.node(self.graph_node, 'rect', self.svg.node(self.graph_node, 'rect',
@ -78,6 +81,7 @@ class Graph(BaseGraph):
self.svg.node(self.tooltip_node, 'text') self.svg.node(self.tooltip_node, 'text')
def _x_axis(self): def _x_axis(self):
"""Make the x axis: labels and guides"""
if not self._x_labels: if not self._x_labels:
return return
@ -105,6 +109,7 @@ class Graph(BaseGraph):
self.x_label_rotation, x, y) self.x_label_rotation, x, y)
def _y_axis(self): def _y_axis(self):
"""Make the y axis: labels and guides"""
if not self._y_labels: if not self._y_labels:
return return
@ -137,6 +142,7 @@ class Graph(BaseGraph):
self.y_label_rotation, x, y) self.y_label_rotation, x, y)
def _legend(self): def _legend(self):
"""Make the legend box"""
if not self.show_legend: if not self.show_legend:
return return
legends = self.svg.node( legends = self.svg.node(
@ -166,6 +172,7 @@ class Graph(BaseGraph):
).text = title ).text = title
def _title(self): def _title(self):
"""Make the title"""
if self.title: if self.title:
self.svg.node(self.graph_node, 'text', class_='title', self.svg.node(self.graph_node, 'text', class_='title',
x=self.margin.left + self.view.width / 2, x=self.margin.left + self.view.width / 2,
@ -173,6 +180,7 @@ class Graph(BaseGraph):
).text = self.title ).text = self.title
def _serie(self, serie): def _serie(self, serie):
"""Make serie node"""
return dict( return dict(
plot=self.svg.node( plot=self.svg.node(
self.plot, self.plot,

4
pygal/graph/line.py

@ -27,7 +27,7 @@ class Line(Graph):
"""Line graph""" """Line graph"""
def _get_value(self, values, i): def _get_value(self, values, i):
return self.format(values[i][1]) return self._format(values[i][1])
@cached_property @cached_property
def _values(self): def _values(self):
@ -114,7 +114,7 @@ class Line(Graph):
) if not self.y_labels else map(float, self.y_labels) ) if not self.y_labels else map(float, self.y_labels)
self._x_labels = self.x_labels and zip(self.x_labels, self._x_pos) self._x_labels = self.x_labels and zip(self.x_labels, self._x_pos)
self._y_labels = zip(map(self.format, self._y_pos), self._y_pos) self._y_labels = zip(map(self._format, self._y_pos), self._y_pos)
def _plot(self): def _plot(self):
for serie in self.series: for serie in self.series:

4
pygal/graph/radar.py

@ -31,7 +31,7 @@ class Radar(Line):
return values return values
def _get_value(self, values, i): def _get_value(self, values, i):
return self.format(values[i][0]) return self._format(values[i][0])
@cached_property @cached_property
def _values(self): def _values(self):
@ -126,5 +126,5 @@ class Radar(Line):
self._box.ymin, self._box.ymax, max_scale=8 self._box.ymin, self._box.ymax, max_scale=8
) if not self.y_labels else map(int, self.y_labels) ) if not self.y_labels else map(int, self.y_labels)
self._x_labels = self.x_labels and zip(self.x_labels, self._x_pos) self._x_labels = self.x_labels and zip(self.x_labels, self._x_pos)
self._y_labels = zip(map(self.format, self._y_pos), self._y_pos) self._y_labels = zip(map(self._format, self._y_pos), self._y_pos)
self._box.xmin = self._box.ymin = - self._box.ymax self._box.xmin = self._box.ymin = - self._box.ymax

2
pygal/graph/stackedbar.py

@ -45,7 +45,7 @@ class StackedBar(Bar):
self._x_labels = self.x_labels and zip(self.x_labels, [ self._x_labels = self.x_labels and zip(self.x_labels, [
sum(x_range) / 2 for x_range in self._x_ranges]) sum(x_range) / 2 for x_range in self._x_ranges])
self._y_labels = zip(map(self.format, y_pos), y_pos) self._y_labels = zip(map(self._format, y_pos), y_pos)
def _plot(self): def _plot(self):
stack_vals = [[0, 0] for i in range(self._length)] stack_vals = [[0, 0] for i in range(self._length)]

6
pygal/graph/xy.py

@ -26,7 +26,7 @@ class XY(Line):
"""XY Line graph""" """XY Line graph"""
def _get_value(self, values, i): def _get_value(self, values, i):
return 'x=%s, y=%s' % tuple(map(self.format, values[i])) return 'x=%s, y=%s' % tuple(map(self._format, values[i]))
def _compute(self): def _compute(self):
xvals = [val[0] xvals = [val[0]
@ -69,5 +69,5 @@ class XY(Line):
x_pos = self._compute_scale(self._box.xmin, self._box.xmax) x_pos = self._compute_scale(self._box.xmin, self._box.xmax)
y_pos = self._compute_scale(self._box.ymin, self._box.ymax) y_pos = self._compute_scale(self._box.ymin, self._box.ymax)
self._x_labels = zip(map(self.format, x_pos), x_pos) self._x_labels = zip(map(self._format, x_pos), x_pos)
self._y_labels = zip(map(self.format, y_pos), y_pos) self._y_labels = zip(map(self._format, y_pos), y_pos)

Loading…
Cancel
Save