How to export matplotlib plots as iframes - matplotlib

I want to generate some plots with Matplotlib and then generate iframes to embed in a Google Sites site.
I would like that if the image change, the change be reflected on my Google Site.
I have tried:
from matplotlib.pyplot import figure
import mpld3
fig = figure()
ax = fig.gca()
ax.plot([1,5,3,4])
hola= mpld3.save_html(fig,'myfig.html',template_type='simple')
If I open myfig.html on the browser and go to View Page Source, I can see
<script type="text/javascript" src="https://mpld3.github.io/js/d3.v3.min.js"></script>
<script type="text/javascript" src="https://mpld3.github.io/js/mpld3.v0.3.js"></script>
<style>
</style>
<div id="fig_el190911208844747686822225975"></div>
<script type="text/javascript">
!function(mpld3){
mpld3.draw_figure("fig_el190911208844747686822225975", {"width": 432.0, "height": 288.0, "axes": [{"bbox": [0.125, 0.125, 0.775, 0.755], "xlim": [-0.15000000000000002, 3.15], "ylim": [0.8, 5.2], "xdomain": [-0.15000000000000002, 3.15], "ydomain": [0.8, 5.2], "xscale": "linear", "yscale": "linear", "axes": [{"position": "bottom", "nticks": 9, "tickvalues": null, "tickformat": null, "scale": "linear", "fontsize": 10.0, "grid": {"gridOn": false}, "visible": true}, {"position": "left", "nticks": 11, "tickvalues": null, "tickformat": null, "scale": "linear", "fontsize": 10.0, "grid": {"gridOn": false}, "visible": true}], "axesbg": "#FFFFFF", "axesbgalpha": null, "zoomable": true, "id": "el19091120884476504", "lines": [{"data": "data01", "xindex": 0, "yindex": 1, "coordinates": "data", "id": "el19091120885398384", "color": "#1F77B4", "linewidth": 1.5, "dasharray": "none", "alpha": 1, "zorder": 2, "drawstyle": "default"}], "paths": [], "markers": [], "texts": [], "collections": [], "images": [], "sharex": [], "sharey": []}], "data": {"data01": [[0.0, 1.0], [1.0, 5.0], [2.0, 3.0], [3.0, 4.0]]}, "id": "el19091120884474768", "plugins": [{"type": "reset"}, {"type": "zoom", "button": true, "enabled": false}, {"type": "boxzoom", "button": true, "enabled": false}]});
}(mpld3);
So If I copy this code in my Google Sites I can see the picture.
But I need that if I save a new picture in myfig.html that I can see those changes in the site.

Related

How to display multiple charts with varying x-scales side by side in Vega

I have a set of charts with the same y-scale but varying x-scales. I am using hconcat to display them side by side. In order to conserve space and avoid repetition, I have disabled the y-axis for all but the first chart. However, this is causing the title of the first chart to offset:
This is a link to a Vega Editor.
As the blue circle indicates, the two titles, "Chain" and "Mini Invaders," are not in line. Is there a way to fix this?
I have tried to express these charts using facet but as far as I can tell, facets do not permit varying x-scales. However, please do let me know if this is somehow possible with facets.
You need labelBound: true in your spec.
Editor
{
"config": {
"view": {
"continuousWidth": 400,
"continuousHeight": 300,
"stroke": "#000000",
"strokeOpacity": 1,
"strokeWidth": 2
},
"axis": {"labelFontSize": 24, "titleFontSize": 24, "labelBound":true},
"legend": {"labelFontSize": 24, "labelLimit": 0, "titleFontSize": 32},
"title": {"baseline": "bottom", "fontSize": 24}
},
"hconcat": [
{
"layer": [
{
"mark": {"type": "area", "clip": true, "opacity": 0.2},
"encoding": {
"color": {
"field": "Variations",
"legend": {
"orient": "top",
"symbolOpacity": 1,
"symbolSize": 200,
"symbolStrokeWidth": 3,
"symbolType": "stroke"
},
"scale": {
"domain": ["Original Algorithm"],
"range": [
"#e41a1c",
"#377eb8",
"#4daf4a",
"#984ea3",
"#a65628",
"#646464"
]
},
"type": "nominal"
},
"x": {"field": "step", "type": "quantitative"},
"y": {
"axis": {"labels": true, "tickCount": 5, "title": null},
"field": "lower",
"type": "quantitative"
},
"y2": {"field": "upper"}
}
},
{
"mark": {"type": "line", "clip": true},
"encoding": {
"color": {"field": "Variations", "type": "nominal"},
"x": {"field": "step", "type": "quantitative"},
"y": {
"field": "regret",
"scale": {"domain": [0, 1]},
"type": "quantitative"
}
}
}
],
"height": 200,
"title": "Chain",
"transform": [{"filter": "(datum.domain === 'Chain')"}],
"width": 200
},
{
"layer": [
{
"mark": {"type": "area", "clip": true, "opacity": 0.2},
"encoding": {
"color": {
"field": "Variations",
"legend": {
"orient": "top",
"symbolOpacity": 1,
"symbolSize": 200,
"symbolStrokeWidth": 3,
"symbolType": "stroke"
},
"scale": {
"domain": ["Original Algorithm"],
"range": [
"#e41a1c",
"#377eb8",
"#4daf4a",
"#984ea3",
"#a65628",
"#646464"
]
},
"type": "nominal"
},
"x": {"field": "step", "type": "quantitative"},
"y": {
"axis": {"labels": false, "tickCount": 5, "title": null},
"field": "lower",
"type": "quantitative"
},
"y2": {"field": "upper"}
}
},
{
"mark": {"type": "line", "clip": true},
"encoding": {
"color": {"field": "Variations", "type": "nominal"},
"x": {"field": "step", "type": "quantitative"},
"y": {
"field": "regret",
"scale": {"domain": [0, 1]},
"type": "quantitative"
}
}
}
],
"height": 200,
"title": "Mini Invaders",
"transform": [{"filter": "(datum.domain === 'Mini Invaders')"}],
"width": 200
}

Rendering mpld3 JSON chart in React

Good day.
I just recently came across mpld3 and I am trying to see if it will be the solution to my issue.
I want to create Matplotlib charts in Python, save them as JSON objects to a database, and then render them in my React webpage.
So far I have created a plot in Python, using Matplotlib and converted it to a JSON object in a dictionary:
fig = plt.gcf()
mpld3.display(fig)
fig_to_dict = mpld3.fig_to_dict(fig)
Now I can save the dictionary to a file.
My question is: Can I then render this JSON chart in my React project? And if so, how do I do that?
Another thing is - I cannot use D3 in the front-end, I need to do all my "chart making" in the back-end.
Thank you for any and all assistance!
This is not a perfect answer, but I seemed to be solving a similar problem and I appear to have got it working so am sharing my code as is. Hopefully it will prove useful to someone.
This is my react component ('matPlotLibFig.js') that renders a simple figure
import React from 'react'
import mpld3_load_lib from "./mpld3_load_lib";
import mpld3 from 'mpld3'
import _json from "./plot_b.json"
const MatPlotLibFig = () => {
const fig_name = "fig_el427345810798888193429725"
return <div>
<script>
mpld3_load_lib("https://d3js.org/d3.v5.js", function () {
mpld3_load_lib("https://mpld3.github.io/js/mpld3.v0.5.8.js", function () {
mpld3.remove_figure(fig_name)
mpld3.draw_figure(fig_name, _json);
})
});
</script>
<div id={fig_name}></div>
</div>
}
export default MatPlotLibFig
plot_b.json:
{
"width": 640.0,
"height": 480.0,
"axes": [
{
"bbox": [0.125, 0.11, 0.775, 0.77],
"xlim": [-0.5, 10],
"ylim": [0, 10],
"xdomain": [-0.2, 10],
"ydomain": [0.0, 10],
"xscale": "linear",
"yscale": "linear",
"axes": [
{
"position": "bottom",
"nticks": 11,
"tickvalues": null,
"tickformat_formatter": "",
"tickformat": null,
"scale": "linear",
"fontsize": 10.0,
"grid": {
"gridOn": false
},
"visible": true
},
{
"position": "left",
"nticks": 11,
"tickvalues": null,
"tickformat_formatter": "",
"tickformat": null,
"scale": "linear",
"fontsize": 10.0,
"grid": {
"gridOn": false
},
"visible": true
}
],
"axesbg": "#FFFFFF",
"axesbgalpha": null,
"zoomable": true,
"id": "el91906139874005984112",
"lines": [
{
"data": "data01",
"xindex": 0,
"yindex": 1,
"coordinates": "data",
"id": "el91906139873968544448",
"color": "#000000",
"linewidth": 1.5,
"dasharray": "none",
"alpha": 1,
"zorder": 2,
"drawstyle": "default"
}
],
"paths": [],
"markers": [
{
"data": "data01",
"xindex": 0,
"yindex": 1,
"coordinates": "data",
"id": "el91906139873968544448pts",
"facecolor": "#000000",
"edgecolor": "#FFFFFF",
"edgewidth": 5,
"alpha": 1,
"zorder": 2,
"markerpath": [
[
[
-10.0,
10.0
],
[
10.0,
10.0
],
[
10.0,
-10.0
],
[
-10.0,
-10.0
]
],
[
"M",
"L",
"L",
"L",
"Z"
]
]
}
],
"texts": [],
"collections": [],
"images": [],
"sharex": [],
"sharey": []
}
],
"data": {
"data01": [
[
0.0,
6.0
],
[
1.0,
2.0
],
[
2.0,
8.0
],
[
3.0,
3.0
],
[
4.0,
0.0
],
[
5.0,
7.0
]
]
},
"id": "el91906139874196422128",
"plugins": [
{
"type": "reset"
},
{
"type": "zoom",
"button": true,
"enabled": false
},
{
"type": "boxzoom",
"button": true,
"enabled": false
}
]
}
mpld3_load_lib.js:
const mpld3_load_lib = (url, callback) => {
var s = document.createElement('script');
s.src = url;
s.async = true;
s.onreadystatechange = s.onload = callback;
s.onerror = function () { console.warn("failed to load library " + url); };
document.getElementsByTagName("head")[0].appendChild(s);
}
export default mpld3_load_lib
Which renders a dynamic plot that looks like

Vega-Lite: How to use slider value in transform calculation

How do I use the value of a slider in the transform?
This example from vega online editor plots a sine and cosine wave.
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Plots two functions using a generated sequence.",
"width": 300,
"height": 150,
"data": {
"sequence": {
"start": 0,
"stop": 12.7,
"step": 0.1,
"as": "x"
}
},
"transform": [
{
"calculate": "sin(datum.x)",
"as": "sin(x)"
},
{
"calculate": "cos(datum.x)",
"as": "cos(x)"
},
{
"fold": ["sin(x)", "cos(x)"]
}
],
"mark": "line",
"encoding": {
"x": {
"type": "quantitative",
"field": "x"
},
"y": {
"field": "value",
"type": "quantitative"
},
"color": {
"field": "key",
"type": "nominal",
"title": null
}
}
}
I would like to add two sliders and use their values in the calculation. I can define sliders using:
"selection" : {
"amp" : {
"type" : "single",
"fields" : ["sin", "cos"],
"bind": {
"sin": { "input" : "range", "min": 0.0, "max": 10.0, "step": 0.1},
"cos": { "input" : "range", "min": 0.0, "max": 10.0, "step": 0.1}
}
}
},
How do I access the slider values to use in the calculations? Something like
{
"calculate": "amp.sin * sin(datum.x)",
"as": "sin(x)"
},
You can do this in exactly the way you wrote in your question. Additionally, adding an initial value will make the selections valid before you interact with them.
Here is a full example (vega editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Plots two functions using a generated sequence.",
"width": 300,
"height": 150,
"data": {"sequence": {"start": 0, "stop": 12.7, "step": 0.1, "as": "x"}},
"transform": [
{"calculate": "amp.sin * sin(datum.x)", "as": "sin(x)"},
{"calculate": "amp.cos * cos(datum.x)", "as": "cos(x)"},
{"fold": ["sin(x)", "cos(x)"]}
],
"mark": "line",
"encoding": {
"x": {"type": "quantitative", "field": "x"},
"y": {"field": "value", "type": "quantitative"},
"color": {"field": "key", "type": "nominal", "title": null}
},
"selection": {
"amp": {
"type": "single",
"fields": ["sin", "cos"],
"init": {"sin": 1, "cos": 1},
"bind": {
"sin": {"input": "range", "min": 0, "max": 10, "step": 0.1},
"cos": {"input": "range", "min": 0, "max": 10, "step": 0.1}
}
}
}
}

How to show Vega visualizations in Google Colab

I can use Altair to show Vega-Lite visualizations in Google Colab. But is there a way to show plain Vega visualizations?
I tried ipyvega in Google Colab. But when I run their example in Google Colab, then nothing shows up, and there is no error.
You can display a vega chart in Colab using the altair.vega.Vega class, once you have enabled the Colab renderer.
Here is an example:
from urllib import request
import json
with request.urlopen("https://vega.github.io/vega/examples/bar-chart.vg.json") as f:
spec = json.load(f)
from altair import vega
vega.renderers.enable('colab')
vega.Vega(spec)
You can use vega magic from altair. But it needs some setup.
# setup
!pip -q install -U PyYAML
from altair.vega import Vega
Vega.renderers.enable('colab')
%load_ext altair
Then use the %%vega magic.
%%vega
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 400,
"height": 200,
"data": [
{
"name": "table",
"values": [
{"category": "A", "amount": 28},
{"category": "B", "amount": 55},
{"category": "C", "amount": 43},
{"category": "D", "amount": 91},
]
}
],
"scales": [
{
"name": "xscale",
"type": "band",
"domain": {"data": "table", "field": "category"},
"range": "width",
},
{
"name": "yscale",
"domain": {"data": "table", "field": "amount"},
"range": "height"
}
],
"axes": [
{ "orient": "bottom", "scale": "xscale" },
{ "orient": "left" , "scale": "yscale" }
],
"marks": [
{
"type": "rect",
"from": {"data":"table"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "category"},
"width": {"scale": "xscale", "band": 1},
"y": {"scale": "yscale", "field": "amount"},
"y2": {"scale": "yscale", "value": 0}
},
}
}
]
}
The simple bar chart is then displayed.
If the vega spec is already in a dict, using Vega(spec) is easier.
from requests import get
url = 'https://vega.github.io/vega/examples/bar-chart.vg.json'
spec = get(url).json()
Vega(spec)

vega won't update until the mouse has brushed over the div containing the chart

I ran into a subtle vega update behavior that I hope to get your help on
--- when I use the view API to update the signal for a visual element (e.g., a brush), the UI doesn't appear to update until I move my mouse over to the div --- in the notebook, this can create a jarring experience. Is there any way to "eagerly" perform the update?
You can run the following JSON and run the script below in the console
to reproduce the effect that I am talking about. Thanks!
Have the following spec in Vega Editor
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Midas Generated Visualization of dataframe STATE_distribution",
"selection": {
"zoom": {
"type": "interval",
"bind": "scales",
"translate": "[mousedown[!event.shiftKey], window:mouseup] > window:mousemove!",
"zoom": "wheel!"
},
"brush": {
"type": "interval",
"resolve": "union",
"on": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
"translate": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
"zoom": null,
"encodings": ["x"]
}
},
"data": {
"values": [
{"STATE": "AK", "count": 2, "is_overview": true},
{"STATE": "RI", "count": 4, "is_overview": true},
{"STATE": "WA", "count": 75, "is_overview": true},
{"STATE": "WI", "count": 120, "is_overview": true},
{"STATE": "WV", "count": 155, "is_overview": true},
{"STATE": "WY", "count": 43, "is_overview": true}
]
},
"mark": "bar",
"encoding": {
"x": {"field": "STATE", "type": "ordinal"},
"y": {"field": "count", "type": "quantitative", "stack": null},
"color": {
"field": "is_overview",
"type": "nominal",
"scale": {"range": ["#003E6B", "#9FB3C8"], "domain": [false, true]},
"legend": null
},
"opacity": {"value": 0.5}
},
"config": {}
}
Then paste VEGA_DEBUG.view.signal("brush_x", [10, 100]) in the console. You will see that the brush will not update until you move your mouse over to the div that contains the chart.
After updating a signal, call runAsync() to invoke an update. The behavior that you see where the view updates when you hover over it comes from the fact that Vega listens to hover events and invokes an updates.