Я нацеливаюсь на конкретную сюжетную трассировку с помощью своих блестящих входных данных R, но мне бы хотелось сделать это, не обращаясь к данным, лежащим в основе всех других трассировок. Как показано ниже, обновление трассировки цилиндра зависит от состояния else. Я бы хотел этого избежать, поскольку в моих реальных данных у меня есть много других следов, а не тот, что здесь (след сферы).
library(shiny)
library(plotly)
library(purrr)
plot_cylinder <- function(x, y, z, radius, height, color = 'red') {
theta <- seq(0, 2*pi, length.out = 30)
z_cyl <- seq(z, z + height, length.out = 2)
x_cyl <- outer(x + radius * cos(theta), rep(1, length(z_cyl)))
y_cyl <- outer(y + radius * sin(theta), rep(1, length(z_cyl)))
z_cyl <- outer(rep(1, length(theta)), z_cyl)
list(
type = "surface",
x = x_cyl,
y = y_cyl,
z = z_cyl,
colorscale = list(c(0, color), c(1, color))
)
}
plot_sphere <- function(x, y, z, r, color = 'blue') {
theta <- seq(0, 2*pi, length.out = 30)
phi <- seq(0, pi, length.out = 30)
x_sphere <- x + r * outer(cos(theta), sin(phi))
y_sphere <- y + r * outer(sin(theta), sin(phi))
z_sphere <- z + r * outer(rep(1, length(theta)), cos(phi))
list(x = x_sphere, y = y_sphere, z = z_sphere, color = color)
}
# Static sphere data
sphere_radius <- 7.24
sphere_data <- plot_sphere(0, 0, 10, sphere_radius)
cylinder_data <- plot_cylinder(0, 0, 0, 3, 10)
ui <- fluidPage(
titlePanel("Cylinder Plotting"),
sidebarLayout(
sidebarPanel(
sliderInput("radius", "Cylinder Radius:", min = 1, max = 10, value = 3),
sliderInput("height", "Cylinder Height:", min = 1, max = 20, value = 10),
actionButton("initialize", "Initialize Cylinder")
),
mainPanel(
plotlyOutput("plot")
)
)
)
server <- function(input, output, session) {
plot <- plot_ly() |>
add_surface(x = sphere_data$x, y = sphere_data$y,
z = sphere_data$z, colors = sphere_data$color,
opacity = 0.5, name = "sphere") |>
add_surface(x = cylinder_data$x, y = cylinder_data$y,
z = cylinder_data$z, colorscale = cylinder_data$colorscale,
opacity = 0, name = "cylinder")
pb <- plotly_build(plot)
traces <- map(pb$x$data, "name")
output$plot <- renderPlotly({
plot
})
observeEvent(input$initialize, {
proxy <- plotlyProxy("plot", session)
plotlyProxyInvoke(proxy, "restyle", list(
opacity = lapply(traces, function(name) if (name %in% "cylinder") 0.1 else 0.5)
))
})
observeEvent(c(input$radius, input$height), {
proxy <- plotlyProxy("plot", session)
# Get the updated cylinder trace
cylinder_data <- plot_cylinder(0, 0, 0, input$radius, input$height)
# Update the trace with the new x, y, z values
plotlyProxyInvoke(proxy, "restyle", list(
x = lapply(traces, function(name) if (name %in% "cylinder") cylinder_data$x else sphere_data$x),
y = lapply(traces, function(name) if (name %in% "cylinder") cylinder_data$y else sphere_data$y),
z = lapply(traces, function(name) if (name %in% "cylinder") cylinder_data$z else sphere_data$z)
))
})
}
shinyApp(ui = ui, server = server)
извинения; исправленный
Если я правильно понял, вы хотели бы изменить трассировку по ее имени? Вот как получить сопоставление трассировки.имя/трассировка.индекс.
@ismirsehregal Похоже, некоторые пакеты изменились, и эти ответы устарели. Но чем могут помочь индексы? Могу ли я сделать plotlyProxyInvoke(proxy, "restyle", indices, x ...?
Да, функция изменения стиляplotly имеет параметр traceIndices. Сейчас у меня мало времени, но я постараюсь вернуться сюда, чтобы дать правильный ответ.
Итак, выше я привожу только список для параметра «обновление». Вместо этого я могу предоставить более простой список и еще один список индексов трассировки.
Точно, я оставил пример ниже.





Функция изменения стиля Plotly имеет параметр traceIndices:
Эффективное средство изменения атрибутов массива данных в существующий сюжет. При рестайлинге вы можете выбрать указанный изменения затрагивают столько трасс, сколько необходимо. Обновление предоставляется в виде отдельный объект и затронутые следы представлены в виде списка отслеживает индексы. Обратите внимание: если оставить индексы трассировки неуказанными, это предполагает что вы хотите изменить стиль всех трассировок.
Вот как обновить только данные первой трассировки (индекс: 0) с помощью plotlyProxyInvoke:
library(shiny)
library(plotly)
library(purrr)
plot_cylinder <- function(x, y, z, radius, height, color = 'red') {
theta <- seq(0, 2*pi, length.out = 30)
z_cyl <- seq(z, z + height, length.out = 2)
x_cyl <- outer(x + radius * cos(theta), rep(1, length(z_cyl)))
y_cyl <- outer(y + radius * sin(theta), rep(1, length(z_cyl)))
z_cyl <- outer(rep(1, length(theta)), z_cyl)
list(
type = "surface",
x = x_cyl,
y = y_cyl,
z = z_cyl,
colorscale = list(c(0, color), c(1, color))
)
}
plot_sphere <- function(x, y, z, r, color = 'blue') {
theta <- seq(0, 2*pi, length.out = 30)
phi <- seq(0, pi, length.out = 30)
x_sphere <- x + r * outer(cos(theta), sin(phi))
y_sphere <- y + r * outer(sin(theta), sin(phi))
z_sphere <- z + r * outer(rep(1, length(theta)), cos(phi))
list(x = x_sphere, y = y_sphere, z = z_sphere, color = color)
}
# Static sphere data
sphere_radius <- 7.24
sphere_data <- plot_sphere(0, 0, 10, sphere_radius)
cylinder_data <- plot_cylinder(0, 0, 0, 3, 10)
ui <- fluidPage(
titlePanel("Cylinder Plotting"),
sidebarLayout(
sidebarPanel(
sliderInput("radius", "Cylinder Radius:", min = 1, max = 10, value = 3),
sliderInput("height", "Cylinder Height:", min = 1, max = 20, value = 10)
),
mainPanel(
plotlyOutput("plot")
)
)
)
server <- function(input, output, session) {
plotly_object <- plot_ly(colors = sphere_data$color) |>
add_surface(x = cylinder_data$x, y = cylinder_data$y,
z = cylinder_data$z, colorscale = cylinder_data$colorscale,
opacity = 0.5, name = "cylinder") |>
add_surface(x = sphere_data$x, y = sphere_data$y,
z = sphere_data$z,
opacity = 0.5, name = "sphere")
pb <- plotly_build(plotly_object)
traces <- unlist(map(pb$x$data, "name"))
trace_indices <- setNames(seq_along(traces) - 1L, traces)
output$plot <- renderPlotly({
plotly_object
})
observeEvent(c(input$radius, input$height), {
proxy <- plotlyProxy("plot", session)
# Get the updated cylinder trace
cylinder_data <- plot_cylinder(0, 0, 0, input$radius, input$height)
# Update the trace with the new x, y, z values
plotlyProxyInvoke(proxy, "restyle", list(
x = list(cylinder_data$x),
y = list(cylinder_data$y),
z = list(cylinder_data$z)
), trace_indices[["cylinder"]])
# if you need to modify multiple traces at once (and leave others as they are):
# plotlyProxyInvoke(proxy, "restyle", list(
# x = list(cylinder_data$x, sphere_data$x + 100L),
# y = list(cylinder_data$y, sphere_data$y + 100L),
# z = list(cylinder_data$z, sphere_data$z + 100L)
# ), list(0L, 1L))
})
}
shinyApp(ui = ui, server = server)
Можете ли вы добавить индекс к сопоставлению имен трассировок из ответа , который вы предоставили выше? У меня много трасс, поэтому я не могу выбрать их просто по номеру, например 0L.
Просто используйте подход plotly_build, показанный в вашем примере. Пожалуйста, посмотрите мое редактирование.
Спасибо! Как бы вы подошли к этому в случае, если plotly_build не возвращает все следы? В частности, те, которые добавлены с plotlyProxyInvoke("addTraces"?
Для динамического обновления сопоставления имени трассировки/индекса трассировки потребуется обновленное решение JS (в вашем примере это не обязательно). Я еще не знаю. Я обновлю свой предыдущий ответ, как только у меня будет решение. Не уверен, когда у меня будет время снова покопаться в этом.
@its.me.adam Я только что обновил свой предыдущий ответ, добавив другой подход к извлечению имени трассировки/сопоставлению индекса трассировки.
Я не вижу, где в вашем коде определяется
traces. Я пропустил это?