使用Dash组件嵌入D3 + HTML

gtlvzcf8  于 2023-11-19  发布在  其他
关注(0)|答案(2)|浏览(129)

我有D3 + HTML代码,我想在Plotly破折号嵌入。有人可以帮助吗?
例如,如果这是使用D3填充散点图的代码,我应该如何使用plotly dash回调?我已经使用plotly dash构建了一个 Jmeter 板。因此,当单击应用按钮时,应该调用此JavaScript并显示散点图。

<svg width="500" height="350"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var svg = d3.select("svg"),
    margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

function make_x_axis() {
    return d3.axisBottom(x)
        // .scale(x)
        //  .orient("bottom")
         .ticks(5)
}

function make_y_axis() {
    return d3.axisLeft(y)
        // .scale(y)
        // .orient("left")
        .ticks(5)
}

let points = d3.range(1, 10).map(function(i) {
    return [i * width / 10, 50 + Math.random() * (height - 100)];
});

var x = d3.scaleLinear()
    .rangeRound([0, width]);

var y = d3.scaleLinear()
    .rangeRound([height, 0]);

var xAxis = d3.axisBottom(x),
    yAxis = d3.axisLeft(y);

var line = d3.line()
    .x(function(d) { return x(d[0]); })
    .y(function(d) { return y(d[1]); });


let drag = d3.drag()
        .on('start', dragstarted)
        .on('drag', dragged)
        .on('end', dragended);

svg.append('rect')
    .attr('class', 'zoom')
    .attr('cursor', 'move')
    .attr('fill', 'none')
    .attr('pointer-events', 'all')
    .attr('width', width)
    .attr('height', height)
    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')


// svg.append("g")
//         .attr("class", "grid")
//         .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
//         .call(make_x_axis()
//             .tickSize(-height, 0, 0)
//             .tickFormat("")
//         )
//
// svg.append("g")
//     .attr("class", "grid")
//     .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
//     // .attr("transform", "translate(0," + (height + margin.top) + ")")
//     .call(make_y_axis()
//     .tickSize(-width, 0, 0)
//     .tickFormat("")
//          )
svg.append("g")
      .attr("class", "grid")
      .attr("transform", `translate(${margin.left}, ${height + margin.top})`)
      .call(make_x_axis()
          .tickSize(-height)
          .tickFormat("")
      )

  // add the Y gridlines
  svg.append("g")
      .attr("class", "grid")
      .attr("transform", `translate(${margin.left}, ${margin.top})`)
      .call(make_y_axis()
          .tickSize(-width)
          .tickFormat("")
      )

 var focus = svg.append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

x.domain(d3.extent(points, function(d) { return d[0]; }));
y.domain(d3.extent(points, function(d) { return d[1]; }));

focus.append("path")
    .datum(points)
    .attr("fill", "none")
    .attr("stroke", "white")
    .attr("stroke-linejoin", "round")
    .attr("stroke-linecap", "round")
    .attr("stroke-width", 1.5)
    .attr("d", line);

focus.selectAll('circle')
    .data(points)
    .enter()
    .append('circle')
    .attr('r', 5.0)
    .attr('cx', function(d) { return x(d[0]);  })
    .attr('cy', function(d) { return y(d[1]); })
    .style('cursor', 'pointer')
    .style('fill', 'steelblue');

focus.selectAll('circle')
        .call(drag);

focus.append('g')
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,' + height + ')')
    .call(xAxis);

focus.append('g')
    .attr('class', 'axis axis--y')
    .call(yAxis);

function dragstarted(d) {
    d3.select(this).raise().classed('active', true);
}

function dragged(d) {
    //d[0] = x.invert(d3.event.x);
    d[1] = y.invert(d3.event.y);
    d3.select(this)
        //.attr('cx', x(d[0]))
        .attr('cy', y(d[1]))
    focus.select('path').attr('d', line);
}

function dragended(d) {
    d3.select(this).classed('active', false);
}

</script>

字符串
Usage.py

import dash
#import dash_alternative_viz as dav
import dash_html_components as html
from dash.dependencies import Input, Output
#import random

external_scripts = [
    "https://d3js.org/d3.v4.min.js"
    
]

app = dash.Dash(external_scripts=external_scripts)
app.layout = html.Div(
        [html.Div(id="content", className="app-header"), 
         html.Button(id="button", children="Button")]
)

@app.callback(
    Output("content", "style"),
    [dash.dependencies.Input("button", "n_clicks")],
)
def update_output(n_clicks):
    if n_clicks:
        return {"display": "block"}
    return {"display": "no graph"}
    
if __name__ == "__main__":
   app.run_server( port = 8052, debug=True)


header.css

app-header {
  height: 350px;
  width: 50%;
  background-color: powderblue;
}


谢谢,米拉

zujrkrfu

zujrkrfu1#

要在达世币应用中嵌入JavaScript,请参阅以下内容。包含Javascript(和CSS)的最简单方法是在应用的根目录下创建一个assets文件夹。
要在Dash应用中执行示例中的代码,您可以将JavaScript代码放在assets文件夹中的.js文件中。
所以你可以有一个script.js文件,看起来像这样:

window.addEventListener("load", function () {
  const svg = d3
    .select("#content")
    .append("svg")
    .attr("width", "500")
    .attr("height", "350");

  const margin = { top: 20, right: 20, bottom: 30, left: 50 };
  const width = +svg.attr("width") - margin.left - margin.right;
  const height = +svg.attr("height") - margin.top - margin.bottom;

  function make_x_axis() {
    return (
      d3
        .axisBottom(x)
        // .scale(x)
        //  .orient("bottom")
        .ticks(5)
    );
  }

  function make_y_axis() {
    return (
      d3
        .axisLeft(y)
        // .scale(y)
        // .orient("left")
        .ticks(5)
    );
  }

  let points = d3.range(1, 10).map(function (i) {
    return [(i * width) / 10, 50 + Math.random() * (height - 100)];
  });

  var x = d3.scaleLinear().rangeRound([0, width]);

  var y = d3.scaleLinear().rangeRound([height, 0]);

  var xAxis = d3.axisBottom(x),
    yAxis = d3.axisLeft(y);

  var line = d3
    .line()
    .x(function (d) {
      return x(d[0]);
    })
    .y(function (d) {
      return y(d[1]);
    });

  let drag = d3
    .drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended);

  svg
    .append("rect")
    .attr("class", "zoom")
    .attr("cursor", "move")
    .attr("fill", "none")
    .attr("pointer-events", "all")
    .attr("width", width)
    .attr("height", height)
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  svg
    .append("g")
    .attr("class", "grid")
    .attr("transform", `translate(${margin.left}, ${height + margin.top})`)
    .call(make_x_axis().tickSize(-height).tickFormat(""));

  // add the Y gridlines
  svg
    .append("g")
    .attr("class", "grid")
    .attr("transform", `translate(${margin.left}, ${margin.top})`)
    .call(make_y_axis().tickSize(-width).tickFormat(""));

  var focus = svg
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  x.domain(
    d3.extent(points, function (d) {
      return d[0];
    })
  );
  y.domain(
    d3.extent(points, function (d) {
      return d[1];
    })
  );

  focus
    .append("path")
    .datum(points)
    .attr("fill", "none")
    .attr("stroke", "white")
    .attr("stroke-linejoin", "round")
    .attr("stroke-linecap", "round")
    .attr("stroke-width", 1.5)
    .attr("d", line);

  focus
    .selectAll("circle")
    .data(points)
    .enter()
    .append("circle")
    .attr("r", 5.0)
    .attr("cx", function (d) {
      return x(d[0]);
    })
    .attr("cy", function (d) {
      return y(d[1]);
    })
    .style("cursor", "pointer")
    .style("fill", "steelblue");

  focus.selectAll("circle").call(drag);

  focus
    .append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

  focus.append("g").attr("class", "axis axis--y").call(yAxis);

  function dragstarted(d) {
    d3.select(this).raise().classed("active", true);
  }

  function dragged(d) {
    //d[0] = x.invert(d3.event.x);
    d[1] = y.invert(d3.event.y);
    d3.select(this)
      //.attr('cx', x(d[0]))
      .attr("cy", y(d[1]));
    focus.select("path").attr("d", line);
  }

  function dragended(d) {
    d3.select(this).classed("active", false);
  }
  
  document.querySelector("#content").style.display = "none" // Hide if button content if button has not yet been clicked.
});

字符串
我把你的代码放在一个load事件监听器中,以确保JavaScript只在页面加载后执行。
我做的另一个调整是在Dash布局中添加一个容器div(我给它一个id content),并在这个容器中附加一个svg元素。你也可以选择body或任何其他从Dash布局中渲染的元素,并在其上附加svg。

  • 据我所知,没有一个真正的Dash svg组件可以直接放在你的Dash布局中。

所以我们的想法是让d3为我们创建svg元素,而不是Dash。
显示图表的最小Dash布局看起来像这样:

external_scripts = [
    "https://d3js.org/d3.v4.min.js",
]

app = dash.Dash(external_scripts=external_scripts)
app.layout = html.Div(
        [html.Div(id="content"), html.Button(id="button", children="Button")]
)


使用Dashexternal_scripts参数包含d3。
实际上显示图表按钮点击我可以想到两种方法(略有不同)。
在Python中使用Dash回调来处理按钮点击:

app = dash.Dash(external_scripts=external_scripts)
app.layout = html.Div(
    [
        html.Div(id="content"),
        html.Button(id="button", children="Button"),
    ]
)

@app.callback(
    Output("content", "style"),
    [dash.dependencies.Input("button", "n_clicks")],
)
def update_output(n_clicks):
    if n_clicks:
        return {"display": "block"}
    return {}


如果按钮没有被点击过一次,则不会显示图形。如果按钮被点击,则会显示图形。您可以更改行为以切换图形的可见性或在点击一次后隐藏按钮,根据您的需要进行调整。
另一种方法是添加click listener in your Javascript script

  • 如果按照上面的示例,请确保在assets文件夹中添加CSS文件,并在div中添加widthheight,否则将不会显示任何内容。*

另一种更复杂的方法是为你的图创建一个React组件,并将其转换为一个Dash组件,你可以在你的Dash布局中使用。请参阅我的答案here和官方文档here以获得一个想法。如果你计划使用很多这样的JavaScript库来与Dash交互,我认为这种方法是可取的。它给你更多的控制,你可以在你的Dash中使用它。可以以更声明的方式与这些JavaScript库进行交互。

mec1mxoz

mec1mxoz2#

D3不能选择Dash在app.py中定义的一些元素,老实说,我对这个问题几乎一无所知。但是你可以在.js中选择D3的“body”,并附加一些元素。
.js格式

var body = d3.select('body');
var svg = body.append('svg').attr('width',200).attr('height',200);
svg.append("circle").attr("r","150px").attr("fill","gray");

字符串

相关问题