当屏幕上显示四开幻灯片时,使用 echarts4r 制作动画图

Shu*_*ham 6 r echarts4r quarto

我正在 R Studio 中使用 Quarto 制作 Revealjs 演示文稿。我正在使用该包{echarts4r}来制作我的绘图。{echarts4r}带有默认动画。当我渲染演示文稿时,所有幻灯片的默认动画已加载。

我想在幻灯片处于活动状态时(即当幻灯片处于视图中时)运行默认的 echarts4r 动画,并在看到其他幻灯片时重置。有人可以帮我解决这个问题吗?

这是四开本演示文稿的代码。

---
title: "A Title"
subtitle: "A Subtitle"
author: "First Last"
institute: "Some Institute"
date: today
self-contained: true
format: revealjs
---


## Introduction

Hello There!


## Pie Chart

```{r}
library(tidyverse)
library(echarts4r)

data <- tibble(name = c("A", "B", "C", "D", "E", "F", "G"),
             number = c(9.7, 2.1, 2.1, 1.9, 1.9, 1.9, 80.4))

data %>% 
e_charts(name) %>% 
e_pie(number, radius = c("50%", "70%")) %>% 
e_legend(orient = "vertical", right = "5", top = "65%")
```
Run Code Online (Sandbox Code Playgroud)

Kat*_*Kat 1

这不是修复方法,也不是四开本方法。但是,此解决方法是动态的。由于@bretauv 的评论,我弄清楚了echarts4r两者都需要发生什么。highcharter

\n

分配元素 ID

\n

您对图表所做的唯一更改是您需要为它们提供一个元素 ID。ID 在整个演示文稿中必须是唯一的。使用“ec0”、“ec1”...等作为您的绘图 ID 是完全可以的。(您只需要对动画绘图执行此操作。)

\n

这是一个例子。

\n
```{r pltEchart, echo=F} \n\niris |> group_by(Species) |> \n  e_charts(Sepal.Length, elementId = "pltEcht") |>  # <--- id is here\n  e_scatter(Sepal.Width) \n\n```\n
Run Code Online (Sandbox Code Playgroud)\n

对于highcharter和大多数其他小部件样式包,添加元素 id 不是内置的。以下是为 添加 id 的方法highcharter

\n
```{r penquins,echo=F}\n\nhc <- hchart(penguins, "scatter", \n             hcaes(x = flipper_length_mm, y = bill_length_mm, group = species))\n\nhc$elementId <- "hc_id"\n\nhc\n\n```\n
Run Code Online (Sandbox Code Playgroud)\n

重新动画绘图

\n

对于每个echarts4r图,要应用下一部分,您需要它所在的幻灯片及其元素 id

\n

对于highcharter,您还需要知道它在演示文稿中出现的顺序(仅就其他绘图而言highcharter)。

\n

无论您使用不太动态的方法还是更动态的方法,剩下的就是向 QMD 添加 JS 块。该块可以位于脚本文件中的任何位置。(我通常将任何 JS 放在我的 RMD/QMD 的最后。)

\n
\n

如果您不知道,JS 是内置的。您不需要做任何新的或不同的事情就可以以这种方式使用 JS。但是,如果您要在源窗格中运行此块,它将不会执行任何操作。您必须渲染它才能看到它的实际效果。如果您最终更改了 JS 或编写了更多自己的代码,请不要假设您在 RStudio 的查看器或演示窗格中看到的内容与您在浏览器中看到的内容完全相同。

\n
\n

在您做出决定之前,我会浏览一下您必须对这两种方法进行更改的内容!如果您不习惯使用 JS,那么第二个绝对是您最好的选择。

\n

每个重新动画情节的每个演示文稿的定制信息

\n

对于您重新设置动画的每个绘图,您必须确定:

\n
    \n
  1. 幻灯片标题或幻灯片编号的子字符串(其中幻灯片编号通过 YAML 声明包含在幻灯片中)
  2. \n
  3. 绘图元素 ID
  4. \n
  5. 绘图顺序(绘图顺序或顺序仅适用于 Highcharts)。
  6. \n
\n

对于幻灯片标题子字符串,如您在 JS 中使用的那样:

\n
    \n
  • 它是基于后台分配的哈希或锚点的标题子字符串
  • \n
  • 子字符串全部小写
  • \n
  • 没有特殊字符
  • \n
  • 该幻灯片必须是唯一的
  • \n
\n

如果您不确定使用什么或如何查找独特的\xe2\x80\x94,有一种简单的方法可以找到该信息。如果您从 RStudio 中的演示文稿窗格在浏览器中打开演示文稿,幻灯片的 URL 将与此类似。

\n

每张幻灯片都将具有相同的 URL 初始组件 ,http://localhost:7287/#/但除此之外,每张幻灯片都将是唯一的

\n
http://localhost:7287/#/another-hc\n
Run Code Online (Sandbox Code Playgroud)\n

# 后面的字符串是该幻灯片的标题锚。您可以准确使用 URL 中的内容(#/ 之后)。

\n

把它放在一起

\n

这会连续检查幻灯片是否已更改(10 毫秒间隔)。如果幻灯片发生变化,它会检查三个绘图之一是否在该幻灯片上。如果是,则重新开始幻灯片动画。

\n
您需要在 JS 中个性化什么
\n

ecReloaderforcharts4r有 2 个参数:

\n
    \n
  1. 标题子字符串或幻灯片编号
  2. \n
  3. 绘图元素 ID
  4. \n
\n

hcReloaderforhighcharter有 3 个参数:

\n
    \n
  1. 标题子字符串或幻灯片编号
  2. \n
  3. 绘图元素 ID
  4. \n
  5. 绘图序列号
  6. \n
\n

setInterval函数(名为 的块)中customizeMe,您需要为要重新设置动画的每个图编写一个函数调用。在我的示例中,我重新设置了三个图。这是您修改的唯一部分。(请注意,每行都需要结束带分号。)

\n
  ecReloader('code', 'pltEcht');        /* slide title. plot element id */\n  hcReloader('highchart', 'hc_id', 0);  /* slide title, id, sequence */\n  hcReloader(6, 'another_hc_id', 1);    /* slide number, id, sequence */\n
Run Code Online (Sandbox Code Playgroud)\n
\n     /* assuming only one on slide */\nsetInterval(function() { \n  var current = window.location.hash;\n  tellMe = keepLooking(current);\n  if(tellMe) {                        /* if the slide changed, then look */\n  ecReloader('code', 'pltEcht');\n  hcReloader('highchart', 'hc_id', 0);\n  hcReloader(6, 'another_hc_id', 1);    /* second highcharter plot */\n  }\n}, 10); // check every 10 milliseconds\n\n
Run Code Online (Sandbox Code Playgroud)\n

在您的演示文稿中,您需要使用两个 JS 块才能完成这项工作。(块名称是customizeMereloaders。)

\n
\n

我确信有一种方法可以自定义幻灯片编号的外观;不过,此代码是基于默认值的。

\n
\n

这是完成这项工作的所有 JS。

\n
\n```{r customizeMe,echo=F,engine='js'}\n\n     /* assuming only one on slide */\nsetInterval(function() { \n  var current = window.location.hash;\n  tellMe = keepLooking(current);\n  if(tellMe) {                        /* if the slide changed, then look */\n  ecReloader('code', 'pltEcht');\n  hcReloader('highchart', 'hc_id', 0);\n  hcReloader(6, 'another_hc_id', 1);    /* second highcharter plot */\n  }\n}, 10); // check every 10 milliseconds\n\n```\n    \n```{r reloaders,echo=F,engine='js'}\n\n// more dynamic; a couple of key words for each plot\n\n// multiple options for addressing Echarts plots\nfunction ecReloader(slide, id) {\n  /* slide (string)  slide title unique substring (check URL when on the slide)\n                --or-- \n           (integer) as in the slide number\n     id (string)     element id of the plot to change */\n  if(typeof slide === 'number') {                        // slide number provided\n    which = document.querySelector('div.slide-number');  // page numbers like '6 / 10'\n    validator = Number(which.innerText.split(' ')[0]);\n    if(slide === validator) {                            // slide number matches current slide\n      var ec = document.getElementById(id);\n      ele = echarts.init(ec, get_e_charts_opts(ec.id));\n      thatsIt = get_e_charts_opts(ec.id);          /* store data */\n      ele.setOption({xAxis: {}, yAxis: {}}, true); /* remove data */\n      ele.setOption(thatsIt, false);               /* append original data */\n    }\n  } else {                                               // unique element in slide title \n    if(window.location.hash.indexOf(slide) > -1) {\n      var ec = document.getElementById(id);\n      ele = echarts.init(ec, get_e_charts_opts(ec.id));\n      thatsIt = get_e_charts_opts(ec.id);          /* store data */\n      ele.setOption({xAxis: {}, yAxis: {}}, true); /* remove data */\n      ele.setOption(thatsIt, false);               /* append original data */\n    }\n  }\n}\n\n// multiple options for addressing Highcharts plots, assumes 1 chart per slide!\nfunction hcReloader(slide, id, order) {\n  /* slide (string)  slide title unique substring (check URL when on the slide)\n                --or-- \n           (integer) as in the slide number\n     id (string)     element id of the plot to change\n     order (integer) 0 through the number of charts in the plot, which one is this plot?\n                  (in order of appearance) */\n  if(typeof slide === 'number') {                        // slide number provided\n    which = document.querySelector('div.slide-number');  // page numbers like '6 / 10'\n    validator = Number(which.innerText.split(' ')[0]);\n    if(slide === validator) {                            // slide number matches current slide\n      var hc1 = document.getElementById(id).firstChild;  \n      Highcharts.chart(hc1, Highcharts.charts[order].options); // re-draw plot\n    }\n  } else {                                               // unique element in slide title\n    if(window.location.hash.indexOf(slide) > -1) {\n      var hc1 = document.getElementById(id).firstChild;\n      Highcharts.chart(hc1, Highcharts.charts[order].options); // re-draw plot\n    }\n  }\n}\n\n/* Current Slide Section (bookmark #) */\noHash = window.location.hash;\n\n/* check if the slide has changed */\nfunction keepLooking (nHash) { \n  if(oHash === nHash) {\n    return false;\n  } else {\n    oHash = nHash;          /* if slide changed, reset the value of oHash */\n    return true;\n  }\n}\n\n```\n
Run Code Online (Sandbox Code Playgroud)\n

这是我用来创建和测试它的完整 QMD 脚本,以便您可以了解它是如何工作的。

\n
\n---\ntitle: "Untitled"\nformat: \n  revealjs:\n    slide-number: true\neditor: source\n---\n\n## Quarto\n\n```{r basics, echo=F}\nlibrary(echarts4r)\nlibrary(tidyverse)\nlibrary(htmltools)\nlibrary(highcharter)\n\n```\n\n```{r data, include=F,echo=F}\n\ndata("iris")\ndata(penguins, package = "palmerpenguins") \n\n```\n\nword\n\n## Bullets\n\nmore words\n\n## More Plots; How about Highcharter?\n\n```{r penquins,echo=F}\n\nhc <- hchart(penguins, "scatter", \n             hcaes(x = flipper_length_mm, y = bill_length_mm, group = species))\n\nhc$elementId <- "hc_id"\n\nhc\n\n```\n\n## Code\n\n`echarts` style plot\n\n```{r pltEcht, echo=F} \n\niris |> group_by(Species) |> \n  e_charts(Sepal.Length, elementId = "pltEcht") |> e_scatter(Sepal.Width) \n\n```\n\n\n## Another HC\n\n```{r penquins2,echo=F}\n\nhc2 <- hchart(iris, "scatter",\n              hcaes(x = Sepal.Length, y = Sepal.Width, group = Species))\n\nhc2$elementId <- "another_hc_id"\n\nhc2\n\n```\n\n\n```{r customizeMe,echo=F,engine='js'}\n\n     /* assuming only one on slide */\nsetInterval(function() { \n  var current = window.location.hash;\n  tellMe = keepLooking(current);\n  if(tellMe) {                        /* if the slide changed, then look */\n  ecReloader('code', 'pltEcht');\n  hcReloader('highchart', 'hc_id', 0);\n  hcReloader(6, 'another_hc_id', 1);    /* second highcharter plot */\n  }\n}, 10); // check every 10 milliseconds\n\n```\n\n```{r reloaders,echo=F,engine='js'}\n\n// more dynamic; a couple of key words for each plot\n\n// multiple options for addressing Echarts plots\nfunction ecReloader(slide, id) {\n  /* slide (string)  slide title unique substring (check URL when on the slide)\n                --or-- \n           (integer) as in the slide number\n     id (string)     element id of the plot to change */\n  if(typeof slide === 'number') {                        // slide number provided\n    which = document.querySelector('div.slide-number');  // page numbers like '6 / 10'\n    validator = Number(which.innerText.split(' ')[0]);\n    if(slide === validator) {                            // slide number matches current slide\n      var ec = document.getElementById(id);\n      ele = echarts.init(ec, get_e_charts_opts(ec.id));\n      thatsIt = get_e_charts_opts(ec.id);          /* store data */\n      ele.setOption({xAxis: {}, yAxis: {}}, true); /* remove data */\n      ele.setOption(thatsIt, false);               /* append original data */\n    }\n  } else {                                               // unique element in slide title \n    if(window.location.hash.indexOf(slide) > -1) {\n      var ec = document.getElementById(id);\n      ele = echarts.init(ec, get_e_charts_opts(ec.id));\n      thatsIt = get_e_charts_opts(ec.id);          /* store data */\n      ele.setOption({xAxis: {}, yAxis: {}}, true); /* remove data */\n      ele.setOption(thatsIt, false);               /* append original data */\n    }\n  }\n}\n\n// multiple options for addressing Highcharts plots, assumes 1 chart per slide!\nfunction hcReloader(slide, id, order) {\n  /* slide (string)  slide title unique substring (check URL when on the slide)\n                --or-- \n           (integer) as in the slide number\n     id (string)     element id of the plot to change\n     order (integer) 0 through the number of charts in the plot, which one is this plot?\n                  (in order of appearance) */\n  if(typeof slide === 'number') {                        // slide number provided\n    which = document.querySelector('div.slide-number');  // page numbers like '6 / 10'\n    validator = Number(which.innerText.split(' ')[0]);\n    if(slide === validator) {                            // slide number matches current slide\n      var hc1 = document.getElementById(id).firstChild;  \n      Highcharts.chart(hc1, Highcharts.charts[order].options); // re-draw plot\n    }\n  } else {                                               // unique element in slide title\n    if(window.location.hash.indexOf(slide) > -1) {\n      var hc1 = document.getElementById(id).firstChild;\n      Highcharts.chart(hc1, Highcharts.charts[order].options); // re-draw plot\n    }\n  }\n}\n\n/* Current Slide Section (bookmark #) */\noHash = window.location.hash;\n\n/* check if the slide has changed */\nfunction keepLooking (nHash) { \n  if(oHash === nHash) {\n    return false;\n  } else {\n    oHash = nHash;          /* if slide changed, reset the value of oHash */\n    return true;\n  }\n}\n\n```  \n
Run Code Online (Sandbox Code Playgroud)\n

您可以将 JS 放在 QMD 中的任何位置。

\n

如果您看到加载延迟(闪烁之类的事情),您可以降低间隔之间的毫秒数。(该数字位于函数末尾setInterval,您可以在其中看到}, 10).

\n

如果出现问题,只需将 JS 设置为eval=F. 您实际上并没有永久更改演示文稿中的任何内容。

\n