2

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.

  • https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml Did you try this? –  Mar 30 '20 at 05:10
  • Yeah that was the first thing i tried. I am trying to render d3 code. I do not need any dependencies. https://codepen.io/sherwinfarrell/pen/vYOPBVo – Sherwin Mascarenhas Mar 31 '20 at 09:48

2 Answers2

2

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;
0

You need to create a new React element, set its HTML to your HTML code and render it to the DOM using dangerouslySetInnerHTML.

Example:

function createMarkup() {
  return {__html: ` // start of a multi-line string
<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>
`}; // end of a multi-line string
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}
  • Hey did this work for you? This was one of the first things i tried. Will try it again but dangerously set inner html was throwing an error somewhere in the html. It couldn't parse it fully. Did you get an output of a graph when doing this? – Sherwin Mascarenhas Mar 31 '20 at 09:38
  • I will try later and let you know. –  Mar 31 '20 at 12:56