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(); })(); """