import warnings import json import random from .base import Renderer from ..exporter import Exporter class VegaRenderer(Renderer): def open_figure(self, fig, props): self.props = props self.figwidth = int(props['figwidth'] * props['dpi']) self.figheight = int(props['figheight'] * props['dpi']) self.data = [] self.scales = [] self.axes = [] self.marks = [] def open_axes(self, ax, props): if len(self.axes) > 0: warnings.warn("multiple axes not yet supported") self.axes = [dict(type="x", scale="x", ticks=10), dict(type="y", scale="y", ticks=10)] self.scales = [dict(name="x", domain=props['xlim'], type="linear", range="width", ), dict(name="y", domain=props['ylim'], type="linear", range="height", ),] def draw_line(self, data, coordinates, style, label, mplobj=None): if coordinates != 'data': warnings.warn("Only data coordinates supported. Skipping this") dataname = "table{0:03d}".format(len(self.data) + 1) # TODO: respect the other style settings self.data.append({'name': dataname, 'values': [dict(x=d[0], y=d[1]) for d in data]}) self.marks.append({'type': 'line', 'from': {'data': dataname}, 'properties': { "enter": { "interpolate": {"value": "monotone"}, "x": {"scale": "x", "field": "data.x"}, "y": {"scale": "y", "field": "data.y"}, "stroke": {"value": style['color']}, "strokeOpacity": {"value": style['alpha']}, "strokeWidth": {"value": style['linewidth']}, } } }) def draw_markers(self, data, coordinates, style, label, mplobj=None): if coordinates != 'data': warnings.warn("Only data coordinates supported. Skipping this") dataname = "table{0:03d}".format(len(self.data) + 1) # TODO: respect the other style settings self.data.append({'name': dataname, 'values': [dict(x=d[0], y=d[1]) for d in data]}) self.marks.append({'type': 'symbol', 'from': {'data': dataname}, 'properties': { "enter": { "interpolate": {"value": "monotone"}, "x": {"scale": "x", "field": "data.x"}, "y": {"scale": "y", "field": "data.y"}, "fill": {"value": style['facecolor']}, "fillOpacity": {"value": style['alpha']}, "stroke": {"value": style['edgecolor']}, "strokeOpacity": {"value": style['alpha']}, "strokeWidth": {"value": style['edgewidth']}, } } }) def draw_text(self, text, position, coordinates, style, text_type=None, mplobj=None): if text_type == 'xlabel': self.axes[0]['title'] = text elif text_type == 'ylabel': self.axes[1]['title'] = text class VegaHTML(object): def __init__(self, renderer): self.specification = dict(width=renderer.figwidth, height=renderer.figheight, data=renderer.data, scales=renderer.scales, axes=renderer.axes, marks=renderer.marks) def html(self): """Build the HTML representation for IPython.""" id = random.randint(0, 2 ** 16) html = '
' % id html += '\n' return html def _repr_html_(self): return self.html() def fig_to_vega(fig, notebook=False): """Convert a matplotlib figure to vega dictionary if notebook=True, then return an object which will display in a notebook otherwise, return an HTML string. """ renderer = VegaRenderer() Exporter(renderer).run(fig) vega_html = VegaHTML(renderer) if notebook: return vega_html else: return vega_html.html() VEGA_TEMPLATE = """ ( function() { var _do_plot = function() { if ( (typeof vg == 'undefined') && (typeof IPython != 'undefined')) { $([IPython.events]).on("vega_loaded.vincent", _do_plot); return; } vg.parse.spec(%s, function(chart) { chart({el: "#vis%d"}).update(); }); }; _do_plot(); })(); """