123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- """
- pygal Tag
- ---------
- This implements a Liquid-style pygal tag for Pelican. JSON is used for the data,
- and you can pass a bunch of pygal's 'config' items through as-is
- [1] http://www.pygal.org/
- Syntax
- ------
- {% pygal
- {
- <graph data>
- }
- %}
- Examples
- --------
- {%
- pygal {
- "type": "bar",
- "title": "Test Chart",
- "x-labels" : {"from": 2002, "to": 2013},
- "data" : [
- {"title": "Firefox",
- "values": [null, null, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]},
- {"title": "Chrome",
- "values": [null, null, null, null, null, null, 0, 3.9, 10.8, 23.8, 35.3]},
- {"title": "IE",
- "values": [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]},
- {"title": "Others",
- "values": [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]}
- ]
- }
- %}
- {%
- pygal {
- "type": "pie",
- "half_pie": true,
- "title": "Browser usage in February 2012 (in %)",
- "data" : [
- {"title": "IE",
- "values": 19.5},
- {"title": "Firefox",
- "values": 36.6},
- {"title": "Chrome",
- "values": 36.3},
- {"title": "Safari",
- "values": 4.5},
- {"title": "Opera",
- "values": 2.3}
- ]
- }
- %}
- {%
- pygal {
- "type": "pie",
- "config": {
- "show_legend": false,
- "print_values": true,
- "show_y_labels": true
- },
- "title": "Browser usage in February 2012 (in %)",
- "data" : [
- {"title": "IE",
- "values": 19.5},
- {"title": "Firefox",
- "values": 36.6},
- {"title": "Chrome",
- "values": 36.3},
- {"title": "Safari",
- "values": 4.5},
- {"title": "Opera",
- "values": 2.3}
- ]
- }
- %}
- ...
- Output
- ------
- <<div class="pygal" style="text-align: center;"><embed type="image/svg+xml" src=SVG_MARKUP_EMBEDDED style="max-width:1000px"/></div>
- """
- import base64
- import re
- from json import loads
- from .mdx_liquid_tags import LiquidTags
- SYNTAX = '{% pygal (data) %}'
- DOT_BLOCK_RE = re.compile(r'^\s*\{\s*(?P<code>.*\})\s*\}$', re.MULTILINE | re.DOTALL)
- def run_pygal(data, options=[], format='svg'):
- """ Runs pygal programs and returns image data
- """
- import pygal
- chart_title = data.get('title', None)
- chart_type = data.get('type', '').lower()
- # Config options are pretty much proxied straight through from the JSON dict into the object
- config = pygal.Config()
- config_dict = data.get('config', {})
- for key in config_dict.keys():
- setattr(config, key, config_dict[key])
- if chart_type == 'bar':
- chart = pygal.HorizontalBar(config) if data.get('horizontal', False) else pygal.Bar(config)
- elif chart_type == 'line':
- chart = pygal.Line(config)
- elif chart_type == 'pie':
- ir=data.get('inner_radius', 0.0)
- hp=data.get('half_pie', False)
- chart = pygal.Pie(config, inner_radius=ir, half_pie=hp)
- else:
- print('undefined or unknown chart type')
- if chart is not None:
- chart.title = data.get('title', None)
- # Do labels (if present)
- label_data = data.get('x-labels', None)
- if isinstance(label_data, list):
- # use list
- chart.x_labels = label_data
- elif isinstance(label_data, dict):
- # use a range
- range_from = label_data.get('from', 0)
- range_to = label_data.get('to', 0)
- chart.x_labels = map(str, range(range_from, range_to))
- # insert data
- for data_set in data.get('data', []):
- title = data_set.get('title', None)
- values = data_set.get('values', None)
- chart.add(title, values)
- # now render
- result = chart.render_data_uri()
- else:
- result = None
- return result
- @LiquidTags.register('pygal')
- def pygal_parser(preprocessor, tag, markup):
- """ Simple pygal parser """
- # Find JSON payload
- data = loads(markup)
- if tag == 'pygal' and data is not None:
- # Run generation of chart
- output = run_pygal(data)
- # Return embedded SVG image
- return '<div class="pygal" style="text-align: center;"><embed type="image/svg+xml" src=%s style="max-width:1000px"/></div>' % output
- else:
- raise ValueError('Error processing input. \nExpected syntax: {0}'.format(SYNTAX))
- #----------------------------------------------------------------------
- # This import allows image tag to be a Pelican plugin
- from .liquid_tags import register
|