I'm attempting to create a shiny app where the user can choose which of three columns to plot over time, consisting of the percentages of three candidates. So far the actual plot works perfectly, but I would like to add colours such that Cand_1 gets a blue line, Cand_2 a green, and Cand_3 a red one. I've attempted to use Plot + scale_colour_manuall = "c("Cand_1" = "blue", "Cand_2" = "green", "Cand_3" = "red) with and without "" around the variable names, and also if within the aes() such that:
Plot <- Plot + geom_line(aes(month, !! sym(input$cand)), group = 1, if(input$cand == "Cand_1){
colour = "blue"}
if(input$cand == "Cand_2"){colour = "green"}
if(input$cand == "Cand_2"){colour = "red})
But none of them works, either giving the error Attempted to create layer with no stat, or simply ignoring the argumens.
The whole code looks like this:
library(shiny)
library(tidyverse)
setwd("")
Data <- read.csv("Data.csv", stringsAsFactors = F)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("Candidates"),
# Sidebar with a select input
sidebarLayout(
sidebarPanel(
selectInput("Cand",
"Candidates",
choices = colnames(Data)[2:4], multiple = TRUE)
),
mainPanel(
plotOutput("LederPlott"),
textOutput("length")
)
)
)
# Define server logic required to draw plot
server <- function(input, output) {
output$CandPlott <- renderPlot({
Plot <- ggplot(Data)
if(length(input$Cand) == 1){
Plot <- Plot + geom_line(aes(month, !! sym(input$Cand)), group = 1)
}
if(length(input$Cand) == 2){
Plot <- Plot + geom_line(aes(month, !! syms(input$Cand)[[1]]), group = 1)+
geom_line(aes(month, !! syms(input$Cand)[[2]]), group = 1)
}
if(length(input$Cand) == 3){
Plot <- Plot + geom_line(aes(month, !! syms(input$Cand)[[1]]), group = 1)
Plot <- Plot + geom_line(aes(month, !! syms(input$Cand)[[2]]), group = 1)
Plot <- Plot + geom_line(aes(month, !! syms(input$Cand)[[3]]), group = 1)
}
Plot <- Plot + theme_classic() + ylab("%") + ggtitle("%God")
Plot
})
output$length <- renderText(input$Cand)
}
# Run the application
shinyApp(ui = ui, server = server)
And here is some sample data:
Month Cand_1 Cand_2 Cand_3
2019-02-01 60,7 90,1 86,2
2019-03-01 58,9 90,2 80,3
2019-04-01 47,3 88,3 84,6
2019-05-01 54,5 87,3 90
2019-06-01 50,6 86 89
2019-07-01 49,8 84,2 87,1
You cannot assign colour like this,
Plot <- Plot + geom_line(aes(month, !! sym(input$cand)), group = 1, if(input$cand == "Cand_1){
colour = "blue"}
if(input$cand == "Cand_2"){colour = "green"}
if(input$cand == "Cand_2"){colour = "red})
Because colour is a parameter of the aes(). It must appear at top level, like this:
Plot <- Plot + geom_line(aes(month, !! sym(input$cand)), group = 1, colour = <your decision here>)
But also, this parameter serves another purpose. It serves to colour different groups with different colours. What you want is one variable per time. So it won't work either, for this kind of purpose.
What you need is to place the color= parameter in the geom_line() call, but outside the aes():
Plot <- Plot + geom_line(aes(month, !! sym(input$cand)), group = 1),
colour = if(input$cand == "Cand_1") "blue" else
if(input$cand == "Cand_2")"green" else
if(input$cand == "Cand_3") "red")
There are shorter ways of doing it, also:
color.list <- list(Cand_1 = "blue", Cand_2 = "green", Cand_3 = "red")
Plot <- Plot + geom_line(aes(month, !! sym(input$cand)), group = 1),
colour = color.list[[input$cand]])
Related
Is there a way to have a selectInput change two elements of a plot? For example below, I created a reactive block to manipulate the data I want to plot in geom_point for each selectInput choice and it works perfectly. However, I also want the color of the points to change, a different color for each choice that is automatic, the user need not choose one themselves. So for one input$case points I want what is written in geom_point "orangered2". But if they choose the other input$case option, I would like the points in geom_point to be "gold".
Maybe an if statement but I am not sure where to nest that if so.
I posted a snippet of my UI and server bits.
UI snippet from a tab
tabPanel("Analysis",
sidebarLayout(
sidebarPanel(width = 4,
selectInput(inputId = "case",
label="Locations",
choices = c("TRUE", "FALSE")))
Server snippet
server <- function(input, output){
data_use <- reactive({
real_final[real_final$case %in% input$case,]
})
output$bathy <- renderPlot({
autoplot.bathy(shelf, geom=c("raster", "contour")) +
scale_fill_gradientn(name = "meters above\nsea level", colours = c("plum2", "steelblue4","steelblue3", "steelblue2", "steelblue1"),
breaks = c(-6000,0),
limits = c(-6000,0),
labels = c("-6000m","0m"),
na.value = "black") +
geom_point(data = data_use(), aes(long, lat), color = "orangered2", pch = ".") +
xlab("Longitude") +
ylab("Latitude") +
ggtitle("Seal Locations") +
theme(axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=10,face="bold"))
An option is to return a list with a reactive conductor:
data_and_color <- reactive({
list(
data = real_final[real_final$case %in% input$case,],
color = ifelse(input$case == "TRUE", "gold", "orangered2")
)
})
Then in the renderPlot:
x <- data_and_color()
ggplot(data = x$data, ......)
color = x$color
Please find my code below (I did not place the updated code for each image here.) The Code below is for the image labeled original :
packages <- c("ggplot2", "dplyr", "quantreg", "officer","tidyverse","here","glue","rvg","viridis","scales")
install.packages(setdiff(packages, rownames(installed.packages())))
lapply(packages, require, character.only = TRUE)
data <- read.csv(file='Spiderplot_data.csv', header=TRUE)
Progressed <- as.factor(data$Progression)
Response <- as.factor(data$X)
Response <- factor(data$X, levels = c("Progressive Disease", "Stable Disease", "Partial Response", "Complete Response"))
highlight_df <- filter(data, Progression == 1)
p <- ggplot() +
geom_line(
data,
mapping = aes(
x = Cycle,
y = Change,
group = Study_ID,
color = Response
)
) +
geom_point(
data,
mapping = aes(
x = Cycle,
y = Change,
group = Study_ID,
color = Response,
shape = Progressed
)
) +
geom_point( # Data set with just points
highlight_df,
shape = 18,
size = 2.8,
mapping = aes(
x = Cycle,
y = Change,
group = Study_ID,
)
) +
scale_shape_manual(
values = c(16,18)
) +
scale_color_brewer(
palette = "Set1"
) +
scale_x_continuous(
name = "Cycle",
breaks = c(0,2,4,6,8,10,12,14,16,18,20,30,40,45),
limits = c(0,45),
expand = expansion(mult = c(0,0.001))
) +
scale_y_continuous(
name = "Percent Change in Lesion SLD (%)",
breaks = c(-1,-.75,-.50,-.40,-.30,-.20,-.10,.10,.20,.30,.40,.50,.65),
limits = c(-1,.65),
labels = percent
) +
ggtitle("Response Plot")
p
p_dml <- rvg::dml(ggobj = p)
# initialize PowerPoint slide ----
officer::read_pptx() %>%
# add slide ----
officer::add_slide() %>%
# specify object and location of object ----
officer::ph_with(p_dml, ph_location(width = 10, height = 5)) %>%
# export slide -----
base::print(
target = here::here(
"demo_3.pptx"
)
)
As you can see the distance between each point on the x axis is linear and equal, is there a way to spread out the distance on the plot between 0-20 and make space between 20-40 smaller?
As you can see I have tried to do this using the expand function, but to no avail, I am using the funciton wrong?
Any help would be much appreciated.
Orginal image
Image with scale_x_sqrt
Image with scale_x_continuous(trans = scales::pseudo_log_trans(sigma = 3))
While this is as close as we've gotten to what I am looking for, is there a function that allows me to customize exactly where the ticks are on the axis?
For a function that accepts a data frame, a plot switch value, and bin size vector, I'm trying to create plots for each count-bin and each density-bin size combination for every numerical variable column when a plot switch value of 'grid' is inputted. I have it working that I get individual plots for each combination, but when I tried to put the plots for each numerical variable on a grid and I'm seeing variations in the actual plots even though as far as I can tell I didn't alter the calculations nor the plot commands.
For instance, notice that, even accounting for scale variations, y-density plots are different in the images below. Tried looking at the documentation for grid.arrange and list just to make sure I wasn't missing something, but I still can't figure it out. Did I somehow change the plot command without realizing it?
Tested with:
data(diamonds, package = "ggplot2")
test <- diamonds[1:100,]
hstPlts(test,ps='grid') #without grid
hst1(test,ps='grid') #with grid
hstPlts <- function(df,ps = 'off',bnSize=c(30)){
#hstPlts() accepts any data frame and if the ps parameter is “on” or
#“grid”, then plot a pair of blue histograms with a vertical red line at the
#mean
#for every numerical variable at each number of bins integer specified in
#the bin
#vector parameter. if the plot switch is set to “grid”, there should be a
#grid for each count-bin combination and a separate grid for
#each density-bin size combination.
#parameters:
#df : data frame
#ps : plot switch defaulted to 'off' with two additional value options -
#'on' and 'grid'
#bnSize : vector containing numeric values representing number of bins for
histograms
num_var <- df[sapply(df,is.numeric)] #extract numeric columns
for(i in 1:length(bnSize)){ #iterate through each bin size
for(j in 1:(ncol(num_var))){ #iterate through each numeric variable
if(ps=='on' | ps =='grid'){ #conditional for both 'on' and 'grid'
#values
bnWid <- (max(num_var[,j]) - min(num_var[,j]))/bnSize[i] # compute
#bin widths
vrMn <- mean(num_var[[j]]) #compute column means for red line
mean = sprintf("%8.3f ", vrMn) #set up label for mean line with
#formatted decimals
cntPlt <- ggplot(num_var, aes(x=num_var[,j])) + #plot count
#histogram with numeric variable on x-axis
geom_histogram(colour = "blue", fill = "blue", binwidth =
bnWid) +
#detail bar fill colors and histogram bin widths
geom_vline(xintercept = mean(num_var[,j]),colour="red") +
#mean line
abs(x=colnames(num_var)[j]) #label x-axis
densPlt <- cntPlt + aes(y = ..density..) + labs(y = "density")
#create corresponding density histogram
print(cntPlt)
print(densPlt)
}
if(ps == 'grid'){ #conditional for just 'grid' value
grdPlt <- ggplot(num_var, aes(x=num_var[,j])) + #create plot for
#each count-bin combination and a separate grid for
#each density-bin size combination
geom_histogram(colour = "blue", fill = "blue", binwidth =
bnWid) +
#detail bar fill colors and histogram bin widths
labs(x=colnames(num_var)[j]) #label x-axis
print(grdPlt)
print(grdPlt + aes(y = ..density..) + labs(y = "density"))
}
}
}
}
hst1 <- function(df,ps = 'off',bsizes=c(30)){
numvar <- df[sapply(df,is.numeric)]
if(ps=='on')
for(i in 1:length(bsizes)){
for(j in 1:(ncol(numvar))){
bwidth <- (max(numvar[,j]) - min(numvar[,j]))/bsizes[i]
var_mean <- mean(numvar[[j]])
mean = sprintf("%8.3f ", var_mean)
counts <- ggplot(numvar, aes(x=numvar[,j])) +
geom_histogram(colour = "blue", fill = "blue", binwidth
= bwidth) +
geom_vline(xintercept = mean(numvar[,j]),colour="red") +
labs(x=colnames(numvar)[j]) # Labeling the x axis
dense <- counts + aes(y = ..density..) + labs(y = "density")
print(counts)
print(dense)
}
}
}
else if(ps == 'grid'){
for(i in 1:length(bsizes)){
cntLst <- list()
denseLst <- list()
for(j in 1:(ncol(numvar))){
bwidth <- (max(numvar[,j]) - min(numvar[,j]))/bsizes[i]
cntGrPlt <- ggplot(numvar, aes(x=numvar[,j])) +
geom_histogram(colour = "blue", fill = "blue", binwidth =
bwidth) +
labs(x=colnames(numvar)[j])
cntLst[[length(cntLst)+1]] <- cntGrPlt
denseLst[[j]] <- cntGrPlt + aes(y = ..density..) + labs(y =
"density")
}
grid.arrange(grobs=cntLst,ncol=2)
grid.arrange(grobs=denseLst,ncol=2)
}
}
}
I am making a shiny app, that shows the user a ggplot after he selects the daterange he is interested in (= the range for the x-axis). So I guess I need to define a reactive data object (correct?).
The ggplot has some subsetting in it. R tells me that reactive data object is not subsettable. In my rookie understanding of ggplot, the subsetting has to be done inside the geom_bar(), geom_line() statements in order to obtain the graph that I want.
Can anyone suggest me how to proceed with the subsetting?
And how to reference the factor category in generating colors for the graph?
Thanks!
sample data
A = c(3, 4, 3, 5)
B = c(2, 2, 1, 4)
Z = c(1, 2, 1, 2)
R = c(-2, -1, -3, 0)
S = c(7,7,7,9)
mydata = data.frame(cbind(A,B,Z,R,S))
dates = c("2014-01-01","2014-02-01","2014-03-01","2014-04-01")
mydata$date = as.Date(dates)
mydata.m = melt(mydata,id="date")
names(mydata.m) = c("variable", "category","value")
shiny server: select observations as per user input (dateRangeInput)
data.r = reactive({
a = subset(mydata.m, variable %in% input$daterange)
return(a)
})
shiny server: make the plot
output$myplot = renderPlot({
# ggplot with proper reference to reactive function <<data.r()>>
s = ggplot(data.r(), aes(x=variable, fill=category)) +
# bars for categories A, B, Z: needs subsetting the data... but how?
+ geom_bar(data=subset(data.r(), category %in% c("A","B")), aes(y=value), stat="identity", position="stack")
+ geom_bar(subset=.(category=="Z"), aes(y=-value), stat="identity")
# lines for categories R, S: same.
+ geom_line(subset=.(category=="R"), aes(y=value))
+ geom_line(subset=.(category=="S"), aes(y=value))
# how to reference the factor <<category>> in reactive function <<data.r()>>?
+ scale_fill_manual(breaks = levels(category), values = mycolorgenerator(length(levels(category))))
print(s)
})
UI.R
# INPUT PART
library(shiny)
shinyUI(pageWithSidebar(
# Application title
headerPanel("My App"),
sidebarPanel(
dateRangeInput("daterange", "Date range:",
start = "2014-01-01",
end = "2014-04-01",
min = "2014-01-01",
max = "2014-04-01",
format = "dd/mm/yyyy",
separator = "-"),
submitButton(text="Update!")
),
# -----------------------------------------------
# OUTPUT PART
mainPanel(
tabsetPanel(
tabPanel("Tab 1", h4("Head 1"),plotOutput("myplot"))
)
)
))
SERVER.R
library(reshape)
library(shiny)
library(ggplot2)
# GEN DATA -----------------------------------------------
A = c(3, 4, 3, 5)
B = c(2, 2, 1, 4)
Z = c(1, 2, 1, 2)
R = c(-2, -1, -3, 0)
S = c(7,7,7,9)
mydata = data.frame(cbind(A,B,Z,R,S))
dates = c("2014-01-01","2014-02-01","2014-03-01","2014-04-01")
mydata$date = as.Date(dates)
mydata.m = melt(mydata,id="date")
names(mydata.m) = c("variable", "category","value")
# SERVER -----------------------------------------------
shinyServer(function (input, output) {
# DATA
data.r = reactive({
a = subset(mydata.m, variable %in% input$daterange)
return(a)
})
# GGPLOT
mycolorgenerator = colorRampPalette(c('sienna','light grey'))
output$myplot = renderPlot({
# ggplot with proper reference to reactive function <<data.r()>>
s = ggplot(data.r(), aes(x=variable, fill=category)) +
# bars for categories A, B, Z: needs subsetting the data... but how?
geom_bar(data=subset(data.r(), category %in% c("A","B")), aes(y=value), stat="identity", position="stack") +
geom_bar(subset=.(category=="Z"), aes(y=-value), stat="identity") +
# lines for categories R, S: same.
geom_line(subset=.(category=="R"), aes(y=value)) +
geom_line(subset=.(category=="S"), aes(y=value)) +
# how to reference the factor <<category>> in reactive function <<data.r()>>?
scale_fill_manual(breaks = levels(category), values = mycolorgenerator(length(levels(category))))
print(s)
})
})
(The complete server.R and ui.R really helped)
I'm not sure where you got the .() function from or the idea that geom_bar has a subset= parameter. But here's an updated renderPlot that doesn't seem to generate any errors at least
output$myplot = renderPlot({
dd<-data.r()
# ggplot with proper reference to reactive function <<data.r()>>
s = ggplot(dd, aes(x=variable, fill=category)) +
# bars for categories A, B, Z: needs subsetting the data... but how?
geom_bar(data=subset(dd, category %in% c("A","B")), aes(y=value),
stat="identity", position="stack") +
geom_bar(data=subset(dd, category=="Z"), aes(y=-value), stat="identity") +
# lines for categories R, S: same.
geom_line(data=subset(dd, category=="R"), aes(y=value)) +
geom_line(data=subset(dd, category=="S"), aes(y=value)) +
scale_fill_manual(breaks = levels(dd$category),
values = mycolorgenerator(length(levels(dd$category))))
print(s)
})
Mostly I changed the data= to explicit subset() calls
I have a dataframe a with three columns :
GeneName, Index1, Index2
I draw a scatterplot like this
ggplot(a, aes(log10(Index1+1), Index2)) +geom_point(alpha=1/5)
Then I want to color a point whose GeneName is "G1" and add a text box near that point, what might be the easiest way to do it?
You could create a subset containing just that point and then add it to the plot:
# create the subset
g1 <- subset(a, GeneName == "G1")
# plot the data
ggplot(a, aes(log10(Index1+1), Index2)) + geom_point(alpha=1/5) + # this is the base plot
geom_point(data=g1, colour="red") + # this adds a red point
geom_text(data=g1, label="G1", vjust=1) # this adds a label for the red point
NOTE: Since everyone keeps up-voting this question, I thought I would make it easier to read.
Something like this should work. You may need to mess around with the x and y arguments to geom_text().
library(ggplot2)
highlight.gene <- "G1"
set.seed(23456)
a <- data.frame(GeneName = paste("G", 1:10, sep = ""),
Index1 = runif(10, 100, 200),
Index2 = runif(10, 100, 150))
a$highlight <- ifelse(a$GeneName == highlight.gene, "highlight", "normal")
textdf <- a[a$GeneName == highlight.gene, ]
mycolours <- c("highlight" = "red", "normal" = "grey50")
a
textdf
ggplot(data = a, aes(x = Index1, y = Index2)) +
geom_point(size = 3, aes(colour = highlight)) +
scale_color_manual("Status", values = mycolours) +
geom_text(data = textdf, aes(x = Index1 * 1.05, y = Index2, label = "my label")) +
theme(legend.position = "none") +
theme()