R 灵活布局中的动态打印数:减少打印数时出错
我正在尝试设计一种新的方法,在一个闪亮的页面中创建一个可变数量的绘图,到目前为止它的方向是正确的,但是当我减少绘图数量时,我会在控制台中不断打印以下错误 警告:[]中出错:下标超出边界[无堆栈跟踪] 可用] 这与现在不再需要的绘图出错有关,但我不知道如何消除这个错误 设计基于: 我试图阻止我的应用程序打印任何错误,我想知道(也要学习)如何消除以下应用程序中的越界错误: 目前,在插入实际绘图进行测试之前,仅使用虚拟R 灵活布局中的动态打印数:减少打印数时出错,r,ggplot2,plot,shiny,R,Ggplot2,Plot,Shiny,我正在尝试设计一种新的方法,在一个闪亮的页面中创建一个可变数量的绘图,到目前为止它的方向是正确的,但是当我减少绘图数量时,我会在控制台中不断打印以下错误 警告:[]中出错:下标超出边界[无堆栈跟踪] 可用] 这与现在不再需要的绘图出错有关,但我不知道如何消除这个错误 设计基于: 我试图阻止我的应用程序打印任何错误,我想知道(也要学习)如何消除以下应用程序中的越界错误: 目前,在插入实际绘图进行测试之前,仅使用虚拟绘图 故意不使用网格排列解决方案,因为: 我计划在每个绘图上方添加按钮,用于选项、删
绘图
故意不使用网格排列解决方案,因为:
我计划在每个绘图上方添加按钮,用于选项、删除、保存等
-我想让每个绘图
都可以用svgpanzoom
缩放(用网格是不可能的。据我所知,排列ggplot2
)
需要(有光泽)
ui您不需要单独的observe
,因此我根据这里的一个示例重新编写了没有它的代码-。您可以使用n\u cols
max_plots <- 10;
n_cols = 3;
server <- function(input, output) {
output$plots <- renderUI({
plot_output_list <- list()
for(i in 1:ceiling(input$n/n_cols)) {
cols_ <- list();
for(j in 1:round((input$n/n_cols - (i - 1))*n_cols)) {
cols_ <- append(cols_,list(column(width = floor(12/n_cols), offset = 0, plotOutput(paste0("plot", (i-1)*n_cols+j)))));
}
plot_output_list <- append(plot_output_list, list(fluidRow(cols_, style = "width:1200px" )));
}
do.call(tagList, plot_output_list)
})
for (i in 1:max_plots) {
local({
my_i <- i; plotname <- paste0("plot", my_i)
output[[plotname]] <- renderPlot({
plot(1:my_i, 1:my_i, main = paste0("1:", my_i)
)
})
})
}
}
ui<- pageWithSidebar(
headerPanel("Dynamic number of plots"),
sidebarPanel(sliderInput("n", "Number of plots", value=1, min=1, max=max_plots)),
mainPanel(uiOutput("plots")
)
)
shinyApp(ui=ui,server=server)
max\u plots您不需要单独的observe
,因此我根据这里的一个示例重新编写了没有它的代码-。您可以使用n\u cols
max_plots <- 10;
n_cols = 3;
server <- function(input, output) {
output$plots <- renderUI({
plot_output_list <- list()
for(i in 1:ceiling(input$n/n_cols)) {
cols_ <- list();
for(j in 1:round((input$n/n_cols - (i - 1))*n_cols)) {
cols_ <- append(cols_,list(column(width = floor(12/n_cols), offset = 0, plotOutput(paste0("plot", (i-1)*n_cols+j)))));
}
plot_output_list <- append(plot_output_list, list(fluidRow(cols_, style = "width:1200px" )));
}
do.call(tagList, plot_output_list)
})
for (i in 1:max_plots) {
local({
my_i <- i; plotname <- paste0("plot", my_i)
output[[plotname]] <- renderPlot({
plot(1:my_i, 1:my_i, main = paste0("1:", my_i)
)
})
})
}
}
ui<- pageWithSidebar(
headerPanel("Dynamic number of plots"),
sidebarPanel(sliderInput("n", "Number of plots", value=1, min=1, max=max_plots)),
mainPanel(uiOutput("plots")
)
)
shinyApp(ui=ui,server=server)
max_plots稍微调整了Alex的答案,以稍微改进自动布局
max_plots <- 12;
shinyApp(
ui<- pageWithSidebar(
headerPanel("Dynamic number of plots"),
sidebarPanel(width = 2, sliderInput("n", "Number of plots", value=1, min=1, max=max_plots),
h4("Clicked points"),
verbatimTextOutput("click_info"),
h4('click points to see info'),
h4('select area to zoom'),
h4('Double click to unzoom')
),
mainPanel(uiOutput("plots")
)
),
server <- function(input, output) {
ranges <- reactiveValues()
values <- reactiveValues()
output$plots <- renderUI({
plot_output_list <- list()
n <- input$n
n_cols <- if(n == 1) {
1
} else if (n %in% c(2,4)) {
2
} else if (n %in% c(3,5,6,9)) {
3
} else {
4
}
Pwidth <- 900/n_cols
Pheigth <- 600/ceiling(n/n_cols) # calculate number of rows
for(i in 1:ceiling(input$n/n_cols)) {
cols_ <- list();
for(j in 1:round((input$n/n_cols - (i - 1))*n_cols)) {
# print((i-1)*n_cols+j)
n <- (i-1)*n_cols+j
cols_ <- append(cols_,list(column(width = floor(12/n_cols), offset = 0,
# uiOutput(paste('Button', n, sep = '')), ## problem part
plotOutput(paste0("plot", (i-1)*n_cols+j), width = Pwidth, height = Pheigth,
dblclick = paste0("plot", (i-1)*n_cols+j, '_dblclick'),
click = paste0("plot", (i-1)*n_cols+j, '_click'),
brush = brushOpts(
id = paste0("plot", (i-1)*n_cols+j, '_brush'),
resetOnNew = TRUE
))
)));
}
plot_output_list <- append(plot_output_list, list(fluidRow(cols_, style = "width:1000px" )));
}
do.call(tagList, plot_output_list)
})
observe({
lapply(1:input$n, function(i){
plotname <- paste0("plot", i)
output[[plotname]] <- renderPlot({
ggplot(mtcars, aes(wt, mpg, color = as.factor(cyl))) + geom_point() +
coord_cartesian(xlim =ranges[[paste('plot', i, 'x', sep = '')]],
ylim = ranges[[paste('plot', i, 'y', sep = '')]],
# expand = FALSE
) +
theme_classic() +
theme(legend.text=element_text(size=12),
legend.title=element_blank())
})
})
})
# }
output$click_info <- renderPrint({
nearPoints(mtcars, input$plot1_click, addDist = TRUE)
})
# When a double-click happens, check if there's a brush on the plot.
# If so, zoom to the brush bounds; if not, reset the zoom.
lapply(1:max_plots, function(i){
observeEvent(input[[paste('plot', i, '_dblclick', sep = '')]], {
brush <- input[[paste('plot', i, '_brush', sep = '')]]
if (is.null(brush)) {
ranges[[paste('plot', i, 'x', sep = '')]] <- NULL
ranges[[paste('plot', i, 'y', sep = '')]] <- NULL
values[[paste('brushedPoints', i, sep = '')]] <- NULL
}
})
})
lapply(1:max_plots, function(i){
observeEvent(input[[paste('plot', i, '_brush', sep = '')]], {
brush <- input[[paste('plot', i, '_brush', sep = '')]]
if (!is.null(brush)) {
ranges[[paste('plot', i, 'x', sep = '')]] <- c(brush$xmin, brush$xmax)
ranges[[paste('plot', i, 'y', sep = '')]] <- c(brush$ymin, brush$ymax)
values[[paste('brushedPoints', i, sep = '')]] <- nrow(brushedPoints(mtcars[mtcars$cyl == 4], input[[paste('plot', i, '_brush', sep = '')]]))
}
})
})
observe({
lapply(1:input$n, function(i){
output[[paste0('Button', i)]] <- renderUI({
actionButton(inputId = paste0('button', i), label = 'x')
})
})
})
}
)
max_plots稍微调整了Alex的答案,以稍微改进自动布局
max_plots <- 12;
shinyApp(
ui<- pageWithSidebar(
headerPanel("Dynamic number of plots"),
sidebarPanel(width = 2, sliderInput("n", "Number of plots", value=1, min=1, max=max_plots),
h4("Clicked points"),
verbatimTextOutput("click_info"),
h4('click points to see info'),
h4('select area to zoom'),
h4('Double click to unzoom')
),
mainPanel(uiOutput("plots")
)
),
server <- function(input, output) {
ranges <- reactiveValues()
values <- reactiveValues()
output$plots <- renderUI({
plot_output_list <- list()
n <- input$n
n_cols <- if(n == 1) {
1
} else if (n %in% c(2,4)) {
2
} else if (n %in% c(3,5,6,9)) {
3
} else {
4
}
Pwidth <- 900/n_cols
Pheigth <- 600/ceiling(n/n_cols) # calculate number of rows
for(i in 1:ceiling(input$n/n_cols)) {
cols_ <- list();
for(j in 1:round((input$n/n_cols - (i - 1))*n_cols)) {
# print((i-1)*n_cols+j)
n <- (i-1)*n_cols+j
cols_ <- append(cols_,list(column(width = floor(12/n_cols), offset = 0,
# uiOutput(paste('Button', n, sep = '')), ## problem part
plotOutput(paste0("plot", (i-1)*n_cols+j), width = Pwidth, height = Pheigth,
dblclick = paste0("plot", (i-1)*n_cols+j, '_dblclick'),
click = paste0("plot", (i-1)*n_cols+j, '_click'),
brush = brushOpts(
id = paste0("plot", (i-1)*n_cols+j, '_brush'),
resetOnNew = TRUE
))
)));
}
plot_output_list <- append(plot_output_list, list(fluidRow(cols_, style = "width:1000px" )));
}
do.call(tagList, plot_output_list)
})
observe({
lapply(1:input$n, function(i){
plotname <- paste0("plot", i)
output[[plotname]] <- renderPlot({
ggplot(mtcars, aes(wt, mpg, color = as.factor(cyl))) + geom_point() +
coord_cartesian(xlim =ranges[[paste('plot', i, 'x', sep = '')]],
ylim = ranges[[paste('plot', i, 'y', sep = '')]],
# expand = FALSE
) +
theme_classic() +
theme(legend.text=element_text(size=12),
legend.title=element_blank())
})
})
})
# }
output$click_info <- renderPrint({
nearPoints(mtcars, input$plot1_click, addDist = TRUE)
})
# When a double-click happens, check if there's a brush on the plot.
# If so, zoom to the brush bounds; if not, reset the zoom.
lapply(1:max_plots, function(i){
observeEvent(input[[paste('plot', i, '_dblclick', sep = '')]], {
brush <- input[[paste('plot', i, '_brush', sep = '')]]
if (is.null(brush)) {
ranges[[paste('plot', i, 'x', sep = '')]] <- NULL
ranges[[paste('plot', i, 'y', sep = '')]] <- NULL
values[[paste('brushedPoints', i, sep = '')]] <- NULL
}
})
})
lapply(1:max_plots, function(i){
observeEvent(input[[paste('plot', i, '_brush', sep = '')]], {
brush <- input[[paste('plot', i, '_brush', sep = '')]]
if (!is.null(brush)) {
ranges[[paste('plot', i, 'x', sep = '')]] <- c(brush$xmin, brush$xmax)
ranges[[paste('plot', i, 'y', sep = '')]] <- c(brush$ymin, brush$ymax)
values[[paste('brushedPoints', i, sep = '')]] <- nrow(brushedPoints(mtcars[mtcars$cyl == 4], input[[paste('plot', i, '_brush', sep = '')]]))
}
})
})
observe({
lapply(1:input$n, function(i){
output[[paste0('Button', i)]] <- renderUI({
actionButton(inputId = paste0('button', i), label = 'x')
})
})
})
}
)
max\u绘图嗯,我想我明白你为什么重写了几乎整个应用程序,但我通常不建议这样回答,因为如果你将解决方案隐藏在一个完整的代码转换之下,它可能不符合OPs最初的需要。然而,我确实找到了答案,并对你的答案做了一些更改,以使其正常工作。一件事是t您的答案不能以这种方式生成一个2*3的网格,因此我重新引入了代码来设置列的nr,就像我在问题中所做的那样。我将发布第二个答案来显示修改后的版本。谢谢Alex!亲爱的@Mark,如果您设置n_cols=3(我在我的答案中已经更改了它)你应该得到一个很好的2*3网格,不是吗?请看这里的屏幕截图:是的,但如果绘图的数量是8或4,它需要4列。别担心,我已经让它工作了。在我将我的代码版本发布到这里之前,我仍然在做一些编辑,但我仍然坚持在每个绘图上方放置额外的元素(请参阅更新的答案),当出现第二行绘图时,代码就会中断…嗯,我想我可以理解为什么你几乎重写了整个应用程序,但我通常不建议以这种方式回答,因为如果你将解决方案隐藏在完整的代码转换下,它可能不符合OPs的原始需要。不过,我确实找到了答案,并对你的应用程序进行了一些更改答案是这样的。有一点是,你的答案不能以这种方式生成一个漂亮的2*3网格,因此我重新引入了设置列数的代码,就像我在问题中所做的那样。我将发布第二个答案以显示修改后的版本。谢谢Alex!亲爱的@Mark,如果你设置n_cols=3(我在我的答案中更改了它)你应该得到一个很好的2*3网格,不是吗?请看这里的屏幕截图:是的,但如果绘图的数量是8或4,它需要4列。别担心,我已经让它工作了。在我将我的代码版本发布到这里之前,我仍然在做一些编辑,但我仍然坚持在每个绘图上方放置额外的元素(请参阅更新的答案),当出现第二行绘图时,代码将中断。。。