Комбинирование ggplot2 и d3 (учебник gridSVG приводит к неинтерактивному изображению)
Я следую простому учебному пособию по интеграции ggplot2 и d3. Я специально работаю над методом 2 на этом учебном сайте (http://timelyportfolio.github.io/gridSVG_intro/). Я пытаюсь воспроизвести интерактивный сюжет (это последний сюжет на этой странице).
Я использовал один и тот же синтаксис и ввел его в файл .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>'
)
Единственным результатом, который я получаю от этого script, является файл plot1.svg. Однако, когда я открываю это в браузере (попробовал Safari и Google Chrome), это застойная версия изображения.
Я отправил бы электронное письмо автору самому. Но эта контактная информация недоступна. Он предназначен для простого учебника, поэтому я надеюсь, что это простое решение!
Я новичок в этом интерактивном компоненте. Тем не менее, я последовал инструкциям шаг за шагом и не знал, что я, возможно, пренебрег. Любая поддержка или информация, имеющие отношение к решению этой проблемы, будут очень оценены!
Ответы
Ответ 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
Итак, stdout перенаправляется в файл.
Я бы попытался немного перестроить код и написать все в файл 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")
Ответ 2
- Вам не хватает ссылки на библиотеку D3.js!
-
cat
, как и у вас, в обычном R script, просто выводит на консоль, как сказал @Mark.
Чтобы решить 1) ваш окончательный html-документ должен содержать: <script src="http://d3js.org/d3.v3.min.js"></script>
или эквивалент.
Чтобы решить 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, вы можете нажать "Вязать HTML". В противном случае вы можете использовать knitr::knit2html
или rmarkdown::render
с консоли или в другом .R script)
Ответ 3
Если вам не нравится предложение @arvi1000 использовать knitr
(что является хорошим), вы можете использовать sink(file = "myfile.html")
перед первым оператором cat()
, чтобы записать весь вывод в myfile.html
. В конце просто добавьте инструкцию sink()
, чтобы начать запись на стандартный вывод.
Как и @arvi1000, вам также не хватает ссылки на библиотеку D3.js. Следуя их указаниям, положите cat('<script src="http://d3js.org/d3.v3.min.js"></script>')
в качестве своего первого оператора cat()
. Вам также может потребоваться следовать рекомендациям @Mark о создании допустимого HTML файла.
Честно говоря, самый простой способ - использовать knitr
. Я включил содержимое действительного файла .Rmd, который будет создавать график D3.js. Просто запустите knitr::knit2html()
в файле .Rmd, содержащем следующий код. Я добавил несколько комментариев с моей лучшей интерпретацией того, что происходит (я никогда не делал ggplot для D3.js, поэтому для меня это был классный опыт!)
```{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>'
)
```