Browse Source

Clean up config + organize it

pull/8/head
Florian Mounier 13 years ago
parent
commit
864ee6a6b2
  1. 2
      demo/cabaret/static/css.css
  2. 12
      demo/cabaret/static/js.js
  3. 6
      demo/cabaret/templates/_layout.jinja2
  4. 116
      demo/cabaret/templates/index.jinja2
  5. 11
      demo/moulinrouge/tests.py
  6. 161
      pygal/config.py
  7. 4
      pygal/graph/bar.py
  8. 2
      pygal/graph/line.py
  9. 3
      pygal/util.py

2
demo/cabaret/static/css.css

@ -16,7 +16,7 @@ figure svg {
background: none; background: none;
} }
textarea { .nav a {
-webkit-transition: all 500ms ease-out; -webkit-transition: all 500ms ease-out;
-moz-transition: all 500ms ease-out; -moz-transition: all 500ms ease-out;
transition: all 500ms ease-out; transition: all 500ms ease-out;

12
demo/cabaret/static/js.js

@ -9,9 +9,8 @@ function resend() {
var $this = $(this), var $this = $(this),
val = $this.val(); val = $this.val();
if($this.attr('type') == 'checkbox') { if($this.attr('type') == 'checkbox') {
val = $this.is(":checked"); opts[$this.attr('id').replace('c-', '')] = $this.is(":checked");
} } else if(val) {
if(val) {
opts[$this.attr('id').replace('c-', '')] = val; opts[$this.attr('id').replace('c-', '')] = val;
} }
}); });
@ -29,9 +28,9 @@ function resend() {
// $fig.find('div').get(0).innerHTML = data; // $fig.find('div').get(0).innerHTML = data;
$fig.find('div').html(data); $fig.find('div').html(data);
init_svg($fig.find('svg').get(0)); init_svg($fig.find('svg').get(0));
$('textarea').css({'-webkit-box-shadow': ''}); $('.nav a').css({color: ''});
}).fail(function () { }).fail(function () {
$('textarea').css({'-webkit-box-shadow': 'inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(255, 0, 0, 0.6)'}); $('.nav a').css({color: 'red'});
}); });
} }
@ -41,7 +40,6 @@ $(function () {
$('#style').on('change', resend); $('#style').on('change', resend);
$('.c-opts:not([type=checkbox])').on('input', resend); $('.c-opts:not([type=checkbox])').on('input', resend);
$('.c-opts[type=checkbox]').on('change', resend); $('.c-opts[type=checkbox]').on('change', resend);
$('label.tt').tooltip({ placement: 'right' }); $('div.tt').tooltip();
$('input.tt').tooltip({ placement: 'top' });
resend(); resend();
}); });

6
demo/cabaret/templates/_layout.jinja2

@ -27,13 +27,13 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="row-fluid"> <div class="row-fluid">
<div class="span3"> <div class="span4">
<div class="well sidebar-nav"> <div class="">
{% block side %} {% block side %}
{% endblock side %} {% endblock side %}
</div> </div>
</div> </div>
<div class="span9"> <div class="span8">
{% block section %} {% block section %}
{% endblock section %} {% endblock section %}
</div> </div>

116
demo/cabaret/templates/index.jinja2

@ -1,54 +1,80 @@
{% extends '_layout.jinja2' %} {% extends '_layout.jinja2' %}
{% block side %} {% block side %}
<ul class="nav nav-list"> <form class="form-horizontal">
<li class="nav-header">Type</li> <div class="tabbable tabs-left">
<li> <ul class="nav nav-tabs">
<select id="type"> <li class="active"><a href="#main" data-toggle="tab">Main</a></li>
{% for name in charts_names %} {% for group in configs[0].categories if group != 'Style' %}
<option value="{{ name }}">{{ name }}</option> <li><a href="#{{ group }}" data-toggle="tab">{{ group }}</a></li>
{% endfor %} {% endfor %}
</select> </ul>
</li>
<li class="divider"></li> <div class="tab-content">
<li class="nav-header">Data</li> <div class="tab-pane active" id="main">
<li> <div class="control-group tt" title="Chose the chart type">
<textarea id="data" rows="3"> <label class="control-label" for="type">Type</label>
<div class="controls">
<select id="type">
{% for name in charts_names %}
<option value="{{ name }}">{{ name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="control-group tt" title="Enter the chart data">
<label class="control-label" for="data">Data</label>
<div class="controls">
<textarea id="data" rows="3">
"Serie 1": [4, 5, 2, 8, 2, 0], "Serie 1": [4, 5, 2, 8, 2, 0],
"Serie 2": [0, 5, 2, 6, 2] "Serie 2": [0, 5, 2, 6, 2]
</textarea> </textarea>
</li> </div>
<li class="divider"></li> </div>
<li>
<li class="nav-header">Style</li> <div class="control-group tt" title="Chose the chart style">
<select id="style"> <label class="control-label" for="style">Style</label>
{% for style in styles_names | sort(-1) %} <div class="controls">
<option value="{{ style }}">{{ style.replace('_', ' ') | title }}</option> <select id="style">
{% endfor %} {% for style in styles_names | sort(-1) %}
</select> <option value="{{ style }}">{{ style.replace('_', ' ') | title }}</option>
</li> {% endfor %}
<li class="divider"></li> </select>
{% for key in configs if key.name not in ['js', 'css'] %} </div>
{% set doc = 'title="' + key.doc + ' ' + key.subdoc + '"' %} </div>
<li>
<div class="controls">
{% if key.is_boolean %}
<label class="nav-header checkbox tt" for="c-{{ key.name }}" {{ doc }}>
<input type="checkbox" id="c-{{ key.name }}" class="c-opts tt" {{ 'checked' if key.value }} {{ doc }} />{{ key.name }}
</label>
{% else %}
<label class="nav-header tt" for="c-{{ key.name }}" {{ doc }}> {{ key.name }}</label>
{% if key.is_numeric %}
<input type="number" id="c-{{ key.name }}" class="c-opts tt" value="{{ key.value or ''}}" {{ doc }} />
{% elif key.is_string %}
<input type="text" id="c-{{ key.name }}" class="c-opts tt" value="{{ key.value or ''}}" {{ doc }} />
{% elif key.is_list %}
<input type="text" id="c-{{ key.name }}" class="c-opts tt list-of-{{ key.subtype}}" placeholder="value1, value2, ..." value="{{ key.value or ''}}" {{ doc }} />
{% endif %}
{% endif %}
</div> </div>
</li>
{% endfor %} {% for group, keys in configs | groupby('category') %}
</ul> <div class="tab-pane" id="{{ group }}">
{% for key in keys if key.name not in ['js', 'css', 'style'] %}
{% set doc = 'title="' + key.doc + ' <br /><small>' + key.subdoc + '</small>"' %}
<div class="control-group tt" {{ doc }}>
{% if key.is_boolean %}
<div class="controls">
<label class="checkbox" for="c-{{ key.name }}">
<input type="checkbox" id="c-{{ key.name }}" class="c-opts" {{ 'checked' if key.value }} />{{ key.name.replace('_', ' ') |title }}
</label>
</div>
{% else %}
<label class="control-label" for="c-{{ key.name }}" > {{ key.name.replace('_', ' ') | title }}</label>
<div class="controls">
{% if key.is_numeric %}
<input type="number" id="c-{{ key.name }}" class="c-opts" value="{{ key.value or ''}}" />
{% elif key.is_string %}
<input type="text" id="c-{{ key.name }}" class="c-opts" value="{{ key.value or ''}}" />
{% elif key.is_list %}
<input type="text" id="c-{{ key.name }}" class="c-opts list-of-{{ key.subtype }}" placeholder="value1, value2{{ ', ...' if key.name != 'range' }}" value="{{ key.value or ''}}" />
{% endif %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
</form>
{% endblock side %} {% endblock side %}
{% block section %} {% block section %}

11
demo/moulinrouge/tests.py

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of pygal # This file is part of pygal
from pygal import Bar, Gauge, Pyramid, Funnel, Dot, StackedBar, CHARTS_BY_NAME, Config from pygal import (
Bar, Gauge, Pyramid, Funnel, Dot, StackedBar,
CHARTS_BY_NAME, Config, Line)
from pygal.style import styles from pygal.style import styles
@ -111,6 +113,13 @@ def get_test_routes(app):
stacked.add('2', [4, 5, 6]) stacked.add('2', [4, 5, 6])
return stacked.render_response() return stacked.render_response()
@app.route('/test/show_dots')
def test_show_dots():
line = Line(show_dots=False)
line.add('1', [1, 2, 3])
line.add('2', [4, 5, 6])
return line.render_response()
@app.route('/test/config') @app.route('/test/config')
def test_config(): def test_config():

161
pygal/config.py

@ -32,13 +32,22 @@ CONFIG_ITEMS = []
class Key(object): class Key(object):
def __init__(self, default_value, type_, doc, subdoc="", subtype=None): categories = []
def __init__(
self, default_value, type_, category, doc,
subdoc="", subtype=None):
self.value = default_value self.value = default_value
self.type = type_ self.type = type_
self.doc = doc self.doc = doc
self.category = category
self.subdoc = subdoc self.subdoc = subdoc
self.subtype = subtype self.subtype = subtype
self.name = "Unbound" self.name = "Unbound"
if not category in self.categories:
self.categories.append(category)
CONFIG_ITEMS.append(self) CONFIG_ITEMS.append(self)
@property @property
@ -81,124 +90,152 @@ class Config(object):
__metaclass__ = MetaConfig __metaclass__ = MetaConfig
width = Key(800, int, "Graph width") style = Key(
DefaultStyle, Style, "Style", "Style holding values injected in css")
height = Key(600, int, "Graph height")
human_readable = Key(
False, bool, "Display values in human readable format",
"(ie: 12.4M)")
logarithmic = Key(False, bool, "Display values in logarithmic scale")
order_min = Key(None, int, "Minimum order of scale, defaults to None")
css = Key( css = Key(
('style.css', 'graph.css'), list, ('style.css', 'graph.css'), list, "Style",
"List of css file", "List of css file",
"It can be an absolute file path or an external link", "It can be an absolute file path or an external link",
str) str)
js = Key(
('https://raw.github.com/Kozea/pygal.js/master/svg.jquery.js',
'https://raw.github.com/Kozea/pygal.js/master/pygal-tooltips.js'),
list, "List of js file",
"It can be a filepath or an external link",
str)
style = Key(DefaultStyle, Style, "Style holding values injected in css")
label_font_size = Key(10, int, "Label font size") ############ Look ############
value_font_size = Key(8, int, "Value font size") title = Key(
None, str, "Look",
"Graph title.", "Leave it to None to disable title.")
tooltip_font_size = Key(20, int, "Tooltip font size") width = Key(
800, int, "Look", "Graph width")
title_font_size = Key(16, int, "Title font size") height = Key(
600, int, "Look", "Graph height")
legend_font_size = Key(14, int, "Legend font size") show_dots = Key(True, bool, "Look", "Set to false to remove dots")
x_label_rotation = Key( stroke = Key(
0, int, "Specify x labels rotation angles", "in degrees") True, bool, "Look",
"Line dots (set it to false to get a scatter plot)")
y_label_rotation = Key( fill = Key(
0, int, "Specify y labels rotation angles", "in degrees") False, bool, "Look", "Fill areas under lines")
show_legend = Key(True, bool, "Set to false to remove legend") show_legend = Key(
True, bool, "Look", "Set to false to remove legend")
legend_at_bottom = Key( legend_at_bottom = Key(
False, bool, "Set to true to position legend at bottom") False, bool, "Look", "Set to true to position legend at bottom")
show_dots = Key(True, bool, "Set to false to remove dots") legend_box_size = Key(
12, int, "Look", "Size of legend boxes")
legend_box_size = Key(12, int, "Size of legend boxes") rounded_bars = Key(
None, int, "Look", "Set this to the desired radius in px")
############ Label ############
x_labels = Key( x_labels = Key(
None, list, None, list, "Label",
"X labels, must have same len than data.", "X labels, must have same len than data.",
"Leave it to None to disable x labels display.", "Leave it to None to disable x labels display.",
str) str)
y_labels = Key( y_labels = Key(
None, list, None, list, "Label",
"You can specify explicit y labels", "You can specify explicit y labels",
"(must be list(int))", int) "Must be a list of numbers", float)
title = Key( x_label_rotation = Key(
None, str, "Graph title.", "Leave it to None to disable title.") 0, int, "Label", "Specify x labels rotation angles", "in degrees")
rounded_bars = Key(False, bool, "Set this to the desired radius in px") y_label_rotation = Key(
0, int, "Label", "Specify y labels rotation angles", "in degrees")
include_x_axis = Key(False, bool, "Always include x axis") ############ Value ############
human_readable = Key(
False, bool, "Value", "Display values in human readable format",
"(ie: 12.4M)")
fill = Key(False, bool, "Fill areas under lines") logarithmic = Key(
False, bool, "Value", "Display values in logarithmic scale")
stroke = Key(
True, bool, "Line dots (set it to false to get a scatter plot)")
interpolate = Key( interpolate = Key(
None, str, "Interpolation, this requires scipy module", None, str, "Value", "Interpolation, this requires scipy module",
"May be any of 'linear', 'nearest', 'zero', 'slinear', 'quadratic," "May be any of 'linear', 'nearest', 'zero', 'slinear', 'quadratic,"
"'cubic', 'krogh', 'barycentric', 'univariate'," "'cubic', 'krogh', 'barycentric', 'univariate',"
"or an integer specifying the order" "or an integer specifying the order"
"of the spline interpolator") "of the spline interpolator")
interpolation_precision = Key( interpolation_precision = Key(
250, int, "Number of interpolated points between two values") 250, int, "Value", "Number of interpolated points between two values")
order_min = Key(
None, int, "Value", "Minimum order of scale, defaults to None")
range = Key( range = Key(
None, list, "Explicitly specify min and max of values", None, list, "Value", "Explicitly specify min and max of values",
"(ie: (0, 100))", int) "(ie: (0, 100))", int)
include_x_axis = Key(
False, bool, "Value", "Always include x axis")
zero = Key( zero = Key(
0, int, "Set the ordinate zero value", "(for filling)") 0, int, "Value",
"Set the ordinate zero value",
"Useful for filling to another base than abscissa")
############ Text ############
no_data_text = Key( no_data_text = Key(
"No data", str, "Text to display when no data is given") "No data", str, "Text", "Text to display when no data is given")
label_font_size = Key(10, int, "Text", "Label font size")
value_font_size = Key(8, int, "Text", "Value font size")
tooltip_font_size = Key(20, int, "Text", "Tooltip font size")
title_font_size = Key(16, int, "Text", "Title font size")
legend_font_size = Key(14, int, "Text", "Legend font size")
print_values = Key( print_values = Key(
True, bool, "Print values when graph is in non interactive mode") True, bool,
"Text", "Print values when graph is in non interactive mode")
print_zeroes = Key( print_zeroes = Key(
False, bool, "Print zeroes when graph is in non interactive mode")
disable_xml_declaration = Key(
False, bool, False, bool,
"Don't write xml declaration and return str instead of string", "Text", "Print zeroes when graph is in non interactive mode")
"usefull for writing output directly in html")
explicit_size = Key(False, bool, "Write width and height attributes")
truncate_legend = Key( truncate_legend = Key(
None, int, "Legend string length truncation threshold (None = auto)") None, int, "Text",
"Legend string length truncation threshold", "None = auto")
truncate_label = Key( truncate_label = Key(
None, int, "Label string length truncation threshold (None = auto)") None, int, "Text",
"Label string length truncation threshold", "None = auto")
############ Misc ############
js = Key(
('https://raw.github.com/Kozea/pygal.js/master/svg.jquery.js',
'https://raw.github.com/Kozea/pygal.js/master/pygal-tooltips.js'),
list, "Misc", "List of js file",
"It can be a filepath or an external link",
str)
disable_xml_declaration = Key(
False, bool, "Misc",
"Don't write xml declaration and return str instead of string",
"usefull for writing output directly in html")
explicit_size = Key(
False, bool, "Misc", "Write width and height attributes")
pretty_print = Key(False, bool, "Pretty print the svg") pretty_print = Key(
False, bool, "Misc", "Pretty print the svg")
strict = Key( strict = Key(
False, bool, "If True don't try to adapt / filter wrong values") False, bool, "Misc",
"If True don't try to adapt / filter wrong values")
def __init__(self, **kwargs): def __init__(self, **kwargs):
"""Can be instanciated with config kwargs""" """Can be instanciated with config kwargs"""

4
pygal/graph/bar.py

@ -97,8 +97,8 @@ class Bar(Graph):
bar, 'rect', bar, 'rect',
x=x, x=x,
y=y, y=y,
rx=self.rounded_bars * 1, rx=self.rounded_bars * 1 if self.rounded_bars else 0,
ry=self.rounded_bars * 1, ry=self.rounded_bars * 1 if self.rounded_bars else 0,
width=bar_inner_width, width=bar_inner_width,
height=height, height=height,
class_='rect reactive tooltip-trigger') class_='rect reactive tooltip-trigger')

2
pygal/graph/line.py

@ -43,7 +43,7 @@ class Line(Graph):
for serie in self.series for serie in self.series
for val in (serie.interpolated for val in (serie.interpolated
if self.interpolate else serie.points) if self.interpolate else serie.points)
if val[1] is not None and (not self.logarithmic or val[1] > 0)] if val[1] is not None]
def _fill(self, values): def _fill(self, values):
"""Add extra values to fill the line""" """Add extra values to fill the line"""

3
pygal/util.py

@ -299,10 +299,11 @@ def prepare_values(raw, config, cls):
if fun in adapters: if fun in adapters:
adapters.remove(fun) adapters.remove(fun)
adapters = [not_zero, positive] + adapters adapters = [not_zero, positive] + adapters
adapter = reduce(compose, adapters) adapter = reduce(compose, adapters) if not config.strict else ident
series = [] series = []
width = max([len(values) for _, values in raw] + width = max([len(values) for _, values in raw] +
[len(config.x_labels or [])]) [len(config.x_labels or [])])
for title, raw_values in raw: for title, raw_values in raw:
metadata = {} metadata = {}
values = [] values = []

Loading…
Cancel
Save