Morning, I have a little problem with my ggplot graph.
For some reason, I can't see right now, the y axis ticks and numbers are missing. Maybe, I'm missing something really obvious here or it's something in my settings.
The toothgrowth dataset does not really fit the graph, but you can still see the problem (normally facet_wrap is included, but it does not work with this dataset).
library(tidyverse)
library(ggbeeswarm)
library(gghalves)
library(tidyr)
library(ggplot2)
library(ggpubr)
theme_set(theme_bw(16))
data <- ToothGrowth
a<- ggplot(data, aes(x=supp, y=len)) +
geom_half_boxplot(
data = data %>% filter(supp=="OJ"),
aes(x = supp, y = len, fill=supp), outlier.color = NA) +
scale_fill_manual(values=c("#F2F2F2", "#999999"))+
geom_half_boxplot(
data = data %>% filter(supp=="VC"),
aes(x = supp, y = len, fill=supp), side = "r", outlier.color = NA) +
geom_line(aes(group=supp, colour = supp), position = position_dodge(0.2), alpha = 0.3) +
geom_point(aes(group=supp, colour = supp),size=1,shape=21, position = position_dodge(0.2)) +
scale_color_manual(values=c("chartreuse3", "yellow2",
"firebrick3"))+
# facet_wrap(~ supp)+
# theme(
# strip.background = element_blank(),
# strip.text.x = element_blank())+
theme(plot.margin=unit(c(0,0,0,0),"cm"))+
scale_y_discrete(name ="Name")+
theme(text = element_text(size=11))+
theme(legend.position = "none")
a
Would be great if someone could see the problem; I'm going blind by now. Many thanks!!
Shouldn't your y axis be continuous?
scale_y_continuous(name ="Name")
Then you can add the limits and ticks positions as you want:
scale_y_continuous(name="Name",limits=c(min,max), breaks=c(a,b,c,d))
Related
I am using the windrose function posted here: Wind rose with ggplot (R)?
I need to have the percents on the figure showing on the individual lines (rather than on the left side), but so far I have not been able to figure out how. (see figure below for depiction of goal)
Here is the code that makes the figure:
p.windrose <- ggplot(data = data,
aes(x = dir.binned,y = (..count..)/sum(..count..),
fill = spd.binned)) +
geom_bar()+
scale_y_continuous(breaks = ybreaks.prct,labels=percent)+
ylab("")+
scale_x_discrete(drop = FALSE,
labels = waiver()) +
xlab("")+
coord_polar(start = -((dirres/2)/360) * 2*pi) +
scale_fill_manual(name = "Wind Speed (m/s)",
values = spd.colors,
drop = FALSE)+
theme_bw(base_size = 12, base_family = "Helvetica")
I marked up the figure I have so far with what I am trying to do! It'd be neat if the labels either auto-picked the location with the least wind in that direction, or if it had a tag for the placement so that it could be changed.
I tried using geom_text, but I get an error saying that "aesthetics must be valid data columns".
Thanks for your help!
One of the things you could do is to make an extra data.frame that you use for the labels. Since the data isn't available from your question, I'll illustrate with mock data below:
library(ggplot2)
# Mock data
df <- data.frame(
x = 1:360,
y = runif(360, 0, 0.20)
)
labels <- data.frame(
x = 90,
y = scales::extended_breaks()(range(df$y))
)
ggplot(data = df,
aes(x = as.factor(x), y = y)) +
geom_point() +
geom_text(data = labels,
aes(label = scales::percent(y, 1))) +
scale_x_discrete(breaks = seq(0, 1, length.out = 9) * 360) +
coord_polar() +
theme(axis.ticks.y = element_blank(), # Disables default y-axis
axis.text.y = element_blank())
#teunbrand answer got me very close! I wanted to add the code I used to get everything just right in case anyone in the future has a similar problem.
# Create the labels:
x_location <- pi # x location of the labels
# Get the percentage
T_data <- data %>%
dplyr::group_by(dir.binned) %>%
dplyr::summarise(count= n()) %>%
dplyr::mutate(y = count/sum(count))
labels <- data.frame(x = x_location,
y = scales::extended_breaks()(range(T_data$y)))
# Create figure
p.windrose <- ggplot() +
geom_bar(data = data,
aes(x = dir.binned, y = (..count..)/sum(..count..),
fill = spd.binned))+
geom_text(data = labels,
aes(x=x, y=y, label = scales::percent(y, 1))) +
scale_y_continuous(breaks = waiver(),labels=NULL)+
scale_x_discrete(drop = FALSE,
labels = waiver()) +
ylab("")+xlab("")+
coord_polar(start = -((dirres/2)/360) * 2*pi) +
scale_fill_manual(name = "Wind Speed (m/s)",
values = spd.colors,
drop = FALSE)+
theme_bw(base_size = 12, base_family = "Helvetica") +
theme(axis.ticks.y = element_blank(), # Disables default y-axis
axis.text.y = element_blank())
I am trying to recreate a geological cross section similar to the one below, which show various rock parameters (x axis) plotted against depth (y axis)
I can nicely recreate the individual plots in ggplot2 and grid together to create something very similar. To finish off i would really like to join lines between the plots which show regions of similar geology as in the picture.
Below is some code which plots the charts with the horizontal lines, what i would really to do is to join lines ( if possible in R) and if possible align the charts based on the line
library(ggplot2)
library(gridExtra)
df1 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df1$depth = seq.int(nrow(df1))
df2 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df2$depth = seq.int(nrow(df1))
top1 = 32
top2 = 50
plot1 = ggplot(df1, aes(y = depth, x = X1))+
scale_y_continuous(trans = "reverse")+
geom_path()+
geom_hline(yintercept=top1, colour = "red")+
annotate(geom="text", x=25, y=top1, label=top1, color="red")+
theme_bw()+
theme(panel.grid.major = element_line(colour = "grey"), panel.background = element_rect(colour = "black", size=0.5))+
ylab("Depth ft")+
ggtitle("plot1")
plot2 = ggplot(df2, aes(y = depth, x = X1))+
scale_y_continuous(trans = "reverse")+
geom_path()+
geom_hline(yintercept=top2, colour = "red")+
annotate(geom="text", x=25, y=top2, label=top2, color="red")+
theme_bw()+
theme(panel.grid.major = element_line(colour = "grey"), panel.background = element_rect(colour = "black", size=0.5))+
ylab("Depth ft")+
ggtitle("plot2")
grid.arrange (plot1, plot2, ncol=2)
This would be the desired result i would be looking for with the lines joined and if possible aligned.
Thanks for any help or advice given
Cheers
I can't help with the line-joining part, but the idea of the shifted scales sounded pretty interesting. This solution takes an arbitrary number of dataframes and an accompanying list of isolines, then shifts the y-scale so that each isoline is at 0.
Each dataframe is then plotted and the y-axes are renumbered appropriately.
library(purrr)
library(dplyr)
library(ggplot2)
# library(cowplot)
# I never load `cowplot` because it changes some settings onload.
# I just call the namespace with `cowplot::plot_grid(...)`
# You will need it installed though.
depth_plots <- function(..., isolines) {
dats <- list(...)
stopifnot(length(dats) == length(isolines))
scaled_dats <- map2(dats, isolines, ~.x %>% mutate(sc_depth = depth - .y))
new_range <-
map(scaled_dats, ~range(.x$sc_depth)) %>%
unlist() %>%
range() %>%
scales::expand_range(mul = 0.05)
plots <- map2(
scaled_dats, isolines,
~ggplot(.x, aes(y = sc_depth, x = X1)) +
scale_y_continuous(
trans = "reverse",
breaks = scales::extended_breaks()(.x$depth) - .y,
labels = scales::extended_breaks()(.x$depth)
) +
geom_path() +
geom_hline(yintercept=0, colour = "red") +
annotate(geom="text", x=25, y=0, label=.y, color="red") +
coord_cartesian(
ylim = new_range
) +
theme_bw()
)
cowplot::plot_grid(plotlist = plots, nrow = 1)
}
To test out the varying depth structures, I changed your sample data a bit:
df1 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df1$depth = seq.int(nrow(df1))
df2 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df2$depth = seq.int(nrow(df1))*0.75
df3 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df3$depth = seq.int(nrow(df1))*2
depth_plots(df1, df2, df3, isolines = c(32,50, 4))
Hope that gets you started!
I've been stuck on an issue and can't find a solution. I've tried many suggestions on Stack Overflow and elsewhere about manually ordering a stacked bar chart, since that should be a pretty simple fix, but those suggestions don't work with the huge complicated mess of code I plucked from many places. My only issue is y-axis item ordering.
I'm making a series of stacked bar charts, and ggplot2 changes the ordering of the items on the y-axis depending on which dataframe I am trying to plot. I'm trying to make 39 of these plots and want them to all have the same ordering. I think ggplot2 only wants to plot them in ascending order of their numeric mean or something, but I'd like all of the bar charts to first display the group "Bird Advocates" and then "Cat Advocates." (This is also the order they appear in my data frame, but that ordering is lost at the coord_flip() point in plotting.)
I think that taking the data frame through so many changes is why I can't just add something simple at the end or use the reorder() function. Adding things into aes() also doesn't work, since the stacked bar chart I'm creating seems to depend on those items being exactly a certain way.
Here's one of my data frames where ggplot2 is ordering my y-axis items incorrectly, plotting "Cat Advocates" before "Bird Advocates":
Group,Strongly Opposed,Opposed,Slightly Opposed,Neutral,Slightly Support,Support,Strongly Support
Bird Advocates,0.005473026,0.010946052,0.012509773,0.058639562,0.071149335,0.31118061,0.530101642
Cat Advocates,0.04491726,0.07013396,0.03624901,0.23719464,0.09141056,0.23404255,0.28605201
And here's all the code that takes that and turns it into a plot:
library(ggplot2)
library(reshape2)
library(plotly)
#Importing data from a .csv file
data <- read.csv("data.csv", header=TRUE)
data$s.Strongly.Opposed <- 0-data$Strongly.Opposed-data$Opposed-data$Slightly.Opposed-.5*data$Neutral
data$s.Opposed <- 0-data$Opposed-data$Slightly.Opposed-.5*data$Neutral
data$s.Slightly.Opposed <- 0-data$Slightly.Opposed-.5*data$Neutral
data$s.Neutral <- 0-.5*data$Neutral
data$s.Slightly.Support <- 0+.5*data$Neutral
data$s.Support <- 0+data$Slightly.Support+.5*data$Neutral
data$s.Strongly.Support <- 0+data$Support+data$Slightly.Support+.5*data$Neutral
#to percents
data[,2:15]<-data[,2:15]*100
#melting
mdfr <- melt(data, id=c("Group"))
mdfr<-cbind(mdfr[1:14,],mdfr[15:28,3])
colnames(mdfr)<-c("Group","variable","value","start")
#remove dot in level names
mylevels<-c("Strongly Opposed","Opposed","Slightly Opposed","Neutral","Slightly Support","Support","Strongly Support")
mdfr$variable<-droplevels(mdfr$variable)
levels(mdfr$variable)<-mylevels
pal<-c("#bd7523", "#e9aa61", "#f6d1a7", "#999999", "#c8cbc0", "#65806d", "#334e3b")
ggplot(data=mdfr) +
geom_segment(aes(x = Group, y = start, xend = Group, yend = start+value, colour = variable,
text=paste("Group: ",Group,"<br>Percent: ",value,"%")), size = 5) +
geom_hline(yintercept = 0, color =c("#646464")) +
coord_flip() +
theme(legend.position="top") +
theme(legend.key.width=unit(0.5,"cm")) +
guides(col = guide_legend(ncol = 12)) + #has 7 real columns, using to adjust legend position
scale_color_manual("Response", labels = mylevels, values = pal, guide="legend") +
theme(legend.title = element_blank()) +
theme(axis.title.x = element_blank()) +
theme(axis.title.y = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.text.x = element_blank()) +
theme(legend.key = element_rect(fill = "white")) +
scale_y_continuous(breaks=seq(-100,100,100), limits=c(-100,100)) +
theme(panel.background = element_rect(fill = "#ffffff"),
panel.grid.major = element_line(colour = "#CBCBCB"))
The plot:
I think this works, you may need to play around with the axis limits/breaks:
library(dplyr)
mdfr <- mdfr %>%
mutate(group_n = as.integer(case_when(Group == "Bird Advocates" ~ 2,
Group == "Cat Advocates" ~ 1)))
ggplot(data=mdfr) +
geom_segment(aes(x = group_n, y = start, xend = group_n, yend = start + value, colour = variable,
text=paste("Group: ",Group,"<br>Percent: ",value,"%")), size = 5) +
scale_x_continuous(limits = c(0,3), breaks = c(1, 2), labels = c("Cat", "Bird")) +
geom_hline(yintercept = 0, color =c("#646464")) +
theme(legend.position="top") +
theme(legend.key.width=unit(0.5,"cm")) +
coord_flip() +
guides(col = guide_legend(ncol = 12)) + #has 7 real columns, using to adjust legend position
scale_color_manual("Response", labels = mylevels, values = pal, guide="legend") +
theme(legend.title = element_blank()) +
theme(axis.title.x = element_blank()) +
theme(axis.title.y = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.text.x = element_blank()) +
theme(legend.key = element_rect(fill = "white"))+
scale_y_continuous(breaks=seq(-100,100,100), limits=c(-100,100)) +
theme(panel.background = element_rect(fill = "#ffffff"),
panel.grid.major = element_line(colour = "#CBCBCB"))
produces this plot:
You want to factor the 'Group' variable in the order by which you want the bars to appear.
mdfr$Group <- factor(mdfr$Group, levels = c("Bird Advocates", "Cat Advocates")
I am making a presentation and would like to present one line graph (geom_line()) with an appropriate legend. I then want to overlay a new geom_line and add the corresponding legend item. For aesthetic reasons, I want the overlay to not modify the legend location given in the first plot. The effect should be that one is drawing on an existing graph, and adding to its legend.
If I simply using ggplot to first make the first plot and then make a new plot with both lines, the location of the legend changes noticeably.
If I try to make the first plot be the full plot, but setting one of the line sizes to zero, I run into the problem that I can't suppress the legend-item for the size-zero line.
How can I achieve my desired effect with ggplot2?
EDIT:
Here is the code to make the two graphs that I first naively tried.
require(ggplot2)
require(reshape2)
x<-seq(-10,10,length=200)
G <- (1/(sqrt(2*pi))) * exp(-((x)^2)/(2))
G2 <- 2*(1/(pi))*(1/(x^2+1))
df = data.frame(x,G,G2)
ggplot(data = melt(data.frame(x,G),id.vars = 'x'))+
geom_line(aes(x=x, y=value, color=variable),size=.5)+
scale_color_manual("Distribution",values=c("orange"),labels=c("Gaussian"))+
coord_cartesian(ylim = c(0, 1))
ggplot(data = melt(data.frame(x,G,G2),id.vars = 'x'))+
geom_line(aes(x=x, y=value, color=variable),size=.5)+
scale_color_manual("Distribution",values=c("orange","blue"),labels=c("Gaussian","2Gaussian"))+
coord_cartesian(ylim = c(0, 1))
If it's not clear from these pictures that there is a problem, open up the images from these two links and flip from one to another.
http://rpubs.com/jwg/269311
http://rpubs.com/jwg/269312
NOTICE: The problem is even worse than I first described, since not only is the legend moving but the coordinate axis is moving as well.
Presumably this can be fixed by plotting both and then making its legend-item and the line invisible. Is this a possibility?
Here's a solution which will keep everything aligned with the bonus of animation.
library(ggplot2)
library(tidyr)
library(gganimate)
p <- df %>%
gather(var, val, -x) %>%
ggplot(aes(x, val, frame = var)) +
geom_line(aes(color = var, group = var, cumulative = TRUE)) +
coord_cartesian(ylim = c(0, 1))
gganimate(p, "myplot.gif", "gif")
This should generate a file myplot.gif with this result:
Not sure if this is what you want, but here goes:
x<-seq(-10,10,length=200)
G <- (1/(sqrt(2*pi))) * exp(-((x)^2)/(2))
G2 <- 2*(1/(pi))*(1/(x^2+1))
df <- data.frame(x,G,G2)
df.plot <- tidyr::gather(df, key = 'variable', value = 'value', -x)
ggplot(df.plot, aes(x, value, color = variable)) + geom_line() + scale_color_manual(breaks = c("G"), values = c("orange", NA)) +
coord_cartesian(xlim = c(-10, 10), ylim = c(0,1)) + theme(legend.position = c(0,0)) +
theme(legend.position = "right",
legend.justification = "top")
ggplot(df.plot, aes(x, value, color = variable)) + geom_line() + scale_color_manual(breaks = c("G", "G2"), values = c("orange", "blue")) +
coord_cartesian(xlim = c(-10, 10), ylim = c(0,1)) + theme(legend.position = "right",
legend.justification = "top")
I am trying to plot two flows and one rainfall data in one graph. I have broke it up into top and bottom parts as shown in the following pic. Here I have two issues with this plots and spent ages but cannot solve it.
Why the observed flow always in black, even I have set it up as blue? Did I accidentally used some other arguments to overwrite it?
The most importantly is, how do I able to add a legend for the bottom plot? I tried many different codes but they don't seem to work for me.
x = data.frame(date = Date, rain = Obs_rain, obsflow = Obs_flow,simflow=Sim_flow)
g.top <- ggplot(x, aes(x = date, y = rain, ymin=0, ymax=rain)) +
geom_linerange() +
scale_y_continuous(trans = "reverse") +
theme_bw() +
theme(plot.margin = unit(c(1,5,-30,6),units="points"),
axis.title.y = element_text(vjust =0.3)) +
labs(x = "Date",y = "Rain(mm)")
g.bottom <- ggplot(x, aes(x = date, y = obsflow, ymin=0, ymax=obsflow), colour = "blue",size=0.5) +
geom_linerange() + #plot flow
geom_linerange(aes(y = simflow, ymin=0, ymax=simflow), colour = "red", size =0.5)+
labs(x = "Date", y = "River flow (ML/day)") +
theme_classic() +
theme(plot.background = element_rect(fill = "transparent"),
plot.margin = unit(c(2,0,1,1),units="lines"))
grid.arrange(g.top,g.bottom, heights = c(1/5, 4/5))
Update:
I have resolved the issue with blue line colour. I accidently put arguments in the wrong place. But I'm still struggling with the legend.
g.bottom <- ggplot(x, aes(x = date, y = obsflow, ymin=0, ymax=obsflow)) +
geom_linerange(colour = "blue",size=0.5) + #plot flow
As an explanation of what #pierre means... turn your data from "wide" to "long" format using reshape2::melt, so that the flow type for each date is in one column flow_type, and the value is another (flow_val). Then you specify flow_type as the grouping variable with which to assign colour:
require(reshape2)
x.melted <- melt(x, id.vars = c("date", "rain"), variable.name="flow_type",
value.name="flow_val")
g.bottom <- ggplot(x.melted, aes(x = date),size=0.5) +
geom_linerange(aes(ymin=0, ymax=flow_val, colour=flow_type)) + #plot flow
labs(x = "Date", y = "River flow (ML/day)") +
theme_classic() +
theme(plot.background = element_rect(fill = "transparent"),
plot.margin = unit(c(2,0,1,1),units="lines"),
legend.position="bottom") +
scale_colour_manual(guide = guide_legend(title = "Flow Type"),
values = c("obsflow"="blue", "simflow"="red"))