Hi i was trying to couple a flask application with a react front-end. The project is mainly focused on data science using libraries like pandas and matplotlib. I was trying to return a HTML equivalent of a matplotlib fig and was trying to render it in the front end.
Since it is pure HTML and not JSX it throws an error when react tries to render it. The HTML works perfectly when run in a purely html setup. I tried multiple libraries and have failed to render the fig in a react base setup.
Another approach i tried was creating a separate element that renders the HTML separately using the document model but since the figure comes in later, i feel the dom doesn't re render the whole page (I may be wrong here, but tried for long and nothing worked).
The HTML I am Trying to render (This comes in as a Post request, Thats why i feel the re rendering does't happen, as it isn't a react component when an element is created using the document model):
<style>
</style>
<div id="fig_el1692823804362488404764011855"></div>
<script>
function 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);
}
if(typeof(mpld3) !== "undefined" && mpld3._mpld3IsLoaded){
// already loaded: just create the figure
!function(mpld3){
mpld3.draw_figure("fig_el1692823804362488404764011855", {"width": 640.0, "height": 480.0, "axes": [{"bbox": [0.125,
0.10999999999999999, 0.775, 0.77], "xlim": [-0.2, 4.2], "ylim": [0.8, 5.2], "xdomain": [-0.2, 4.2], "ydomain": [0.8, 5.2],
"xscale": "linear", "yscale": "linear", "axes": [{"position": "bottom", "nticks": 11, "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": "el169282380436246664", "lines": [{"data": "data01", "xindex": 0, "yindex": 1, "coordinates": "data", "id": "el169282380435913992", "color": "#1F77B4", "linewidth": 1.5, "dasharray":
"none", "alpha": 1, "zorder": 2, "drawstyle": "default"}], "paths": [], "markers": [], "texts": [], "collections": [], "images": [], "sharex": [], "sharey": []}], "data": {"data01": [[0.0, 3.0], [1.0, 1.0], [2.0, 4.0], [3.0, 1.0], [4.0, 5.0]]}, "id": "el169282380436248840", "plugins": [{"type": "reset"}, {"type": "zoom", "button": true, "enabled": false}, {"type": "boxzoom", "button": true, "enabled": false}]});
}(mpld3);
}else if(typeof define === "function" && define.amd){
// require.js is available: use it to load d3/mpld3
require.config({paths: {d3: "https://mpld3.github.io/js/d3.v3.min"}});
require(["d3"], function(d3){
window.d3 = d3;
mpld3_load_lib("https://mpld3.github.io/js/mpld3.v0.3.js", function(){
mpld3.draw_figure("fig_el1692823804362488404764011855", {"width": 640.0, "height": 480.0, "axes": [{"bbox": [0.125, 0.10999999999999999, 0.775, 0.77], "xlim": [-0.2, 4.2], "ylim": [0.8, 5.2], "xdomain": [-0.2, 4.2], "ydomain": [0.8, 5.2], "xscale": "linear", "yscale": "linear", "axes": [{"position": "bottom", "nticks": 11, "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": "el169282380436246664", "lines": [{"data": "data01", "xindex": 0, "yindex": 1, "coordinates": "data", "id": "el169282380435913992", "color": "#1F77B4", "linewidth": 1.5, "dasharray": "none", "alpha": 1, "zorder": 2, "drawstyle": "default"}], "paths": [], "markers": [], "texts": [], "collections": [], "images": [], "sharex": [], "sharey": []}], "data": {"data01": [[0.0, 3.0], [1.0, 1.0], [2.0, 4.0], [3.0, 1.0], [4.0, 5.0]]}, "id": "el169282380436248840", "plugins": [{"type": "reset"}, {"type": "zoom", "button": true, "enabled": false}, {"type":
"boxzoom", "button": true, "enabled": false}]});
});
});
}else{
// require.js not available: dynamically load d3 & mpld3
mpld3_load_lib("https://mpld3.github.io/js/d3.v3.min.js", function(){
mpld3_load_lib("https://mpld3.github.io/js/mpld3.v0.3.js", function(){
mpld3.draw_figure("fig_el1692823804362488404764011855", {"width": 640.0, "height": 480.0, "axes": [{"bbox": [0.125, 0.10999999999999999, 0.775, 0.77], "xlim": [-0.2, 4.2], "ylim": [0.8, 5.2], "xdomain": [-0.2, 4.2], "ydomain": [0.8, 5.2], "xscale": "linear", "yscale": "linear", "axes": [{"position": "bottom", "nticks": 11, "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": "el169282380436246664", "lines": [{"data": "data01", "xindex": 0, "yindex": 1, "coordinates": "data", "id": "el169282380435913992", "color": "#1F77B4", "linewidth": 1.5, "dasharray": "none", "alpha": 1, "zorder": 2, "drawstyle": "default"}], "paths": [], "markers": [], "texts": [], "collections": [], "images": [], "sharex": [], "sharey": []}], "data": {"data01": [[0.0, 3.0], [1.0, 1.0], [2.0, 4.0], [3.0, 1.0], [4.0, 5.0]]}, "id": "el169282380436248840", "plugins": [{"type": "reset"}, {"type": "zoom", "button": true, "enabled": false}, {"type": "boxzoom", "button": true, "enabled": false}]});
})
});
}
</script>
The approach I was trying as I couldn't find a library good library enough to accurately convert my html to jsx (If there is such a React library that does convert the code, if anyone could convert the html above and check that would be great):
var App = (props) => {
const [dataFrameComponent, setDataFrameComponent] = React.useState("");
useEffect(() => {
const element = document.getElementById("dataframe");
if(typeof(element) != 'undefined' && element!= null){
document.getElementById('dataframe').style.width = "500"
document.getElementById('dataframe').style.height = "500"
document.getElementById('dataframe').innerHTML = dataFrameComponent
}
else{
const script = document.createElement("div");
script.id = 'dataframe'
script.style.height = '200'
script.style.width = '200'
const root = document.getElementById('root')
root.appendChild(script);
}
})
const [number, setNumber] = React.useState(0);
const handleSubmit=(event) => {
event.preventDefault();
let formData = new FormData(); //formdata object
formData.append('number', number);
console.log(formData);
console.log(formData.keys())
fetch('http://127.0.0.1:5000/dataframe',{
method: 'POST',
body: formData
})
.then((data)=> data.text()).then((data) => setDataFrameComponent(data))
}
return (
<div className="App">
<header className="App-header">
<form onSubmit={handleSubmit}>
<label>Enter the number of Elements: </label>
<input type="text" name= "number" onChange={(event) => {setNumber(event.target.value)} } />
<input type="submit" value="Submit" />
</form>
</header>
</div>
);
}
export default App;
The graph that I would like to render dynamically is this. https://codepen.io/sherwinfarrell/pen/vYOPBVo
WHich is the same as the html code I have included here.
P.S. use these 2 methods with caution.
1- you can do it without a library by using createContextualFragment:
import React from 'react';
const html = `
your html here
`;
class App extends React.Component {
componentDidMount() {
const wrapper = document.querySelector('#d3_code');
const range = document.createRange();
range.setStart(wrapper, 0);
wrapper.appendChild(
range.createContextualFragment(html)
);
}
render() {
return (
<div>React Snippet</div>
)
}
}
export default App;
2- the second method is to use dangerously-set-html-content library:
import React from 'react';
import InnerHTML from 'dangerously-set-html-content'
const html = `
your html here
`;
class App extends React.Component {
render() {
return (
<div>
<InnerHTML html={html} />
</div>
)
}
}
export default App;