Plot is not defined when using it in eval()

63 Views Asked by At

I have a notebook project that uses React and ObservablePlot and react-monaco
there's an IDE on my App that :

  1. takes the User Code ( Observable Code ) like this Plot.lineY(props.data, { x: "Date", y: "Close" })

  2. then I pass that code as a prop to my Component

  3. then I pass that prop string code to the eval

the error that I faced with

Plot is not defined ReferenceError: Plot is not defined


What I want:

is to Compile that code with eval and put the return value to marks of the Observable plot.

OR

somehow convert user string code to JS readable code


Plot is an npm package so i imported it from its package like below

Here is my Code:

import React, { useEffect, useState, useRef } from "react";
import * as Plot from "@observablehq/plot";
import * as d3 from "d3";

const PlotChart = (props) => {
  const containerRef = useRef();
  const [data, setData] = useState();

  useEffect(() => {
    d3.csv("/gistemp.csv", d3.autoType).then(setData);
  }, []);

  useEffect(() => {
    if (data === undefined) return;
    const plot = Plot.plot({
      marks: [eval(props.plot)],
    });
    containerRef.current.append(plot);
    return () => plot?.remove();
  }, [data]);

  return <div ref={containerRef} />;
};

export default PlotChart;

I searched a lot and I got no answer for this Problem. Any guide will be appreciate

1

There are 1 best solutions below

0
Hamid Kamyab On BEST ANSWER

Hey guys for anyone who might face with same problem.

It looks like the eval can't use the imported Package; instead, you can store it in a variable that is declared in the same scope that the eval gets used. then use that variable name in the string code that you want to pass into eval.

const PlotChart = (props) => {
 const containerRef = useRef();
 const [data, setData] = useState();
 
 const compileCode = () => {
    // store package in a variable
    const plotly = Plot;
    return eval(props.plot);
  };

  useEffect(() => {
    compileCode();
    setData(props.data);
  }, []);

  useEffect(() => {
    if (data === undefined) return;
    const plot = Plot.plot({
      marks: [compileCode()],
    });
    containerRef.current.append(plot);
    return () => plot?.remove();
  }, [data]);

  return <div ref={containerRef} />;
};

export default PlotChart;

now if you pass a string like below your eval will work fine.

plotly.lineY(props.data, {x: 'Date', y: 'Close'})