当我更新一个闪亮的输入时,htmlwidget 绘制一个新图?

伊格纳西奥

我正在创建我的第一个包,htmlwidgets并且在将输出与闪亮的集成时遇到了一些麻烦。当我更新输入时,我的小部件会在原始图下方绘制一个新图,而不仅仅是更新原始图。例如:

在此处输入图片说明

这是我的js代码,我的猜测是问题出在那里:

HTMLWidgets.widget({

  name: 'IMPosterior',

  type: 'output',

  factory: function(el, width, height) {

    // TODO: define shared variables for this instance

    return {

      renderValue: function(opts) {

        //transition
        var transDuration = 2500;

        var dataDiscrete = opts.bars.map((b, i) => {
            b.y = Number(b.y);
            b.desc = opts.text[i];
            return b;
        });

        var distParams = {
            min: d3.min(opts.data, d => d.x),
            max: d3.max(opts.data, d => d.x)
        };

        distParams.cuts = [-opts.MME, opts.MME, distParams.max];

        opts.data = opts.data.sort((a,b) => a.x - b.x);

        var dataContinuousGroups = [];
        distParams.cuts.forEach((c, i) => {
            let data = opts.data.filter(d => {
                if (i === 0) {
                    return d.x < c;
                } else if (i === distParams.cuts.length - 1) {
                    return d.x > distParams.cuts[i - 1];
                } else {
                    return d.x < c && d.x > distParams.cuts[i - 1];
                }
            });

            data.unshift({x:data[0].x, y:0});
            data.push({x:data[data.length - 1].x, y:0});

            dataContinuousGroups.push({
                color: opts.colors[i],
                data: data
            });
        });

        var margin = {
                top: 50,
                right: 20,
                bottom: 80,
                left: 70
            },
            dims = {
                width: width - margin.left - margin.right,
                height: height - margin.top - margin.bottom
            };

        var xContinuous = d3.scaleLinear()
            .domain([distParams.min - 1, distParams.max + 1])
            .range([0, dims.width]);

        var xDiscrete = d3.scaleBand()
            .domain(dataDiscrete.map(function(d) { return d.x; }))
            .rangeRound([0, dims.width]).padding(0.1);

        var y = d3.scaleLinear()
            .domain([0, 1])
            .range([dims.height, 0]);

        var svg = d3.select(el).append("svg")
            .attr("width", dims.width + margin.left + margin.right)
            .attr("height", dims.height + margin.top + margin.bottom);

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

        var xAxis = d3.axisBottom()
            .scale(xDiscrete);

        var yAxis = d3.axisLeft()
            .scale(y)
            .ticks(10)
            .tickFormat(d3.format(".0%"));

        var yLabel = g.append("text")
            .attr("class", "y-axis-label")
            .attr("transform", "rotate(-90)")
            .attr("y", -52)
            .attr("x", -160)
            .attr("dy", ".71em")
            .style("text-anchor", "end")
            .style("font-size", 14 + "px")
            .text("Probability");

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

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

        var areas = g.selectAll(".area")
            .data(dataDiscrete)
            .enter().append("path")
                .attr("class", "area")
                .style("fill", function(d) { return d.color; })
                .attr("d", function(d, i) {
                    let numPts = dataContinuousGroups[i].data.length - 2;
                    var path = d3.path();
                    path.moveTo(xDiscrete(d.x), y(0));
                    for (j=0; j<numPts; j++) {
                        path.lineTo(xDiscrete(d.x) + j*xDiscrete.bandwidth()/(numPts-1), y(d.y));
                    }
                    path.lineTo(xDiscrete(d.x) + xDiscrete.bandwidth(), y(0));
                    return path.toString();
                });

        var tooltip = d3.tip()
            .attr('class', 'd3-tip chart-data-tip')
            .offset([30, 0])
            .direction('s')
            .html(function(d, i) {
                return "<span>" + dataDiscrete[i].desc + "</span>";
            });

        g.call(tooltip);

        areas
            .on('mouseover', tooltip.show)
            .on('mouseout', tooltip.hide);

        var thresholdLine = g.append("line")
            .attr("stroke", "black")
            .style("stroke-width", "1.5px")
            .style("stroke-dasharray", "5,5")
            .style("opacity", 1)
            .attr("x1", 0)
            .attr("y1", y(opts.threshold))
            .attr("x2", dims.width)
            .attr("y2", y(opts.threshold));


        var updateXAxis = function(type, duration) {
            if (type === "continuous") {
                xAxis.scale(xContinuous);
            } else {
                xAxis.scale(xDiscrete);
            }
            d3.select(".x").transition().duration(duration).call(xAxis);       
        };

        var updateYAxis = function(data, duration) {
            var extent = d3.extent(data, function(d) {
                return d.y;
            });
            extent[0] = 0;
            extent[1] = extent[1] + 0.2*(extent[1] - extent[0]);
            y.domain(extent);
            d3.select(".y").transition().duration(duration).call(yAxis);
        };

        var toggle = function(to, duration) {
            if (to === "distribution") {
                updateYAxis(dataContinuousGroups[0].data.concat(dataContinuousGroups[1].data).concat(dataContinuousGroups[2].data), 0);
                updateXAxis("continuous", duration);

                areas
                    .data(dataContinuousGroups)
                    .transition()
                    .duration(duration)
                        .attr("d", function(d) {
                            var gen = d3.line()
                                .x(function(p) {
                                    return xContinuous(p.x);
                                })
                                .y(function(p) {
                                    return y(p.y);
                                });
                            return gen(d.data);
                        });

                thresholdLine
                    .style("opacity", 0);

                g.select(".y.axis")
                    .style("opacity", 0);

                g.select(".y-axis-label")
                    .style("opacity", 0);

            } else {
                y.domain([0, 1]);
                d3.select(".y").transition().duration(duration).call(yAxis);

                updateXAxis("discrete", duration);

                areas
                    .data(dataDiscrete)
                    .transition()
                    .duration(duration)
                        .attr("d", function(d, i) {
                            let numPts = dataContinuousGroups[i].data.length - 2;
                            var path = d3.path();
                            path.moveTo(xDiscrete(d.x), y(0));
                            for (j=0; j<numPts; j++) {
                                path.lineTo(xDiscrete(d.x) + j*xDiscrete.bandwidth()/(numPts-1), y(d.y));
                            }
                            path.lineTo(xDiscrete(d.x) + xDiscrete.bandwidth(), y(0));
                            return path.toString();
                        });

                thresholdLine
                    .transition()
                    .duration(0)
                    .delay(duration)
                        .style("opacity", 1)
                        .attr("y1", y(opts.threshold))
                        .attr("y2", y(opts.threshold));

                g.select(".y.axis")
                    .transition()
                    .duration(0)
                    .delay(duration)
                        .style("opacity", 1);

                g.select(".y-axis-label")
                    .transition()
                    .duration(0)
                    .delay(duration)
                        .style("opacity", 1);
            }
        };


        // Add buttons

        //container for all buttons
        var allButtons = svg.append("g")
          .attr("id", "allButtons");

        //fontawesome button labels
        var labels = ["B", "D"];

        //colors for different button states
        var defaultColor = "#E0E0E0";
        var hoverColor = "#808080";
        var pressedColor = "#000000";

        //groups for each button (which will hold a rect and text)
        var buttonGroups = allButtons.selectAll("g.button")
          .data(labels)
          .enter()
          .append("g")
          .attr("class", "button")
          .style("cursor", "pointer")
          .on("click", function(d, i) {
            updateButtonColors(d3.select(this), d3.select(this.parentNode));
            d3.select("#numberToggle").text(i + 1);
            if (d === "D") {
                toggle("distribution", transDuration);
            } else {
                toggle("discrete", transDuration);
            }

          })
          .on("mouseover", function() {
            if (d3.select(this).select("rect").attr("fill") != pressedColor) {
              d3.select(this)
                .select("rect")
                .attr("fill", hoverColor);
            }
          })
          .on("mouseout", function() {
            if (d3.select(this).select("rect").attr("fill") != pressedColor) {
              d3.select(this)
                .select("rect")
                .attr("fill", defaultColor);
            }
          });

        var bWidth = 40; //button width
        var bHeight = 25; //button height
        var bSpace = 10; //space between buttons
        var x0 = 20; //x offset
        var y0 = 10; //y offset

        //adding a rect to each toggle button group
        //rx and ry give the rect rounded corner
        buttonGroups.append("rect")
          .attr("class", "buttonRect")
          .attr("width", bWidth)
          .attr("height", bHeight)
          .attr("x", function(d, i) {
            return x0 + (bWidth + bSpace) * i;
          })
          .attr("y", y0)
          .attr("rx", 5) //rx and ry give the buttons rounded corners
          .attr("ry", 5)
          .attr("fill", defaultColor);

        //adding text to each toggle button group, centered
        //within the toggle button rect
        buttonGroups.append("text")
          .attr("class", "buttonText")
          .attr("x", function(d, i) {
            return x0 + (bWidth + bSpace) * i + bWidth / 2;
          })
          .attr("y", y0 + bHeight / 2)
          .attr("text-anchor", "middle")
          .attr("dominant-baseline", "central")
          .attr("fill", "white")
          .text(function(d) {
            return d;
          });

        function updateButtonColors(button, parent) {
          parent.selectAll("rect")
            .attr("fill", defaultColor);

          button.select("rect")
            .attr("fill", pressedColor);

        }

        toggle("distribution", 0);

        setTimeout(() => {
            toggle("discrete", transDuration);
        }, 1000);

      },



      resize: function(width, height) {

        // TODO: code to re-render the widget with a new size

      }

    };
  }
});

这是闪亮应用程序的代码:

# Gen data --------------------------------------------------------------
set.seed(9782)
x <- rnorm(1000)


# Usy my widget -----------------------------------------------------------
library(IMPosterior)
IMPosterior(x= x, MME=1)

## app.R ##
library(shiny)
library(shinydashboard)
library(IMPosterior) # https://github.com/ignacio82/IMPosterior

ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(
    sliderInput(
      "threshold",
      h4("Threshold:"),
      min = 50,
      max = 99,
      value = 75,
      step = 1,
      post = "%"
    )
  ),
  dashboardBody(
    box(
      title = "Posterior Distribution",
      status = "primary",
      solidHeader = TRUE,
      width = 6,
      IMPosteriorOutput("plot", height = "350px")
    )
  )
)

server <- function(input, output) { 

  output$plot <- renderIMPosterior({
    p <- IMPosterior(x = x, MME = 1, threshold = input$threshold/100)
    return(p)
  })

  }

shinyApp(ui, server)

我究竟做错了什么?

伊格纳西奥

我不确定这是否是解决问题的最佳方法,但确实如此。我只需要在我选择后添加.html("")到我的svg右边el

var svg = d3.select(el).html("").append("svg")
            .attr("width", dims.width + margin.left + margin.right)
            .attr("height", dims.height + margin.top + margin.bottom);

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

当我将 cin 用于两个输入时,如何接收一个输入?

来自分类Dev

Python:更新图而不是创建一个新图

来自分类Dev

当我用border-radius聚焦输入时,会出现一个方形边框

来自分类Dev

在一个图中绘制两个图

来自分类Dev

在一个gnuplot中绘制两个图

来自分类Dev

基于一个闪亮的小部件在Rmarkdown中并排绘制2个图

来自分类Dev

无法在一个循环中绘制多个图?

来自分类Dev

使用Seaborn在一个图中绘制多个不同的图

来自分类Dev

无法在一个循环中绘制多个图?

来自分类Dev

matplotlib:在一个大图中绘制多个小图

来自分类Dev

绘制一个图,在右边绘制一个附加的y轴,在顶部绘制一个附加的x轴,并链接到底部的图

来自分类Dev

我做了一个 switch case 程序,当我给出输入时它不执行 switch case

来自分类Dev

尝试创建一个闪亮的应用程序。在指定公式输入时出现错误

来自分类Dev

动态绘制要在一组轴上显示的多个图(一次绘制一个图)

来自分类Dev

当我们向输入字段提供输入时,为什么PhantomJS仅输入最后一个字母?

来自分类Dev

当我们向输入字段提供输入时,为什么PhantomJS仅输入最后一个字母?

来自分类Dev

为什么我的子图只绘制到最后一个斧头?

来自分类Dev

我怎样才能绘制一个图来获得二元结果的概率

来自分类Dev

为什么Seaborn的对图不绘制第一个图?

来自分类Dev

如图和图所示,在matlab中绘制一个简单的binaryThresholding函数图

来自分类Dev

当我使用 quantmod 包绘制图表时,我得到多个图,而不是 1 个。如何只得到最后一个图表?

来自分类Dev

我想用输入字段更新一个数组,但是它创建了一个新的数组

来自分类Dev

一个内部图或一个内部图?

来自分类Dev

D3 v4 更新条形图不绘制最后一个条形图

来自分类Dev

如何在Matlab中使用两个矩阵绘制一个图

来自分类Dev

将3个箱形图绘制到一个图中

来自分类Dev

如何在Matlab中使用两个矩阵绘制一个图

来自分类Dev

我可以维护一个 TcpStreams 的 Vec 以在其中一个读取新输入时跨线程写入它们吗?

来自分类Dev

当我尝试从同一个包导入时出现 ImportError

Related 相关文章

  1. 1

    当我将 cin 用于两个输入时,如何接收一个输入?

  2. 2

    Python:更新图而不是创建一个新图

  3. 3

    当我用border-radius聚焦输入时,会出现一个方形边框

  4. 4

    在一个图中绘制两个图

  5. 5

    在一个gnuplot中绘制两个图

  6. 6

    基于一个闪亮的小部件在Rmarkdown中并排绘制2个图

  7. 7

    无法在一个循环中绘制多个图?

  8. 8

    使用Seaborn在一个图中绘制多个不同的图

  9. 9

    无法在一个循环中绘制多个图?

  10. 10

    matplotlib:在一个大图中绘制多个小图

  11. 11

    绘制一个图,在右边绘制一个附加的y轴,在顶部绘制一个附加的x轴,并链接到底部的图

  12. 12

    我做了一个 switch case 程序,当我给出输入时它不执行 switch case

  13. 13

    尝试创建一个闪亮的应用程序。在指定公式输入时出现错误

  14. 14

    动态绘制要在一组轴上显示的多个图(一次绘制一个图)

  15. 15

    当我们向输入字段提供输入时,为什么PhantomJS仅输入最后一个字母?

  16. 16

    当我们向输入字段提供输入时,为什么PhantomJS仅输入最后一个字母?

  17. 17

    为什么我的子图只绘制到最后一个斧头?

  18. 18

    我怎样才能绘制一个图来获得二元结果的概率

  19. 19

    为什么Seaborn的对图不绘制第一个图?

  20. 20

    如图和图所示,在matlab中绘制一个简单的binaryThresholding函数图

  21. 21

    当我使用 quantmod 包绘制图表时,我得到多个图,而不是 1 个。如何只得到最后一个图表?

  22. 22

    我想用输入字段更新一个数组,但是它创建了一个新的数组

  23. 23

    一个内部图或一个内部图?

  24. 24

    D3 v4 更新条形图不绘制最后一个条形图

  25. 25

    如何在Matlab中使用两个矩阵绘制一个图

  26. 26

    将3个箱形图绘制到一个图中

  27. 27

    如何在Matlab中使用两个矩阵绘制一个图

  28. 28

    我可以维护一个 TcpStreams 的 Vec 以在其中一个读取新输入时跨线程写入它们吗?

  29. 29

    当我尝试从同一个包导入时出现 ImportError

热门标签

归档