【问题标题】:Combining ggplot2 and d3 (gridSVG tutorial results in non-interactive image)结合ggplot2和d3(gridSVG教程导致非交互式图像)
【发布时间】:2015-12-10 20:43:09
【问题描述】:

我正在关注一个关于集成 ggplot2 和 d3 的简单教程。我正在本教程站点 (http://timelyportfolio.github.io/gridSVG_intro/) 上专门研究方法 2。我正在尝试复制交互式图(它是该页面上的最后一个图)。

我使用了它们相同的语法,并将其插入到一个 .R 文件中,如下所示:

library(gridSVG)
library(ggplot2)
library(XML)
library(rjson)

set.seed(955)
dat <- data.frame(cond = rep(c("A", "B"), each=10), xvar = 1:20 + rnorm(20,sd=3), yvar = 1:20 + rnorm(20,sd=3))

g4 = ggplot(dat, aes(x=xvar, y=yvar)) + geom_smooth() + geom_point(shape=19, aes(color = cond), size=5)
g4
g4.svg <- grid.export("plot1.svg",addClasses=TRUE)

cat(saveXML(g4.svg$svg))

cat(
  '<script> ourdata=',
  rjson::toJSON(apply(g4$data,MARGIN=1,FUN=function(x)return(list(x)))),
  '</script>'
)

cat(
  '<script> dataToBind = ',
  'd3.entries(ourdata.map(function(d,i) {return d[0]}))',
  '</script>'
)

cat(
  '<script>\n',
  'scatterPoints = d3.select(".points").selectAll("use");\n',
  'scatterPoints.data(dataToBind)',
  '</script>\n'
)

cat('<script>\n',
    'scatterPoints  
    .on("mouseover", function(d) {      
    //Create the tooltip label
    var tooltip = d3.select(this.parentNode).append("g");
    tooltip
    .attr("id","tooltip")
    .attr("transform","translate("+(d3.select(this).attr("x")+10)+","+d3.select(this).attr("y")+")")
    .append("rect")
    .attr("stroke","white")
    .attr("stroke-opacity",.5)
    .attr("fill","white")
    .attr("fill-opacity",.5)
    .attr("height",30)
    .attr("width",50)
    .attr("rx",5)
    .attr("x",2)
    .attr("y",5);
    tooltip.append("text")
    .attr("transform","scale(1,-1)")
    .attr("x",5)
    .attr("y",-22)
    .attr("text-anchor","start")
    .attr("stroke","gray")
    .attr("fill","gray")
    .attr("fill-opacity",1)
    .attr("opacity",1)
    .text("x:" + Math.round(d.value.xvar*100)/100);
    tooltip.append("text")
    .attr("transform","scale(1,-1)")
    .attr("x",5)
    .attr("y",-10)
    .attr("text-anchor","start")
    .attr("stroke","gray")
    .attr("fill","gray")      
    .attr("fill-opacity",1)
    .attr("opacity",1)
    .text("y:" + Math.round(d.value.yvar*100)/100);
    })              
    .on("mouseout", function(d) {       
    d3.select("#tooltip").remove();  
    });',
'</script>'
)

我从这个脚本得到的唯一输出是 plot1.svg 文件。但是,当我在浏览器中打开它时(尝试过 Safari 和 Google Chrome),它是图像的停滞版本。

我会亲自给作者发电子邮件。但该联系信息不可用。它是一个简单的教程,所以我希望它是一个简单的解决方案!

我对这个交互式组件很陌生。但是,我一步一步地按照说明进行操作,并且不确定我可能忽略了什么。非常感谢任何与解决此问题相关的支持或信息!

【问题讨论】:

  • 生成的文档是什么样的?是&lt;svg&gt; all the plot stuff &lt;/svg&gt; &lt;script&gt; all that javascript &lt;/script&gt;吗?
  • @Mark 感谢您的回复!我得到的唯一输出是 plot1.svg 文件。如果我在 Rstudio 中打开它,我看到它的一般格式是 ggplot 和 gridsvg 的东西和其他我不熟悉的文本 。搜索后,我没有看到任何 .
  • 您选择 d3 有什么特别的原因吗?还有另一个有趣的选择,例如喜欢htmlwidgets.org/showcase_plotly.html
  • @Mlavoie 感谢 cmets 和好问题(对不起我的延迟!)我实际上想要做的是创建一个交互式图,它是散点图和网络之间的东西:它在节点之间有边(网络),但每个节点都有一个特定的 x,y 位置(散点图)。我实际上首先尝试了 htmlwidgets!但似乎 htmlwidgets 不允许多个 geom (hrbrmstr.github.io/metricsgraphics)。所以,我被困在他们展示的美丽散点图中添加边缘 (hrbrmstr.github.io/metricsgraphics)。谢谢。
  • 很高兴看到您找到我的帖子。抱歉,我花了这么长时间才找到它。听起来你找到了答案。还有很多有用的新工具可以让这变得更容易。为了将来参考,如果您看到类似 username.github.io/repo 的内容,您可以通过将其翻译为 github.com/username/repo 找到所有来源,然后提交问题或查找联系信息。在这种情况下github.com/timelyportfolio/gridSVG_intro。我还应该补充一点,这个特定的帖子是用slidify 创建的。现在我使用rmarkdown

标签: r d3.js svg ggplot2 interactive


【解决方案1】:

编辑

所以,我最终安装了 R 来看看我原来的答案哪里出错了。我很接近。我错过了saveXML 的电话,正如@arvi1000 指出的那样,我没有找到d3 的来源。这是一个完整的固定示例。我刚刚用 R 3.2.3 运行它,它会在你的工作目录中生成一个myAwesomePlot.html

library(gridSVG)
library(ggplot2)
library(XML)
library(rjson)

set.seed(955)
dat <- data.frame(cond = rep(c("A", "B"), each=10), xvar = 1:20 + rnorm(20,sd=3), yvar = 1:20 + rnorm(20,sd=3))

g4 = ggplot(dat, aes(x=xvar, y=yvar)) + geom_smooth() + geom_point(shape=19, aes(color = cond), size=5)

# what does this line do?  It writes the SVG to the file "plot1.svg"?
g4.svg <- grid.export("", addClasses=TRUE)

# create a valid html file
cat("<html><head><script src='http://d3js.org/d3.v3.min.js'></script></head><body>", file="myAwesomePlot.html")

# I'm assuming this gets the svg content and can write it to a file
cat(saveXML(g4.svg$svg), file="myAwesomePlot.html", append=TRUE)

cat(
'<script> ourdata=',
rjson::toJSON(apply(g4$data,MARGIN=1,FUN=function(x)return(list(x)))),
'</script>', file="myAwesomePlot.html", append=TRUE
)

cat(
  '<script> dataToBind = ',
  'd3.entries(ourdata.map(function(d,i) {return d[0]}))',
  '</script>'
  , file="myAwesomePlot.html", append=TRUE)

cat(
  '<script>\n',
  'scatterPoints = d3.select(".points").selectAll("use");\n',
  'scatterPoints.data(dataToBind)',
  '</script>\n'
  , file="myAwesomePlot.html", append=TRUE)

cat('<script>\n',
    'scatterPoints  
    .on("mouseover", function(d) {      
    //Create the tooltip label
    var tooltip = d3.select(this.parentNode).append("g");
    tooltip
    .attr("id","tooltip")
    .attr("transform","translate("+(d3.select(this).attr("x")+10)+","+d3.select(this).attr("y")+")")
    .append("rect")
    .attr("stroke","white")
    .attr("stroke-opacity",.5)
    .attr("fill","white")
    .attr("fill-opacity",.5)
    .attr("height",30)
    .attr("width",50)
    .attr("rx",5)
    .attr("x",2)
    .attr("y",5);
    tooltip.append("text")
    .attr("transform","scale(1,-1)")
    .attr("x",5)
    .attr("y",-22)
    .attr("text-anchor","start")
    .attr("stroke","gray")
    .attr("fill","gray")
    .attr("fill-opacity",1)
    .attr("opacity",1)
    .text("x:" + Math.round(d.value.xvar*100)/100);
    tooltip.append("text")
    .attr("transform","scale(1,-1)")
    .attr("x",5)
    .attr("y",-10)
    .attr("text-anchor","start")
    .attr("stroke","gray")
    .attr("fill","gray")      
    .attr("fill-opacity",1)
    .attr("opacity",1)
    .text("y:" + Math.round(d.value.yvar*100)/100);
    })              
    .on("mouseout", function(d) {       
    d3.select("#tooltip").remove();  
    });',
'</script>'
, file="myAwesomePlot.html", append=TRUE)

# close out file
cat("</body></html>", file="myAwesomePlot.html", append=TRUE)

原答案

我已经有一段时间没有进行任何R 编程,但那些cat 函数看起来不正确。他们将写入标准输出,而不是写入文件。我的猜测是grid.export 只写入svg 文件,其他所有内容都被删除。乍一看,我假设您打算将这段代码运行为:

R myRCode.R > outPutFile.svg

以便标准输出重定向到文件中。

我会尝试稍微重构代码并将所有内容明确写入html 文件:

library(gridSVG)
library(ggplot2)
library(XML)
library(rjson)

set.seed(955)
dat <- data.frame(cond = rep(c("A", "B"), each=10), xvar = 1:20 + rnorm(20,sd=3), yvar = 1:20 + rnorm(20,sd=3))

g4 = ggplot(dat, aes(x=xvar, y=yvar)) + geom_smooth() + geom_point(shape=19, aes(color = cond), size=5)
g4

// what does this line do?  It writes the SVG to the file "plot1.svg"?
g4.svg <- grid.export("plot1.svg",addClasses=TRUE)

// create a valid html file
cat("<html><head></head><body>", file="myAwesomePlot.html")

// I'm assuming this gets the svg content and can write it to a file
cat(g4.svg$svg, file="myAwesomePlot.html")

cat(
  '<script> ourdata=',
  rjson::toJSON(apply(g4$data,MARGIN=1,FUN=function(x)return(list(x)))),
  '</script>', file="myAwesomePlot.html"
)

// etc, rest of JavaScript

// close out file
cat("</body></html>", file="myAwesomePlot.html")

【讨论】:

  • 感谢您的建议。我确实尝试对此进行重组,但似乎 cat(g4.svg$svg, file="myAwesomePlot.html") 行导致错误:“cat(list(...), file, sep,填充、标签、附加):参数 1(类型 'externalptr')不能由 'cat' 处理”我尝试使用 write()、dput() 等替换这个想法,但我无法将其写入html 文件。
  • 这是一个很好的答案,但是没有指向 d3.js 库的链接,我认为结果不起作用!
  • @LanneR,请参阅更新的答案,我很抱歉我没有尽快回复。感谢您给我一个再次启动R 的借口,我已经好几年没有使用它了。
  • @Mark 谢谢你的帮助!
【解决方案2】:
  • 您缺少指向 D3.js 库的链接!
  • cat,正如@Mark 所说,在纯 R 脚本中,只是输出到控制台。

要解决 1) 您的最终 html 文档必须包含:&lt;script src="http://d3js.org/d3.v3.min.js"&gt;&lt;/script&gt; 或等效项。

要解决 2),您可以使用 Rmarkdown .Rmd 文件并将您拥有的所有内容放在一个块中。

在带有 .Rmd 扩展名的文件中,以以下行开始块:

```{r, echo=FALSE, results='asis', warning=FALSE, message=FALSE}

接下来,请确保在此行中包含 D3 库:

cat('<script src="http://d3js.org/d3.v3.min.js"></script>')

然后在上面添加所有代码,然后结束块:

```

如果您在 Rstudio 中执行此操作,则可以点击“Knit HTML”。否则,您可以在控制台或其他 .R 脚本中使用 knitr::knit2htmlrmarkdown::render

【讨论】:

  • 感谢您的支持,对我帮助很大!
【解决方案3】:

如果您不喜欢@arvi1000 的建议使用knitr(这是一个很好的建议),您可以在您的第一个cat() 语句之前使用sink(file = "myfile.html") 将所有输出写入myfile.html。最后,只需添加语句sink() 即可开始写回标准输出。

就像@arvi1000 所说,您还缺少指向 D3.js 库的链接。按照他们的指示,将cat('&lt;script src="http://d3js.org/d3.v3.min.js"&gt;&lt;/script&gt;') 作为您的第一个cat() 声明。您可能还需要遵循 @Mark 的建议来创建有效的 HTML 文件。

老实说,最简单的方法是使用knitr。我已经包含了一个有效的 .Rmd 文件的内容,该文件将生成 D3.js 图。只需在包含以下代码的 .Rmd 文件上运行 knitr::knit2html()。我添加了一些对正在发生的事情的最佳解释的 cmets(我从未对 D3.js 做过 ggplot,所以这对我来说是一次很酷的学习体验!)

```{r echo = FALSE, message = FALSE, fig.keep = 'none'}
library(gridSVG)
library(ggplot2)
library(XML)
library(rjson)

# create a plot with some fake data

set.seed(955)
dat <- data.frame(cond = rep(c("A", "B"), each=10), xvar = 1:20 + rnorm(20,sd=3), yvar = 1:20 + rnorm(20,sd=3))

g4 = ggplot(dat, aes(x=xvar, y=yvar)) + geom_smooth() + geom_point(shape=19, aes(color = cond), size=5)

# you need to print the plot in order to capture it with grid.export
g4
# exporting the plot to a .svg file
g4.svg <- grid.export("plot1.svg",addClasses=TRUE)
```

```{r, echo=FALSE, results='asis', warning=FALSE, message=FALSE}

# load the d3.js script
cat('<script src="http://d3js.org/d3.v3.min.js"></script>')

# convert the svg file to an XML string and print it 
cat(saveXML(g4.svg$svg))

# looks like you convert the ggplot object data to JSON for use by d3.js
# looks like the aesthetics are included here? I don't seem them defined 
# anywhere else
cat(
  '<script> ourdata=',
  rjson::toJSON(apply(g4$data,MARGIN=1,FUN=function(x)return(list(x)))),
  '</script>'
)

# d3.js data definition
cat(
  '<script> dataToBind = ',
  'd3.entries(ourdata.map(function(d,i) {return d[0]}))',
  '</script>'
)

# d3.js scatter plot
cat(
  '<script>\n',
  'scatterPoints = d3.select(".points").selectAll("use");\n',
  'scatterPoints.data(dataToBind)',
  '</script>\n'
)

# d3.js code to support the hover tooltips (hover over a point on the plot)
# this is apparently ALL for the tooltip
cat('<script>\n',
    'scatterPoints  
    .on("mouseover", function(d) {      
    //Create the tooltip label
    var tooltip = d3.select(this.parentNode).append("g");
    tooltip
    .attr("id","tooltip")
    .attr("transform","translate("+(d3.select(this).attr("x")+10)+","+d3.select(this).attr("y")+")")
    .append("rect")
    .attr("stroke","white")
    .attr("stroke-opacity",.5)
    .attr("fill","white")
    .attr("fill-opacity",.5)
    .attr("height",30)
    .attr("width",50)
    .attr("rx",5)
    .attr("x",2)
    .attr("y",5);
    tooltip.append("text")
    .attr("transform","scale(1,-1)")
    .attr("x",5)
    .attr("y",-22)
    .attr("text-anchor","start")
    .attr("stroke","gray")
    .attr("fill","gray")
    .attr("fill-opacity",1)
    .attr("opacity",1)
    .text("x:" + Math.round(d.value.xvar*100)/100);
    tooltip.append("text")
    .attr("transform","scale(1,-1)")
    .attr("x",5)
    .attr("y",-10)
    .attr("text-anchor","start")
    .attr("stroke","gray")
    .attr("fill","gray")      
    .attr("fill-opacity",1)
    .attr("opacity",1)
    .text("y:" + Math.round(d.value.yvar*100)/100);
    })              
    .on("mouseout", function(d) {       
    d3.select("#tooltip").remove();  
    });',
'</script>'
)
```

【讨论】:

  • 谢谢@mikeck!这非常非常有帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-16
  • 1970-01-01
  • 1970-01-01
  • 2012-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多