如何在 R 中旋转 3D Plotly,更新?

Posted

技术标签:

【中文标题】如何在 R 中旋转 3D Plotly,更新?【英文标题】:How to rotate 3D Plotly in R, update? 【发布时间】:2021-12-31 18:12:00 【问题描述】:

我想用 3D 表面制作动画情节

我试图复制这个例子

https://***.com/a/66117098/11555164

但我无法让它工作,没有旋转

library(shiny)
library(plotly)
library(htmlwidgets)

ui <- fluidPage(
  plotlyOutput("graph")
)

server <- function(input, output, session) 
  N <- 100
  x <- rnorm(N, mean = 50, sd = 2.3)
  y <- runif(N, min = 0, max = 100)
  z <- runif(N, min = 4, max = 70)
  luci.frame <- data.frame(x, y, z)
  
  output$graph <- renderPlotly(
    plot_ly(
      type = "scatter3d",
      mode = "markers",
      data = luci.frame,
      x = ~ x,
      y = ~ y,
      z = ~ z
    ) %>%
      layout(scene = list(camera = list(
        eye = list(
          x = 1.25,
          y = 1.25,
          z = 1.25
        ),
        center = list(x = 0,
                      y = 0,
                      z = 0)
      ))) %>%
      onRender("
      function(el, x)
  var id = el.getAttribute('id');
  var gd = document.getElementById(id);
  Plotly.plot(id).then(attach);
  function attach() 
    var cnt = 0;
    
    function run() 
      rotate('scene', Math.PI / 180);
      requestAnimationFrame(run);
     
    run();
    
    function rotate(id, angle) 
      var eye0 = gd.layout[id].camera.eye
      var rtz = xyz2rtz(eye0);
      rtz.t += angle;
      
      var eye1 = rtz2xyz(rtz);
      Plotly.relayout(gd, id + '.camera.eye', eye1)
    
    
    function xyz2rtz(xyz) 
      return 
        r: Math.sqrt(xyz.x * xyz.x + xyz.y * xyz.y),
        t: Math.atan2(xyz.y, xyz.x),
        z: xyz.z
      ;
    
    
    function rtz2xyz(rtz) 
      return 
        x: rtz.r * Math.cos(rtz.t),
        y: rtz.r * Math.sin(rtz.t),
        z: rtz.z
      ;
    
  ;

    ")
  )


shinyApp(ui, server)

我在 Rstudio 的控制台中没有收到任何错误

我也尝试隔离代码,并避免使用 Shiny(将其保存为 HTML) 在 Chrome 中,打开调试时出现渲染错误

这是第二个代码(没有闪亮的)

#library(shiny)
library(plotly)
library(htmlwidgets)

N <- 100
x <- rnorm(N, mean = 50, sd = 2.3)
y <- runif(N, min = 0, max = 100)
z <- runif(N, min = 4, max = 70)
luci.frame <- data.frame(x, y, z)

plot_ly(
  type = "scatter3d",
  mode = "markers",
  data = luci.frame,
  x = ~ x,
  y = ~ y,
  z = ~ z
) %>%
  layout(scene = list(camera = list(
    eye = list(
      x = 1.25,
      y = 1.25,
      z = 1.25
    ),
    center = list(x = 0,
                  y = 0,
                  z = 0)
  ))) %>%
  onRender("
      function(el, x)
  var id = el.getAttribute('id');
  var gd = document.getElementById(id);
  Plotly.plot(id).then(attach);
  function attach() 
    var cnt = 0;
    
    function run() 
      rotate('scene', Math.PI / 180);
      requestAnimationFrame(run);
     
    run();
    
    function rotate(id, angle) 
      var eye0 = gd.layout[id].camera.eye
      var rtz = xyz2rtz(eye0);
      rtz.t += angle;
      
      var eye1 = rtz2xyz(rtz);
      Plotly.relayout(gd, id + '.camera.eye', eye1)
    
    
    function xyz2rtz(xyz) 
      return 
        r: Math.sqrt(xyz.x * xyz.x + xyz.y * xyz.y),
        t: Math.atan2(xyz.y, xyz.x),
        z: xyz.z
      ;
    
    
    function rtz2xyz(rtz) 
      return 
        x: rtz.r * Math.cos(rtz.t),
        y: rtz.r * Math.sin(rtz.t),
        z: rtz.z
      ;
    
  ;

    ")

我在 onRender 上遗漏了什么?


更新: 感谢@ismirsehregal 将Plotly.plot 更改为Plotly.update 您可以检查接受的答案

如果你需要没有Shiny的版本,你可以使用这个代码

library(plotly)
library(htmlwidgets)

N <- 100
x <- rnorm(N, mean = 50, sd = 2.3)
y <- runif(N, min = 0, max = 100)
z <- runif(N, min = 4, max = 70)
luci.frame <- data.frame(x, y, z)

PLT <- plot_ly(
  type = "scatter3d",
  mode = "markers",
  data = luci.frame,
  x = ~ x,
  y = ~ y,
  z = ~ z
) %>%
  layout(scene = list(camera = list(
    eye = list(
      x = 1.25,
      y = 1.25,
      z = 1.25
    ),
    center = list(x = 0,
                  y = 0,
                  z = 0)
  ))) %>%
  onRender("
      function(el, x)
  var id = el.getAttribute('id');
  var gd = document.getElementById(id);
  Plotly.update(id).then(attach);
  function attach() 
    var cnt = 0;
    
    function run() 
      rotate('scene', Math.PI / 1000);
      requestAnimationFrame(run);
     
    run();
    
    function rotate(id, angle) 
      var eye0 = gd.layout[id].camera.eye
      var rtz = xyz2rtz(eye0);
      rtz.t += angle;
      
      var eye1 = rtz2xyz(rtz);
      Plotly.relayout(gd, id + '.camera.eye', eye1)
    
    
    function xyz2rtz(xyz) 
      return 
        r: Math.sqrt(xyz.x * xyz.x + xyz.y * xyz.y),
        t: Math.atan2(xyz.y, xyz.x),
        z: xyz.z
      ;
    
    
    function rtz2xyz(rtz) 
      return 
        x: rtz.r * Math.cos(rtz.t),
        y: rtz.r * Math.sin(rtz.t),
        z: rtz.z
      ;
    
  ;

    ")

PLT

【问题讨论】:

您的示例在 Shiny 中完美运行。因此,请尝试在您的服务器配置中查找错误 @black_paladin 和 ppriede 你用的是哪个版本的 R? R plotly recently updated 从 v1.57.1​​ 到 v2.5.1 的底层 plotly.js 库。这包括许多重大更改 - 此解决方案可能会受到影响。 是的 - 这里使用的 Plotly.plot() 函数是 dropped。 情节 4.10,闪亮 - 1.7.1 谢谢@ismirsehregal !!! 【参考方案1】:

R plotly 4.10.0 recently updated 从 v1.57.1​​ 到 v2.5.1 的底层 plotly.js 库。这包括许多重大更改 - 使用 2.0 版的 plotly.js 函数 Plotly.plot was dropped。

要恢复旧行为Plotly.plot 可以替换为Plotly.update

library(shiny)
library(plotly)
library(htmlwidgets)

ui <- fluidPage(
  plotlyOutput("graph")
)

server <- function(input, output, session) 
  N <- 100
  x <- rnorm(N, mean = 50, sd = 2.3)
  y <- runif(N, min = 0, max = 100)
  z <- runif(N, min = 4, max = 70)
  luci.frame <- data.frame(x, y, z)
  
  output$graph <- renderPlotly(
    plot_ly(
      type = "scatter3d",
      mode = "markers",
      data = luci.frame,
      x = ~ x,
      y = ~ y,
      z = ~ z
    ) %>%
      layout(scene = list(camera = list(
        eye = list(
          x = 1.25,
          y = 1.25,
          z = 1.25
        ),
        center = list(x = 0,
                      y = 0,
                      z = 0)
      ))) %>%
      onRender("
      function(el, x)
  var id = el.getAttribute('id');
  var gd = document.getElementById(id);
  Plotly.update(id).then(attach);
  function attach() 
    var cnt = 0;
    
    function run() 
      rotate('scene', Math.PI / 180);
      requestAnimationFrame(run);
     
    run();
    
    function rotate(id, angle) 
      var eye0 = gd.layout[id].camera.eye
      var rtz = xyz2rtz(eye0);
      rtz.t += angle;
      
      var eye1 = rtz2xyz(rtz);
      Plotly.relayout(gd, id + '.camera.eye', eye1)
    
    
    function xyz2rtz(xyz) 
      return 
        r: Math.sqrt(xyz.x * xyz.x + xyz.y * xyz.y),
        t: Math.atan2(xyz.y, xyz.x),
        z: xyz.z
      ;
    
    
    function rtz2xyz(rtz) 
      return 
        x: rtz.r * Math.cos(rtz.t),
        y: rtz.r * Math.sin(rtz.t),
        z: rtz.z
      ;
    
  ;

    ")
  )


shinyApp(ui, server)

【讨论】:

以上是关于如何在 R 中旋转 3D Plotly,更新?的主要内容,如果未能解决你的问题,请参考以下文章

仅在绘图中围绕 z 轴旋转

如何映射分类变量以在 R Plotly 中为 3D 散点图中的点轮廓着色?

Plotly React 在重新渲染之间保持缩放和旋转

如何更新第二个绘图轴 plotly Scatter3D subplots

如何转换 Excel 导入的数据以使用 Plotly 3D 曲面图?

[R中具有渲染图像的3D图[关闭]