将 javascript (d3.js) 绑定到闪亮

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26650561/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 06:16:03  来源:igfitidea点击:

Binding javascript (d3.js) to shiny

javascriptrd3.jsshiny

提问by Sweetbabyjesus

First, I am fairly unfamiliar with javascript and its library d3.js, but I am familiar with R. Creating dashboards using Shiny has been fun and easy (thanks to stackoverflow). Now I want to expand it by connect d3 elements to it.

首先,我对 javascript 及其库 d3.js 相当不熟悉,但我对 R 很熟悉。使用 Shiny 创建仪表板既有趣又简单(感谢 stackoverflow)。现在我想通过将 d3 元素连接到它来扩展它。

I'm looking for information sources on how to actually bind javascript to Shiny (R dashboard) and explain what is actually going on.

我正在寻找有关如何将 javascript 实际绑定到 Shiny(R 仪表板)并解释实际发生的情况的信息来源。

Background: I did the tutorial on js and jquery on w3schools and learned (a bit) about d3 using Scott Murray's book (Interactive Data visualization for the web). I hoped this would be enough to make me understand the examples and explanation concerning how to build custom input/output bindings on the Shiny website:

背景:我在 w3schools 上做了关于 js 和 jquery 的教程,并使用 Scott Murray 的书(网络交互式数据可视化)学习了(一点)关于 d3 的知识。我希望这足以让我理解有关如何在 Shiny 网站上构建自定义输入/输出绑定的示例和解释:

http://shiny.rstudio.com/articles/building-inputs.html

http://shiny.rstudio.com/articles/building-inputs.html

But unfortunately I don't and I can't seem to find any examples which are in minimal working code. Many examples on github are to complex for me to dissect, most probably because of my little experience with javascript. Here is an examples of custom input binding with javascript:

但不幸的是,我没有,而且我似乎找不到任何使用最少工作代码的示例。github 上的许多例子对我来说很复杂,很可能是因为我对 javascript 的经验很少。以下是使用 javascript 的自定义输入绑定示例:

https://github.com/jcheng5/shiny-js-examples/tree/master/input

https://github.com/jcheng5/shiny-js-examples/tree/master/input

Here is an example of an input & output binding I try to unfold:

这是我尝试展开的输入和输出绑定的示例:

<script src="http://d3js.org/d3.v3.js"></script>
<script type="text/javascript">
(function(){
  // Probably not idiomatic javascript.

  this.countValue=0;

  // BEGIN: FUNCTION
  updateView = function(message) {

    var svg = d3.select(".d3io").select("svg")

    svg.append("text")
      .transition()
      .attr("x",message[0])
      .attr("y",message[1])
      .text(countValue)
      .each("end",function(){
        if(countValue<100) {
          countValue+=1;
          $(".d3io").trigger("change");
        }
      })
  }
  // END: FUNCTION

  //BEGIN: OUTPUT BINDING
  var d3OutputBinding = new Shiny.OutputBinding();
  $.extend(d3OutputBinding, {
    find: function(scope) {
      return $(scope).find(".d3io");
    },
    renderError: function(el,error) {
      console.log("Foe");
    },
    renderValue: function(el,data) {
      updateView(data);
      console.log("Friend");
    }
  });
  Shiny.outputBindings.register(d3OutputBinding);
  //END: OUTPUT BINDING

  //BEGIN: INPUT BINDING
  var d3InputBinding = new Shiny.InputBinding();
  $.extend(d3InputBinding, {
    find: function(scope) {
      return $(scope).find(".d3io");
    },
    getValue: function(el) {
      return countValue;
    },
    subscribe: function(el, callback) {
      $(el).on("change.d3InputBinding", function(e) {
        callback();
      });
    }
  });
  Shiny.inputBindings.register(d3InputBinding);
 //END: OUTPUT BINDING

})()
</script>

Where "d3io" is a div element in the ui, updateView() is a function. Here is the ui:

其中“d3io”是 ui 中的 div 元素,updateView() 是一个函数。这是用户界面:

#UI
library(shiny)

d3IO <- function(inputoutputID) {
  div(id=inputoutputID,class=inputoutputID,tag("svg","")) #; eerst zat ; erbij, maar werkt blijkbaar ook zonder
}

# Define UI for shiny d3 chatter application
shinyUI(pageWithSidebar(

  # Application title
  headerPanel("D3 Javascript chatter",
              "Demo of how to create D3 I/O and cumulative data transfer"),

  sidebarPanel(
    tags$p("This widget is a demonstration of how to wire shiny direct to javascript, without any input elements."),
    tags$p("Each time a transition ends, the client asks the server for another packet of information, and adds it
            to the existing set"),
    tags$p("I can't claim this is likely to be idiomatic javascript, because I'm a novice, but it allows d3 apps
            to do progressive rendering.  In real use, a more complex request/response protocol will probably be
            required.  -AlexBBrown")
  ),

  mainPanel(
    includeHTML("d3widget.js"),
    d3IO("d3io") #Creates div element that d3 selects
    )
))

Here is the server file:

这是服务器文件:

# SERVER
library(shiny)
# Define server logic required to respond to d3 requests
shinyServer(function(input, output) {

  # Generate a plot of the requested variable against mpg and only 
  # include outliers if requested
  output$d3io <- reactive(function() {
    if (is.null(input$d3io)) {
      0;
    } else {
      list(rnorm(1)*400+200,rnorm(1)*400+200);
    }
  })
})

Specific questions:

具体问题:

1) The server.r seems to get input called "d3io" (input$d3io) since this is not defined in ui.r, I reasoned it must come from the javascript file. Which element does it actually refer to?

1) server.r 似乎得到名为“d3io”(input$d3io) 的输入,因为它没有在 ui.r 中定义,我推断它必须来自 javascript 文件。它实际上指的是哪个元素?

2) I have trouble understanding the custom binding part:

2)我无法理解自定义绑定部分:

var d3OutputBinding = new Shiny.OutputBinding();
  $.extend(d3OutputBinding, {
    find: function(scope) {
      return $(scope).find(".d3io");
    },
    renderError: function(el,error) {
      console.log("Foe");
    },
    renderValue: function(el,data) {
      updateView(data);
      console.log("Friend");
    }
  });
  Shiny.outputBindings.register(d3OutputBinding);

My understanding is:

我的理解是:

Create a new shiny outputbinding, first find the class .d3io (div element), if error then write to console "Foe" (is this special code?), if not error then renderValue using the function updateView using data (Where does it receive this value from?) and write to console "Friend". Finally register output.

创建一个新的闪亮的输出绑定,首先找到类 .d3io(div 元素),如果错误则写入控制台“Foe”(这是特殊代码吗?),如果没有错误则使用函数 updateView 使用数据渲染值(它从哪里接收这个值来自?)并写入控制台“朋友”。最后注册输出。

Hope you guys can help! I'm creating a document with the steps on "The necessary steps to learn how to implement javascript into shiny when you don't know any javascript", I would love that!:)

希望大家帮帮忙!我正在创建一个文档,其中包含“当您不知道任何 javascript 时学习如何将 javascript 实现为闪亮的必要步骤”的步骤,我会喜欢的!:)

Cheers, Long

干杯,长

采纳答案by gknicker

Hi Sweetbabyjesus (so fun to say). You had two questions:

嗨,Sweetbabyjesus(说起来很有趣)。你有两个问题:

1) The server.r seems to get input called "d3io" (input$d3io) since this is not defined in ui.r, I reasoned it must come from the javascript file. Which element does it actually refer to?

1) server.r 似乎得到名为“d3io”(input$d3io) 的输入,因为它没有在 ui.r 中定义,我推断它必须来自 javascript 文件。它实际上指的是哪个元素?

That phrase input$d3iohas the following components:

该短语input$d3io具有以下组成部分:

  • inputis a parameter passed into the function - it's a list that stores the current values of all the widgets in the app.
  • $is the member selector.
  • d3iorefers to the content of the div element with that id ('d3IO("d3io")') in the mainPanel of the UI.
  • input是传递给函数的参数 - 它是一个列表,用于存储应用程序中所有小部件的当前值。
  • $是成员选择器。
  • d3io指的是 UI 的 mainPanel 中具有该 id ('d3IO("d3io")') 的 div 元素的内容。

2) I have trouble understanding the custom binding part:

2)我无法理解自定义绑定部分:

var d3OutputBinding = new Shiny.OutputBinding();

That's right, this creates an instance of Shiny.OutputBinding and assigns it to the variable d3OutputBinding.

没错,这将创建 Shiny.OutputBinding 的实例并将其分配给变量 d3OutputBinding。

$.extend(d3OutputBinding, {
  find: function(scope) {
    return $(scope).find(".d3io");
  },
  renderError: function(el,error) {
    console.log("Foe");
  },
  renderValue: function(el,data) {
    updateView(data);
    console.log("Friend");
  }
});

This code extends the behaviour of d3OutputBinding with three functions called find, renderErrorand renderValue. Those three functions are required for a Shiny.OutputBinding.

此代码使用三个名为findrenderError和 的函数扩展了 d3OutputBinding 的行为renderValue。Shiny.OutputBinding 需要这三个函数。

findis the key because it returns a list of elements that should be passed into the two render functions via their elparameter. Notice it's returning elements whose css class is "d3io" - that's the same div mentioned earlier.

find是关键,因为它返回一个元素列表,这些元素应该通过它们的el参数传递给两个渲染函数。请注意,它正在返回 css 类为“d3io”的元素 - 这与前面提到的 div 相同。

Note that extend()is a function of jQuery javascript library, and the $in this context is an alias for the jQuery object.

请注意,这extend()是 jQuery javascript 库的一个函数,并且$在此上下文中是 jQuery 对象的别名。

Shiny.outputBindings.register(d3OutputBinding);

Lets Shiny know that this newly configured object should be put to use now.

让 Shiny 知道现在应该使用这个新配置的对象。

Cheers, Nick

干杯,尼克

回答by Chris Fritz

I'm going to take a step back and assume you want the amazing results D3 is capable of, but aren't necessarily tied to D3. Essentially, I'll be answering this question:

我将退后一步,假设您想要 D3 能够实现的惊人结果,但不一定与 D3 相关联。基本上,我将回答这个问题:

What are the necessary steps to learn how to implement JavaScript into Shiny when you don't know any JavaScript?

当你不知道任何 JavaScript 时,学习如何将 JavaScript 实现到 Shiny 中的必要步骤是什么?

While D3 is amazingly powerful, it's also notoriously difficult to master - even for many folks who are quite comfortable with JavaScript. While I love D3 and use it almost every day, I'd recommend against it in this case. Instead, there's library called Plotly, which uses D3 in the background, but is built specifically for the scientific community and data scientists, so it's very friendly to the R community.

尽管 D3 非常强大,但众所周知,它也很难掌握——即使对于许多熟悉 JavaScript 的人来说也是如此。虽然我喜欢 D3 并且几乎每天都使用它,但在这种情况下我建议不要使用它。相反,有一个名为Plotly的库,它在后台使用 D3,但专为科学界和数据科学家构建,因此对 R 社区非常友好。

They have a thorough tutorial for connecting to Shinyand even have a ggplot2 converterif you're already familiar with that syntax, as many in the R world are. Unless your needs are very unusual, Plotly will likely serve your needs just as well as writing directly in D3, with a much more friendly learning curve.

他们有一个关于连接到 Shiny详尽教程,如果您已经熟悉该语法,甚至还有一个ggplot2 转换器,就像 R 世界中的许多人一样。除非您的需求非常不寻常,否则 Plotly 可能会像直接在 D3 中编写一样满足您的需求,并且具有更友好的学习曲线。

回答by Joe Jansen

Are you familiar with the rCharts package? It can work pretty well with Shiny and most of the output options are based on D3 variants. Twoexamples.

你熟悉rCharts 包吗?它可以很好地与 Shiny 配合使用,并且大多数输出​​选项都基于 D3 变体。两个例子

回答by Sweetbabyjesus

Very busy with work, I haven't had the chance to post it. Note that this is a workaround using the customMessageHandler (and I'm not using custom input/output binding). Here goes:

工作很忙,一直没机会发帖。请注意,这是使用 customMessageHandler 的解决方法(我没有使用自定义输入/输出绑定)。开始:

Objective: Send data from data frame to create a D3JS tree using customMessageHandler.

目标:使用 customMessageHandler 从数据框中发送数据以创建 D3JS 树。

Path: I've managed to send data in data.frame format to a d3js tree. After you click the actionbutton, it changes the data in the data frame to JSON format, then sends it to the js file which creates the tree. The data of the tree is hard-coded on "server.r".

路径:我设法将 data.frame 格式的数据发送到 d3js 树。单击操作按钮后,它会将数据框中的数据更改为 JSON 格式,然后将其发送到创建树的 js 文件。树的数据硬编码在“server.r”上。

Where's the code? On my github! https://github.com/SweetBabyJesus/shiny-d3js-simple-binding

代码在哪里?在我的github上! https://github.com/SweetBabyJesus/shiny-d3js-simple-binding

Original: I created a tree algorithm based on CHAID to create insights from large datasets. People can upload their csv to the dashboard which then spits out the d3js tree:) The code is somewhat lengthy, therefore I cut it down for you and created a minimal code example.

原文:我创建了一个基于 CHAID 的树算法来从大型数据集中创建见解。人们可以将他们的 csv 上传到仪表板,然后仪表板会输出 d3js 树:) 代码有点冗长,因此我为您剪下它并创建了一个最小的代码示例。

Hope you like it.

希望你喜欢。

Cheers, Long

干杯,长