I have, once again, run into some problems with Shiny. When I run my app I get the following message:
Warning: Error in tapply: arguments must have same length
[No stack trace available]
Still quite new to R, I dont understand why I get this warning. I've been randomly experiement with aes_string instead of aes in the graph, but I can't find any workable solution. I would be so grateful if someone could help me.
library(shiny)
library(tidyverse)
df_bransch <- data_frame(
kommun = c("Bjuv", "Bjuv", "Bjuv", "Bromölla", "Bromölla", "Bromölla", "Båstad", "Båstad", "Båstad", "Helsingborg", "Helsingborg", "Helsingborg"),
bransch = c("Besöksnäring", "Byggnadsmaterial", "Fastigheter", "Besöksnäring", "Byggnadsmaterial", "Fastigheter",
"Besöksnäring", "Byggnadsmaterial", "Fastigheter", "Besöksnäring", "Byggnadsmaterial", "Fastigheter"),
Anställda = c(46, 369, 36, 57, 40, 36, 525, 5, 1133, 2392, 195, 1042),
Förädlingsvärde = c(20724, 579892, 91406, 26097, 136440, 51731, 252891, 3852, 1343391, 1257333, 176595, 5017640))
ui <- fluidPage(
navbarPage(title = "TEST", id = "nav",
tabPanel("Branschstruktur",
sidebarLayout(
sidebarPanel(selectInput("kom", "Kommun", choices = unique(df_bransch$kommun), selected = "Malmö"),
varSelectInput("var", "Variabel", df_bransch[c(3,4)])),
mainPanel(plotOutput("plot"))),
tabPanel("Utveckling"))))
server <- function(input, output, session) {
df <- reactive({df_bransch %>%
req(input$var, input$kom) %>%
filter(kommun == input$kom)
})
output$plot <- renderPlot({
ggplot(df(), aes(x = reorder(bransch, input$var), y = input$var)) +
geom_bar(position = "dodge", stat = "identity") +
labs(title = paste0("Branschstruktur, ", input$kom, " år 2018"),
subtitle = paste0("Variabel: ", input$var),
caption = "Källa: Bisnode") +
coord_flip()
})
}
shinyApp(ui, server)
Please make the following change:
ggplot(df(), aes(x = reorder(bransch, df()[[input$var]]), y = df()[[input$var]]))
Also, add to labs() the code y = "Bransch", x = as.name(input$var), to give proper labels on x and y axis. Then you will get the output as:
Related
I am creating two interactive plots in R Shiny and while I can get one plot to show up and work, the second plot keeps giving me the "Warning: Error in [.data.frame: undefined columns selected" and will not appear.
I have looked at many solutions online and none so far have been able to help me or fix my issue.
I am having a hard time seeing how my columns are undefined, but I am also relatively new to R Shiny and could be easily overlooking something, so I was hoping someone could help me figure this out.
Here is my code:
library(shiny)
library(dplyr)
library(readr)
library(ggplot2)
library(tidyverse)
age <- c(1, 4, 7,10, 15)
v_m_1 <- c(10, 14, 17, 20, 25)
v_m_2 <- c(9, 13, 16, 19, 24)
sex <- c("F", "M","U", "F", "M")
P_v_rn <- c(0.11, 0.51, 0.61, 0.91, 1)
C_v_rn <- c(11.1, 15.1, 16.1, 19.1, 20.1)
P_v_rk <- c(0.11, 0.51, 0.61, 0.91, 1)
B_v_rk <- c("Low", "Medium", "Medium", "High", "High")
df_test <- data.frame(age, v_m_1, v_m_2, sex, P_v_rn, C_v_rn, P_v_rk, B_v_rk)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Test"),
# Sidebar with a slider input for number of bins
verticalLayout(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "xvar",
label = "Choose X variable", #All variables are numeric
c("Age" = 1),
selected = 1),
selectInput(inputId = "yvar",
label = "Choose bone variable", #All variables are numeric
c("v_m_1" = 2,
"v_m_2" = 3),
selected = 2),
checkboxInput(inputId = "regression",
label = "Fit LOESS - By Sex",
value = FALSE)),
mainPanel(
plotOutput('dataplot1')
)
),
tags$hr(),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "xvar_name",
label = "Choose X variable", #All variables are numeric
c("Age" = 1),
selected = 1),
selectInput(inputId = "yvar_name",
label = "Choose Y variable", #The first variable option is numeric, the rest are factors
c("P_v_rk" = 7,
"B_v_rk" = 8),
selected = 7),
selectInput(inputId = "zvar_name",
label = "Choose Z variable", #All variables are numeric
c("C_v_rn" = 6,
"P_v_rn" = 5),
selected = 6)),
# Show a plot of the generated distribution
mainPanel(
plotOutput('dataplot2')
)
),
tags$hr(),
))
# Define server logic required to draw a scatterplot
server <- function(input, output) {
df <- df_test %>%
select(age, v_m_1, v_m_2, sex, P_v_rn, C_v_rn, P_v_rk, B_v_rk)
df$B_v_rk <- as.factor(df$B_v_rk)
#Growth Curve
output$dataplot1 <- renderPlot({
xvar <- as.numeric(input$xvar)
yvar <- as.numeric(input$yvar)
Sex <- as.factor(df$sex)
p <- ggplot() +
aes(x = df[ ,xvar],
y = df[ ,yvar],
col = sex) +
geom_point(alpha = 0.5, aes(size = 1.5)) + # 50% transparent
labs(x = names(df[xvar]),
y = names(df[yvar])) +
theme_classic()
if(input$regression) {
# add a line to the plot
p <- p + geom_smooth()
}
p # The plot ('p') is the "return value" of the renderPlot function
})
#Environmental metrics
output$dataplot2 <- renderPlot({
xvar_name <- input$xvar_name
yvar_name <- input$yvar_name
zvar_name <- input$zvar_name
#Color palette for ggplots as blue color range was difficult for me
fun_color_range <- colorRampPalette(c("yellow", "red"))
my_colors <- fun_color_range(20)
p2 <- ggplot() +
aes(x = df[ ,xvar_name],
y = df[ ,yvar_name],
col = df[ ,zvar_name]) +
geom_point(alpha = 0.5, aes(size = 1.5)) + # 50% transparent
scale_colour_gradientn(colors = my_colors) +
labs(x = names(df[xvar_name]),
y = names(df[yvar_name])) +
theme_classic()
p2 # The plot ('p2') is the "return value" of the renderPlot function
})
}
# Run the application
shinyApp(ui = ui, server = server)
Again the first plot works fine, it is the second plot that is producing an error code.
I guess I am confused as the code for the first plot works fine but it won't work for the second plot.
For reference, this is the layout I want, except I want another plot in the error code location.
My guess is that the bug is in the line with names(df[xvar_name]). If df is a data frame, this will throw the error you quoted. To subset a data frame with indices or column names you either use double brackets (df[[...]]) or a comma (df[ ..., ... ]). I think you meant names(df[ , xvar_name ]). This error is repeated on the line below as well.
In general, to identify the place where the problem occurs, use browser() in your code.
I get a warning (Warning: Removed 2 rows containing missing values (geom_path).), which I don't want to have for the following code:
library(shiny)
library(ggplot2)
library(scales)
ui <- navbarPage("Test",
tabPanel("Test_2",
fluidPage(
fluidRow(
column(width = 12, plotOutput("plot", width = 1200, height = 600))
),
fluidRow(
column(width = 12, sliderInput("slider",
label = "Range [h]",
min = as.POSIXct("2019-11-01 00:00"),
max = as.POSIXct("2019-11-01 07:00"),
value = c(as.POSIXct("2019-11-01 00:00"),as.POSIXct("2019-11-01 07:00"))))
))))
server <- function(input, output, session) {
df <- data.frame("x" = c(as.POSIXct("2019-11-01 00:00"),as.POSIXct("2019-11-01 01:00"),
as.POSIXct("2019-11-01 02:00"),as.POSIXct("2019-11-01 03:00"),
as.POSIXct("2019-11-01 04:00"),as.POSIXct("2019-11-01 05:00"),
as.POSIXct("2019-11-01 06:00"),as.POSIXct("2019-11-01 07:00")),
"y" = c(0,1,2,3,4,5,6,7))
observe({
len_date_list <- length(df$x)
min_merge_datetime <- df$x[1]
max_merge_datetime <- df$x[len_date_list]
updateSliderInput(session, "slider",
min = as.POSIXct(min_merge_datetime),
max = as.POSIXct(max_merge_datetime),
timeFormat = "%Y-%m-%d %H:%M")
})
output$plot <- renderPlot({
in_slider_1 <- input$slider[1]
in_slider_2 <- input$slider[2]
ggplot(data=df, aes(x, y, group = 1)) +
theme_bw() +
geom_line(color="black", stat="identity") +
# geom_point() +
scale_x_datetime(labels = date_format("%m-%d %H:%M"),
limits = c(
as.POSIXct(in_slider_1),
as.POSIXct(in_slider_2)))
})
}
shinyApp(server = server, ui = ui)
It seems to be an general problem with the "missing values", because I have found a lot of similar questions. In this question it is explained that it must be the range of the axis. So in my case I'm sure that it is because of the limits in scale_x_datetime.
scale_x_datetime(labels = date_format("%m-%d %H:%M"),
limits = c(
as.POSIXct(in_slider_1),
as.POSIXct(in_slider_2)))
But I didn't found an answered question when scale_x_datetime, as.POSIXct and a slider is used.
BTW: If I comment out "geom_point" I get a further similar warning.
I think it is because you haven't filtered df so when the limits of scale_x_datetime come along they remove the rows in df that don't fit between the slider parameters. I added this:
df %>% filter(between(x, in_slider_1, in_slider_2))
which seems to remove the issue for me. Please test. Just to mention that I did have some time zone problems.
Full code below:
library(shiny)
library(ggplot2)
library(scales)
ui <- navbarPage("Test",
tabPanel("Test_2",
fluidPage(
fluidRow(
column(width = 12, plotOutput("plot", width = 1200, height = 600))
),
fluidRow(
column(width = 12, sliderInput("slider",
label = "Range [h]",
min = as.POSIXct("2019-11-01 00:00"),
max = as.POSIXct("2019-11-01 07:00"),
value = c(as.POSIXct("2019-11-01 00:00"),as.POSIXct("2019-11-01 07:00"))))
))))
server <- function(input, output, session) {
df <- data.frame("x" = c(as.POSIXct("2019-11-01 00:00"),as.POSIXct("2019-11-01 01:00"),
as.POSIXct("2019-11-01 02:00"),as.POSIXct("2019-11-01 03:00"),
as.POSIXct("2019-11-01 04:00"),as.POSIXct("2019-11-01 05:00"),
as.POSIXct("2019-11-01 06:00"),as.POSIXct("2019-11-01 07:00")),
"y" = c(0,1,2,3,4,5,6,7))
observe({
len_date_list <- length(df$x)
min_merge_datetime <- df$x[1]
max_merge_datetime <- df$x[len_date_list]
updateSliderInput(session, "slider",
min = as.POSIXct(min_merge_datetime),
max = as.POSIXct(max_merge_datetime),
timeFormat = "%Y-%m-%d %H:%M")
})
output$plot <- renderPlot({
in_slider_1 <- input$slider[1]
in_slider_2 <- input$slider[2]
ggplot(data=df %>% filter(between(x, in_slider_1, in_slider_2)), aes(x, y, group = 1)) +
theme_bw() +
geom_line(color="black", stat="identity") +
# geom_point() +
scale_x_datetime(labels = date_format("%m-%d %H:%M"),
limits = c(
as.POSIXct(in_slider_1),
as.POSIXct(in_slider_2)))
})
}
shinyApp(server = server, ui = ui)
It looks like you could now actually remove the scale_x_datetime completely and just have:
ggplot(data=df %>% filter(between(x, in_slider_1, in_slider_2)), aes(x, y, group = 1)) +
theme_bw() +
geom_line(color="black", stat="identity")
I know this question already has an answer, but this is another possible solution for you.
If you just want to get rid of it, that implies to me that you are OK with the output. Then you can try the following:
Add na.rm=TRUE to geom_line like : geom_line(..., na.rm=TRUE )
This explicitly tells geom_line and geom_path that is OK to remove NA values.
Reasoning with the warning:
Warning of: Removed k rows containing missing values (geom_path)
This tells you mainly 3 things:
geom_path is being called by another geom_something which is firing the warning. In your case, is geom_line.
It already removed k rows. So if the output is as desired, then you want to those rows removed.
The reason for removal is that some values ARE missing (NA).
What the warning doesn't tells you is WHY those rows have missing (NA) values.
You know that the reason comes from scale_x_datetime. Mainly from the limits argument. In a sense of (X,Y) pairs to be drawn, you set the X scale to values where is no "Y", or Y=NA. Your scale may be continuous, but your data is not. You may want to set a larger scale for a different number of reasons, but ggplot will always find that there isn't an associated Y value, and it makes a unilateral decision and fires a warning instead of an error.
Hopefully, times will come when Errors and Warnings highlights intuitive, language-independent calling trace to the emitter and a link to a correctly explained site with common mistakes, etc.
I am trying to use ggplot2 with a reactive object in shiny.
So, I understand that reactive gives a reactive object that needs to be changed to be a value, but I tried to assign it to a different object both in the reactive part and in the renderPlot part and got no results...
So, if I don't assign it to a different variable, I get the message:
ggplot2 doesn't know how to deal with data of class
reactiveExpr/reactive
I know there are at least 2 questions (here and here) that talk about this problem. I did do my homework and try to use those answers and it didn't work. As far as I can tell, those answers suggest to assign the reactive object to another variable, which I did, and got the message:
Error: object is not a matrix
The answers delineated there do not really explain how to fix the problem in general, they just provide the code to fix that particular example (one answer reads " I think this particular problem should be solved with the following code:" but doesn't point out what part of the code solves the issue).
Can you please explain, how to fix this in this example in the more general case?
here is a Minimal example:
server.R
library(shiny)
shinyServer(function(input, output) {
library(ggplot2)
library(lme4)
model1 <- lmList((conc) ~ time | Subject, data = Indometh)
newpoints <- reactive({data.frame("Subject" = c(1, 4, 2, 5, 6, 3),
"conc" = predict(model1, newdata = data.frame(time=input$sliderTime)),
"time" = rep(input$sliderTime, 6))
})
output$myPlot <- renderPlot({
newpoints2 <- newpoints()
g <- ggplot(Indometh, aes(time, (conc), color= Subject)) + geom_point() +
stat_smooth(method="lm",fullrange=TRUE, fill=NA)
newg <- g + geom_point(data = newpoints2, mapping =
aes(x = time, y = (conc), color= factor(Subject)))
print(newg)
})
})
and the ui.R file:
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Concentration of Indomethacin"),
sidebarLayout(
sidebarPanel(
sliderInput("slidertime",
"Time:",
min = 8,
max = 15,
value = 8)),
mainPanel(
plotOutput("myPlot")
)
)
))
The problem with your example is that you are calling the input with the wrong name it is not sliderTime it is slidertime i change the server to this and it works perfect.
How I fix it? just use browser() inside the reactive expression and found that input$sliderTime was NULL so I check the name.
library(shiny)
shinyServer(function(input, output) {
library(ggplot2)
library(lme4)
model1 <- lmList((conc) ~ time | Subject, data = Indometh)
newpoints <- reactive({
data.frame("Subject" = c(1, 4, 2, 5, 6, 3),
"conc" = predict(model1, newdata = data.frame(time=input$slidertime)),
"time" = rep(input$slidertime, 6))
})
output$myPlot <- renderPlot({
newpoints2 <- newpoints()
g <- ggplot(Indometh, aes(time, (conc), color= Subject)) + geom_point() +
stat_smooth(method="lm",fullrange=TRUE, fill=NA)
newg <- g + geom_point(data = newpoints2, mapping =
aes(x = time, y = (conc), color= factor(Subject)))
print(newg)
})
})
I'm trying to use hover tooltips on a geom_area, but I can't get them to work with that geometry. It only displays lowest set of grouped variables (in the example below, it will show 'Lakers' hover values, but not 'Celtics'.
Interestingly, if you replace the geom_area with, for example, geom_point, the code below works fine. But for the real dashboard I'm making, an area chart is necessary.
library("shiny")
library("ggplot2")
d <- data.frame(date = as.Date(c("2017-01-01", "2017-01-02", "2017-01-03",
"2017-01-01", "2017-01-02", "2017-01-03")),
team = c("Celtics", "Celtics", "Celtics",
"Lakers", "Lakers", "Lakers"),
points_scored = c(108, 89, 95, 78, 93, 82))
ui <- fluidPage(
mainPanel(
plotOutput("graph",
hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")),
uiOutput("hover_info")
)
)
server <- function(input, output) {
output$graph <- renderPlot({
ggplot(d, aes(x = date, y = points_scored, fill = team)) +
geom_area()
})
output$hover_info <- renderUI({
hover <- input$plot_hover
point <- nearPoints(d, hover, threshold = 5, maxpoints = 1, addDist = TRUE)
if (nrow(point) == 0) return(NULL)
wellPanel(
paste0(point$team, " - ", point$date, ": ", point$points_scored)
)
})
}
runApp(list(ui = ui, server = server))
Thanks in advance!
--- Edit ---
It's actually displaying the hover in the incorrect location. See the attached picture. It treats the point (Celtics on Jan 1) as if it's still at y = 108. I want it to hover at the top of the visible red bar (108 + 78 = 186), but still display 108.
I've found a sketchy workaround, but it makes the app do what I want it to do. My edited app only edits the server function, and goes something like this:
Continue to use the main dataframe 'd' to generate the graph. Continue to use the hover in plotOutput off of that graph
Create a workaround dataframe 'd_workaround' that is identical, except it contains 1) the actual y position of the points in a column with the same name as the y column in 'd' and the graph (points_scored. I wanted to name this 'position', but the app only worked if it had the same name as the y column in 'd') and 2) the 'real' value that I want my tooltip to display (points_scored_real)
Direct my nearPoints() to use d_workaround, and my tooltips to display points_scored_real from that column
The app looks like this:
library(shiny)
library(ggplot2)
library(dplyr)
library(tidyr)
library(stringr)
d <- data.frame(date = as.Date(c("2017-01-01", "2017-01-02", "2017-01-03",
"2017-01-01", "2017-01-02", "2017-01-03")),
team = c("Celtics", "Celtics", "Celtics",
"Lakers", "Lakers", "Lakers"),
points_scored = c(108, 89, 95, 78, 93, 82))
ui <- fluidPage(
mainPanel(
plotOutput("graph",
hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")),
uiOutput("hover_info")
)
)
server <- function(input, output) {
output$graph <- renderPlot({
ggplot(d, aes(x = date, y = points_scored, fill = team)) +
geom_area()
})
output$hover_info <- renderUI({
d_workaround <- d %>%
spread(team, points_scored) %>%
mutate(Celtics = str_c(Celtics + Lakers, "-", Celtics),
Lakers = str_c(Lakers, "-", Lakers)) %>%
gather(team, points_scored, Celtics, Lakers) %>%
separate(points_scored, c("points_scored", "points_scored_real"), convert = TRUE)
hover <- input$plot_hover
point <- nearPoints(d_workaround, hover, threshold = 10, maxpoints = 1, addDist = TRUE)
if (nrow(point) == 0) return(NULL)
wellPanel(
paste0(point$team, " - ", point$date, ": ", point$points_scored_real)
)
})
}
runApp(list(ui = ui, server = server))
I have the following simplified example of a Shiny app using plotly graphic.
# Function, library, data
PlotResponseRate <- function(EntryData)
{
PlotData <- as.data.frame(apply(X = EntryData, MARGIN = 2,
function(x) round(length(which(!is.na(x)))/length(x)*100)))
colnames(PlotData) <- "TheData"
PlotData$TheLabel <- factor(str_wrap(colnames(EntryData), width = 30),
levels = unique(str_wrap(colnames(EntryData), width = 30)))
PlotData$TheLabel <- gsub(pattern = "\n", replacement = "<br>", PlotData$TheLabel)
Graphe <- ggplot(data = PlotData, aes(x = TheLabel, y = TheData)) +
geom_bar(stat = "identity", fill = "red", width = 0.8) +
coord_flip() +
labs(title = "Response rate")
}
library(stringr)
library(ggplot2)
library(plotly)
a <- c(1, 2, 2, 2, NA, 1, 2, 2, 1)
b <- c(2, 1, 2, NA, 2, NA, 1, NA, 1)
df <- data.frame(a, b)
colnames(df) <- c("This Is A Long Answer To A Long Question Label For The First Question",
"This Is A Long Answer To A Long Question Label For The Second Question")
# The Shiny app
Interface <-
{
fluidPage(
sliderInput(inputId = "Num",
label = "Choose the questions",
value = c(1:2), min = 1, max = 2, step = 1),
plotlyOutput("Myplot")
)
}
Serveur <- function(input, output)
{
output$Myplot <- renderPlotly({
Plot1 <- PlotResponseRate(EntryData = df[c(input$Num[1]:input$Num[2])])
ggplotly(Plot1)
})
}
shinyApp(ui = Interface, server = Serveur)
The main feature I want is modifying the structure of the plot. Therefore, I add this line of code in renderPlotly after the conversion in a plotly graphic.
ggplotly(Plot1)
Plot1$x$layout$margin$l <- 180
Or when I add this line, I have an error "no applicable method for 'ggplotly' applied to an object of class ”c('double', 'numeric')" and despite efforts I cannot debug. Any idea ?
I precise that it works fine in R command line :
Handle long labels in plotly
According to the comments above, the correct code is the following.
Serveur <- function(input, output)
{
output$Myplot <- renderPlotly({
Plot1 <- PlotResponseRate(EntryData = df[c(input$Num[1]:input$Num[2])])
Plot1 <- plotly_build(Plot1)
Plot1$x$layout$margin$l <- 180
Plot1 <- ggplotly(Plot1)
})
}