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