【问题标题】:How to translate an Observable Notebook example into javascript?如何将 Observable Notebook 示例翻译成 javascript?
【发布时间】:2021-08-11 11:46:25
【问题描述】:

我正在尝试将this observable notebook example 翻译或转换为纯 javascript 和 d3,以便我在网站中使用它。

我试图跟随this answer right here 实现类似的目标。 但它对我不起作用,我收到一条错误消息“Unexpected value NaN parsing cy attribute.”

这是我到目前为止所做的:

<!DOCTYPE HTML>
<meta charset="UTF-8">
<html>
<body>

<head>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.6.2/d3.min.js"></script>
<script src="https://unpkg.com/simple-statistics@7.7.0/dist/simple-statistics.min.js"></script>

</head>

<svg width="300" height="300" />

<script>

const width = 600;
const height = 600;

const margin = ({top: 20, right: 40, bottom: 30, left: 40});

const data = [608.781, 569.67, 689.556, 747.541, 618.134, 612.182, 680.203, 607.766, 726.232, 605.38, 518.655, 589.226, 740.447, 588.375, 666.83, 531.384, 710.272, 633.417, 751.669, 619.06];

const erfinv = () => {
  const a = 8 * (Math.PI - 3) / (3 * Math.PI * (4 - Math.PI));
  return x => {
    const b = Math.log(1 - x * x);
    const c = b / 2 + (2 / (Math.PI * a));
    return Math.sign(x) * Math.sqrt(Math.sqrt((c * c) - b / a) - c);
  };
}    
    
const qnorm = p => Math.SQRT2 * erfinv(2 * p - 1);
const qy = Float64Array.from(data).sort(d3.ascending);
const n = qy.length;
const a = n <= 10 ? 5 / 8 : 0.5;
const z = i => qnorm((i + a) / (n + 1 - 2 * a));

const xAxis = g => g
    .attr("transform", `translate(0,${height - margin.bottom + 6})`)
    .call(d3.axisBottom(x.copy().interpolate(d3.interpolateRound)).ticks(null, "+f"))
    .call(g => g.select(".domain").remove())
    .call(g => g.selectAll(".tick line").clone()
        .attr("stroke-opacity", 0.1)
        .attr("y1", -height))
    .call(g => g.append("text")
        .attr("x", width - margin.right)
        .attr("y", -3)
        .attr("fill", "currentColor")
        .attr("font-weight", "bold")
        .text("z"));


const x = d3.scaleLinear()
    .domain([-3, 3])
    .range([margin.left, width - margin.right]);
    
const regression = x.domain().map(ss.linearRegressionLine(ss.linearRegression(Array.from(qy, (d, i) => ([z(i), d])))));
    
const y = d3.scaleLinear()
    .domain(regression).nice()
    .range([height - margin.bottom, margin.top]);
        
const yAxis = g => g
    .attr("transform", `translate(${margin.left - 6},0)`)
    .call(d3.axisLeft(y.copy().interpolate(d3.interpolateRound)))
    .call(g => g.select(".domain").remove())
    .call(g => g.selectAll(".tick line").clone()
        .attr("stroke-opacity", 0.1)
        .attr("x1", width))
    .call(g => g.select(".tick:last-of-type text").clone()
        .attr("x", 3)
        .attr("text-anchor", "start")
        .attr("font-weight", "bold")
        .text(data.title));

const chart = () => {
  const svg = d3.create("svg")
      .attr("viewBox", [0, 0, width, height])
      .style("max-width", `${width}px`);

  svg.append("g")
      .call(xAxis);

  svg.append("g")
      .call(yAxis);

  svg.append("line")
      .attr("stroke", "currentColor")
      .attr("stroke-opacity", 0.3)
      .attr("x1", x.range()[0])
      .attr("x2", x.range()[1])
      .attr("y1", y(regression[0]))
      .attr("y2", y(regression[1]));

  svg.append("g")
      .attr("fill", "none")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 1.5)
    .selectAll("circle")
    .data(d3.range(n))
    .join("circle")
      .attr("cx", i => x(z(i)))
      .attr("cy", i => y(qy[i]))
      .attr("r", 3);

  return svg.node();
}
    
chart();
</script>

</body>
</html>

非常感谢任何帮助,谢谢。

【问题讨论】:

    标签: javascript html d3.js observable


    【解决方案1】:

    这是一个工作示例:

    <!DOCTYPE HTML>
    <html>
    
    <head>
      <meta charset="UTF-8">
      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.6.2/d3.min.js"></script>
      <script src="https://unpkg.com/simple-statistics@7.7.0/dist/simple-statistics.min.js"></script>
    </head>
    
    <body>
      <svg></svg>
      <script>
        const width = 600;
        const height = 600;
    
        const margin = ({ top: 20, right: 40, bottom: 30, left: 40 });
    
        const data = [
          608.781, 569.67, 689.556, 747.541,
          618.134, 612.182, 680.203, 607.766,
          726.232, 605.38, 518.655, 589.226,
          740.447, 588.375, 666.83, 531.384,
          710.272, 633.417, 751.669, 619.06
        ];
    
        const erfinv = x => {
          const a = 8 * (Math.PI - 3) / (3 * Math.PI * (4 - Math.PI));
          const b = Math.log(1 - x * x);
          const c = b / 2 + (2 / (Math.PI * a));
          return Math.sign(x) * Math.sqrt(Math.sqrt((c * c) - b / a) - c);
        };
    
        const qnorm = p => Math.SQRT2 * erfinv(2 * p - 1);
        const qy = Float64Array.from(data).sort(d3.ascending);
        const n = qy.length;
        const a = n <= 10 ? 5 / 8 : 0.5;
        const z = i => qnorm((i + a) / (n + 1 - 2 * a));
    
        const xAxis = g => g
            .attr("transform", `translate(0,${height - margin.bottom + 6})`)
            .call(d3.axisBottom(x.copy().interpolate(d3.interpolateRound)).ticks(null, "+f"))
            .call(g => g.select(".domain").remove())
            .call(g => g.selectAll(".tick line").clone()
              .attr("stroke-opacity", 0.1)
              .attr("y1", -height))
            .call(g => g.append("text")
              .attr("x", width - margin.right)
              .attr("y", -3)
              .attr("fill", "currentColor")
              .attr("font-weight", "bold")
              .text("z"));
    
        const x = d3.scaleLinear()
            .domain([-3, 3])
            .range([margin.left, width - margin.right]);
    
        const regression = x.domain()
            .map(ss.linearRegressionLine(ss.linearRegression(Array.from(qy, (d, i) => ([z(i), d])))));
    
        const y = d3.scaleLinear()
          .domain(regression).nice()
          .range([height - margin.bottom, margin.top]);
    
        const yAxis = g => g
            .attr("transform", `translate(${margin.left - 6},0)`)
            .call(d3.axisLeft(y.copy().interpolate(d3.interpolateRound)))
            .call(g => g.select(".domain").remove())
            .call(g => g.selectAll(".tick line").clone()
              .attr("stroke-opacity", 0.1)
              .attr("x1", width))
            .call(g => g.select(".tick:last-of-type text").clone()
              .attr("x", 3)
              .attr("text-anchor", "start")
              .attr("font-weight", "bold")
              .text("Stength"));
    
        const svg = d3.select("svg")
            .attr("width", width)
            .attr("height", height);
    
        svg.append("g")
            .call(xAxis);
    
        svg.append("g")
            .call(yAxis);
    
        svg.append("line")
            .attr("stroke", "currentColor")
            .attr("stroke-opacity", 0.3)
            .attr("x1", x.range()[0])
            .attr("x2", x.range()[1])
            .attr("y1", y(regression[0]))
            .attr("y2", y(regression[1]));
    
        svg.append("g")
            .attr("fill", "none")
            .attr("stroke", "steelblue")
            .attr("stroke-width", 1.5)
          .selectAll("circle")
          .data(d3.range(n))
          .join("circle")
            .attr("cx", i => x(z(i)))
            .attr("cy", i => y(qy[i]))
            .attr("r", 3);
      </script>
    </body>
    
    </html>
    

    有几点需要注意。首先,erfinv 函数。你有:

    const erfinv = () => {
      const a = 8 * (Math.PI - 3) / (3 * Math.PI * (4 - Math.PI));
      return x => {
        const b = Math.log(1 - x * x);
        const c = b / 2 + (2 / (Math.PI * a));
        return Math.sign(x) * Math.sqrt(Math.sqrt((c * c) - b / a) - c);
      };
    }
    

    这是一个返回另一个函数的函数。所以当你像erfinv(2 * p - 1) 那样调用它时,它返回的是一个函数,而不是一个数字。你可以这样写:

    const erfinv = x => {
      const a = 8 * (Math.PI - 3) / (3 * Math.PI * (4 - Math.PI));
      const b = Math.log(1 - x * x);
      const c = b / 2 + (2 / (Math.PI * a));
      return Math.sign(x) * Math.sqrt(Math.sqrt((c * c) - b / a) - c);
    };
    

    其次,您的 HTML 代码在 DOM 中已经有了 &lt;svg&gt; 元素。因此,我们可以使用d3.select('svg') 选择现有的,而不是使用d3.create('svg')。此外,return svg.node(); 仅在 Observable 上需要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-20
      • 1970-01-01
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多