I've been building my first applications in shiny in order to publish them and share interactive graphs with my coworkers. At present I've been producing density plots to map behaviour. The Goal is to display between 1 and 4 plots as facets, depending on the "origin" selection and the "variable" selection in shiny. If I manually plot all 4 graphs, I get an output resembling this:
sampleplot <- data.frame("origin" = c("US","GB","GB","US","CA","US","GB","GB","US","CA","US","GB","GB","US","CA","US","GB","GB","US","CA"),
"variable" = c("p1","p2","p3","p1","p4","p1","p2","p3","p1","p1","p1","p2","p3","p1","p4","p1","p2","p3","p1","p1"),
"value" = runif(20, min = 0.2, max = 0.8))
sampleplot %>%
ggplot(aes(value, color = origin)) +
facet_wrap(~ variable, ncol = 2) +
geom_density()
However, in shiny, when you select "p1", and then subsequently "p2", "p3" or "p4", the plot changes for "p1" (not just because of the scale, the shape is altered). It happens with any combination of variables. I get a warning along those lines when that happens:
Warning in ==.default(variable, input$var) :
longer object length is not a multiple of shorter object length
I don't get what the issue is. The variable checkbox input is every type of variable listed, and each facet is essentially an individual subplot. So why does plotting the density of "p2" have an impact on the density of "p1". Would be great if anyone could shine some line on the problem for me.
I made a reproducible shiny app with the data and ggplot call provided, and taking the change in scale apart, nothing rare happens. Let me know if it helps. It would be helpful if you can provide some code of your app, so we know exactly what's going with your plot.
Example app:
library(shiny)
library(tidyverse)
sampleplot <- data.frame("origin" = c("US","GB","GB","US","CA","US","GB","GB","US","CA","US","GB","GB","US","CA","US","GB","GB","US","CA"),
"variable" = c("p1","p2","p3","p1","p4","p1","p2","p3","p1","p1","p1","p2","p3","p1","p4","p1","p2","p3","p1","p1"),
"value" = runif(20, min = 0.2, max = 0.8))
ui <- fluidPage(sidebarLayout(
sidebarPanel(selectInput('selection', "Select sampleplot's variable",choices = unique(sampleplot$variable), multiple = TRUE, selected = 'p1')),
mainPanel(plotOutput('sameplots'))
)
)
server <- function(input, output, session) {
reactive_sameplot <- reactive({
sampleplot %>%
filter(variable %in% input$selection) %>%
ggplot(aes(value, color = origin)) +
facet_wrap(~ variable, ncol = 2) +
geom_density()
})
output$sameplots <- renderPlot({reactive_sameplot()})
}
shinyApp(ui, server)
Related
I have a shiny dashboard with a graph - certain bars on the graph are highlighted based on a corresponding picker input, as you can see in this gif.
I only want the legend to reflect the fill, not the colour. I know how to do this in ggplot, but how can I accomplish this in a ggplotly object?
I've tried setting the guide to False in scale_color_manual, as well as setting guide(color = False), but no luck.
Also, of low priority, if anyone could give me an example of only having the outline around the whole of the stacked bar, not each individual segment, that would be appreciated.
Reproducible example:
library(shiny)
library(shinyWidgets)
library(tidyverse)
library(plotly)
dat <- data.frame(
location = rep(c("Loc1", "Loc2", "Loc3"), each = 3),
category = rep(c("cat1", "cat2", "cat3"), 3),
value = runif(9, 20, 50)
)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
pickerInput(
inputId = "selected",
label = "Select a category:",
choices = c("Loc1", "Loc2", "Loc3")
)
),
mainPanel(
plotlyOutput("outputPlot")
)
)
)
server <- function(input, output) {
output$outputPlot <- renderPlotly({
dat_selected <- dat %>%
# Mutate flag based on selected location
mutate(selected = ifelse(location == input$selected, 1, 0)) %>%
ggplot(
aes(
x = value,
y = location,
group = category,
fill = category,
color = as.factor(selected)
)
) + geom_bar(stat = "identity") +
scale_fill_manual(values = c("yellow", "white", "blue")) +
scale_color_manual(values = c("white", "red"), guide = "none") +
guides(color = F)
ggplotly(dat_selected)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Note that logical values to scale arguments in guides are deprecated. In ggplot2 you would use guides(color = "none") instead.
In ggplotly you may select traces shown in the legend using the traces argument in style():
Replace ggplotly(dat_selected) by
p <- ggplotly(dat_selected) %>%
style(showlegend = FALSE, traces = c(2, 4, 6))
p
Changing legend entry labels is not straightforward. You may alter labels by modifying list entries in the generated object p:
p <- ggplotly(dat_selected) %>%
style(showlegend = FALSE, traces = c(2, 4, 6))
p$x$data[[1]]$name <- "cat1"
p$x$data[[3]]$name <- "cat2"
p$x$data[[5]]$name <- "cat3"
p
(Confusingly, indices of the nested lists in p$x$data we need to modify differ from the trace indices above. This is seen from looking at the structure of p at runtime.)
The result looks like this:
I am working with a large network and wish too highlight certain nodes. I would like these nodes to plot on top of a dense network. They currently are identified by a certain color. Here is some simple example code.
library(network)
library(GGally)
# make a random network
x <- c(0,1,0,1,1,1,0,1,0,1,0,1)
seed <- c(10,25,40,34,1,35,6,3,14,5,23,3)
net <- data.frame(matrix(nrow = 12, ncol = 12))
for (i in 1:12) {
set.seed(seed[i])
net[i] <- sample(x)
}
#plot it with two colors
plot = as.network(net,
directed = FALSE,
ignore.eval = FALSE,
names.eval = 'R_val')
color <- c("yes","yes","no","no","no","no","no","no","no","no","no","no")
final <- ggnet2(net,size = 25,color = color,label = TRUE)
I have really exaggerated the dot size here to make them overlap. Is there a way I can get the "yes" points to always plot on top of the "no" points?
EDIT: Added "labels" for clarity.
Yes, there is! Your color vector first denotes the "yes" and then the "no", which seems to determine the plotting order. Assuming you have more than "yes" or "no", you could try convert the color vector to a factor and set levels. Then you can sort the order of your "yes"s and "no"s:
color <- c("yes","yes","no","no","no","no","no","no","no","no","no","no")
factor_color <- sort(factor(color, levels = c("no", "yes")))
ggnet2(net, size = 100, color = factor_color)
EDIT 1
As per your comment, I cannot think of a (more) elegant solution, but this works for me:
#plot it with two colors
plot = as.network(net,
directed = FALSE,
ignore.eval = FALSE,
names.eval = 'R_val')
color <- c("yes","yes","no","no","no","no","no","no","no","no","no","no")
final <- ggnet2(net,size = 100, color = color, label = TRUE)
final_build <- ggplot2::ggplot_build(final)
# Extract the geom_point data and find which elements have 'yes'
yes_index <- which(color == "yes")
label_data <- final_build$data[[2]]
yes_coordinates_label <- cbind(label_data[yes_index,], label = names(net)[yes_index])
final +
geom_point(data = yes_coordinates_label, aes(x = x, y = y),
size = 100, color = first(yes_coordinates_label$colour)) +
geom_text(data = yes_coordinates_label, aes(x = x, y = y, label = label))
The idea is to plot the dots with geom_point() again but only for the dots which are "yes".
EDIT 2
I couldn't help but think of another solution without plotting the points again. It is possible to retrieve the plot information using ggplot_build() and then to reorder the hierarchy of the points drawn; the datapoints which come first are drawn first. Hence doing the following will work:
library(tidyverse)
# Find the index of the GeomPoint layer
geom_types <- final$layers %>% map("geom") %>% map(class)
GeomPoint_ind <- which(sapply(geom_types, function(x) "GeomPoint" %in% x))
# Retrieve plot information
final_build <- ggplot2::ggplot_build(final)
df <- final_build$data[[GeomPoint_ind]]
# Set the indices which you would like to have on top and modify the ggplot_build object.
yes_index <- which(color == "yes")
final_build$data[[2]] <- rbind(df[-yes_index,], df[yes_index,])
# Convert to plot object and plot
new_final <- ggplot_gtable(final_build)
plot(new_final)
I'm building a shinyapp where I am passing variable names as arguments to the server with the selectInput() widget. The following static example illustrates the plot that I want displayed:
g <- ggplot(d, aes(y, fill = var1, colour = var1)) +
geom_density(alpha=.2)
Just to be clear, here is an image of the above plot
What I want to do in my shinyapp is to separate the plotted distributions by different variables that the user can choose via selectInput(). But when I substitute var1 in the above with a generic argument, this is not what I get. Please see the example:
library(ggplot2)
library(shiny)
d <- data.frame(var1=as.factor(sample(x = 1:4, size = 250, replace = TRUE)),
var2=as.factor(sample(x = 1:4, size = 250, replace = TRUE)),
y=rnorm(250, mean = 0, sd = 1))
nms <- names(d)
ui <- fluidPage(selectInput(inputId ="var", "Variable:",
choices = nms, selected = "var1"),
plotOutput(outputId = "plot")
)
server <- function(input, output) {
g <- ggplot(d, aes(y, fill = input$var, colour = input$var)) +
geom_density(alpha=.2)
output$plot <- renderPlot(g)
}
shinyApp(ui,server)
The actual output I get is
different from the static example I started with (click through for image).
Can someone please point out my error? Thankful for help.
input$var is a string. Therefore, do
output$plot <- renderPlot({
g <- ggplot(d, aes_string("y", fill = input$var, colour = input$var)) +
geom_density(alpha=.2)
g
})
I'm working with choropleth map (ggplot2), i have problem implementing geom_text properly. In output it is showing text over map but i can see many repeated name, no idea why, and need help to fix that please. Using R studio, Australia map shape file and data in a csv file. Moreover I had intention to show values over map instead of state names, don't know how.
codes in UI.R file
library(shiny)
# Define UI for application
shinyUI(fluidPage(
# Application title
headerPanel("Unemployment rate Data"),
# Sidebar with controls to select the variable to plot against
# specify whether outliers should be included
sidebarLayout(
sidebarPanel(
selectInput("variable", "Type:",
c("States" = "region",
"Unemployment_Rate" = "unemployment_rate_2015"
)
)
#checkboxInput("outliers", "Show outliers", FALSE)
),
# Show the caption and plot of the requested variable against population data data
mainPanel(
h3(textOutput("caption")),
plotOutput("datPlot")
)
)#----/sidebar layout
))#----/shinyUI
codes in Server.R file
require(maptools)
require(ggmap)
require(maps)
require(mapproj)
require(data.table)
library(rgeos)
library(plyr)
library(shiny)
library(datasets)
library(ggplot2) # load ggplot
setwd("C:/Users/AbdullahAl/Documents/AU-Shapefile")
pop <- read.csv("unemployment.csv")
AUS = readShapeSpatial("AUS_adm1")
shinyServer(function(input, output) {
# Compute the forumla text in a reactive expression since it is
# shared by the output$caption and output$mpgPlot expressions
output$caption <- reactiveText(function(){
paste("States ~", input$variable)
})
# ggplot version
output$datPlot <- reactivePlot(function() {
pop <- data.table(States = pop$region, var = factor(pop[[input$variable]]))
# Generate a plot of the requested variable against year and only
# include outliers if requested
AUS <- fortify(AUS, region = "NAME_1")
#add color="black" inside geom_map to have the boarder black
ggplot() + geom_map(data = pop, aes(map_id = States, fill = var), map = AUS) +
expand_limits(x = AUS$long, y = AUS$lat) +
# to add values over
geom_text(data = AUS, aes(x =long , y = lat, label = id, size = 2.5),
check_overlap = TRUE, position = "jitter", parse = FALSE) +
geom_label()
# facet_wrap( ~ var) - use this to show each divided states
})
})
Link for .csv file
https://onedrive.live.com/redir?resid=15945AE760E741A4!2712&authkey=!AChRc_Cl_PjJ_I4&ithint=file%2ccsv
And the output as image
the image is showing Australis's map and repeated name of the states over it
I am attempting to build a simple shiny app that creates a data table based on inputs and outputs a line plot using ggplot2. I receive the following error:
Error: ggplot2 doesn't know how to deal with data of class packageIQR
In this app, a user uses a slider to define the time period, or the length of X, and also the change in value by defining the starting value and the change in the value over X. The plot is a linear line. I am new to shiny, so if there are better ways to set up this I also would like suggestions on the best way to set up the server code, but for now I simply get an error and produce no plot.
server.R
library(shiny)
library(ggplot2)
shinyServer(function(input, output){
reactive({
data <- data.table(months = seq(1, input$months, by = 1),
value = seq(input$startingValue,
input$startingValue + input$valueChange,
length.out = input$months))
})
output$yield <- renderPlot({
p <- ggplot(data(), aes(x=months, y=value, colour=value)) +geom_line()
print(p)
})
})
You just need to define the reactive function :
data <- reactive({
data.table(months = seq(1, input$months, by = 1),
value = seq(input$startingValue,
input$startingValue + input$valueChange,
length.out = input$months))
})
Note here you don't need to define the reactive function since you have one caller. You can put all the code in the plot section:
output$yield <- renderPlot({
data <- data.table(months = seq(1, input$months, by = 1),
value = seq(input$startingValue,
input$startingValue + input$valueChange,
length.out = input$months))
p <- ggplot(data, aes(x=months, y=value, colour=value)) +geom_line()
print(p)
})