This question already has answers here:
Force the origin to start at 0
(4 answers)
Closed 2 years ago.
I was wondering if there is a way for me to adjust the location where the notches of the axis meet the edge of the bar plot. If you see in the image below all the notches of the x-axis line up in the center of the bar, I would like them to line up with the left edge of the bar! Is this possible?
Edit: Heres what my code looks like
hr6_xy = data.frame(hr6_bins, hr6_Occur)
hr6_plot = ggplot(hr6_xy, aes(hr6_bins, hr6_Occur)) +
geom_bar(stat = "identity",
color = 'black', fill = 'pink', width = 1)
hr6_plot = hr6_plot + theme_bw()
hr6_plot = hr6_plot + ggtitle("hr6 (68 sites)")
hr6_plot = hr6_plot + xlab("Distance to TSS from Motif Center, kb")
hr6_plot = hr6_plot + ylab("Occurances")
hr6_plot
Two ways I can think of:
(a) shift the position of the bars with position_nudge
ggplot(data = iris, aes(y=Sepal.Length, x = Species)) +
geom_bar(stat = "summary", width = 0.8,
position = position_nudge(x = 0.4))
(b) shift the position of the ticks on the x-axis with scale_x_continuous
ggplot(data = iris, aes(y=Sepal.Length, x = as.numeric(Species))) +
geom_bar(stat = "summary", width = 0.8) +
scale_x_continuous(breaks = c(0.6, 1.6, 2.6),
labels = levels(iris$Species))
Related
This question already has an answer here:
Position geom_text on dodged barplot
(1 answer)
Closed 1 year ago.
How do I adjust the position in geom_text to distribute the column labels over each of their respective columns, currently they are all aligned on top of each other (see picture)
ggplot(ESCd, aes(factor(S),fill = ESC9)) +
geom_bar(stat="count", position = "dodge")+
geom_text(stat='count', aes(label=..count..), vjust=-1, position = "identity")
We could use position = position_dodge():
Here is an example with the built in diamonds dataframe:
library(ggplot2)
ggplot(diamonds, aes(factor(cut),fill = factor(color))) +
geom_bar(stat="count", position = "dodge")+
geom_text(stat='count', aes(label=..count..), position = position_dodge(width = 0.9),
vjust = -0.25, color = "black", size = 3)
I am making a set of scorecards where I am generating a set of graphs that show the distribution of responses from a survey and also where the response for a specific company falls. I need to modify the formatting of a graph, a stacked barchart, and add a few features I’ve outlined below. I’ve already spent a few hours getting my chart to where it is now and would appreciate your help with the features I outline below.
Data is
Data<-data.frame(Reviewed = c("Annually", "Annually", "Hourly", "Monthly", "Weekly","Monthly","Weekly","Other","Other","Monthly","Weekly"),Company=c("a","b","c","d","e","f","g","h","i","j","k"),Question="Q1")
So far I’ve developed this
ggplot(Data, aes(x="Question", fill=Reviewed)) + geom_bar(position='fill' ) +
coord_flip()
I would like to do the following:
Order the variables so they are arranged on plot as follows: Annually,Monthly,Weekly,Hourly,Other
Express the y axis in terms of percent. I.e. 0.25 turns into 25%
Move y-axis directly underneath the bar.
Remove the legend but move the terms underneath the respective part of the graph on a diagonal slant.
Add a black line that cuts down the 50% mark
Add a dot in at the midpoint of the stack for the value of company “e”.
Remove gray background
This is what I'm hoping the finished graph will look like.
There's a lot to unpack here, so I'll break it down bit by bit:
Order the variables so they are arranged on plot as follows: Annually,Monthly,Weekly,Hourly,Other
Assign "Reviewed" as an ordered factor. I'm reversing the order here since it wants to plot the "lowest" factor first (to the left).
Data$Reviewed <- factor(Data$Reviewed,
levels = rev(c('Annually', 'Monthly', 'Weekly', 'Hourly', 'Other')),
ordered = T)
ggplot(Data, aes(x="Question", fill=Reviewed)) + geom_bar(position='fill' ) +
coord_flip()
Express the y axis in terms of percent. I.e. 0.25 turns into 25%
Use scale_y_continuous(labels = scales::percent) to adjust the labels. I believe that the scales was pulled in when you installed ggplot2.
ggplot(Data, aes(x="Question", fill=Reviewed)) +
geom_bar(position = 'fill') +
scale_y_continuous(labels = scales::percent) +
coord_flip()
Move y-axis directly underneath the bar.
Remove gray background
These are done all at once by adding expand = F to coord_flip.
ggplot(Data, aes(x="Question", fill=Reviewed)) +
geom_bar(position = 'fill') +
scale_y_continuous(labels = scales::percent) +
coord_flip(expand = F)
Remove the legend...
Add theme(legend.position = 'none').
ggplot(Data, aes(x="Question", fill=Reviewed)) +
geom_bar(position = 'fill') +
scale_y_continuous(labels = scales::percent) +
coord_flip(expand = F) +
theme(legend.position = 'none')
but move the terms underneath the respective part of the graph on a diagonal slant.
This is tougher and takes a good amount of fiddling.
Use geom_text to make the labels
Calculate the position along the bar using the 'count' stat
Move the labels to the bottom of the plot by providing a fake x coordinate
Align the labels in the center of the bars using position_stack, and make them abut the x axis using hjust.
Add angle.
Use clip = 'off' in coord_flip to make sure that these values are not cut out since they're outside the plotting area.
Fiddle with the x limits to crop out empty plotting area.
Adjust the plot margin in theme to make sure everything can be seen.
ggplot(Data, aes(x="Question", fill=Reviewed)) +
geom_bar(position = 'fill') +
geom_text(aes(label = Reviewed, x = 0.45,
y = stat(..count../sum(..count..))), stat = 'count',
position = position_stack(0.5),
hjust = 0,
angle = 45) +
scale_y_continuous(labels = scales::percent) +
coord_flip(xlim = c(0.555, 1.4), clip = 'off',expand = F) +
theme(plot.margin = margin(0, 0, 35, 10),
legend.position = 'none')
Add a black line that cuts down the 50% mark
Use geom_hline(yintercept = 0.5); remember that it's a "horizontal" line since the coordinates are flipped.
ggplot(Data, aes(x="Question", fill=Reviewed)) +
geom_bar(position = 'fill') +
geom_text(aes(label = Reviewed, x = 0.45,
y = stat(..count../sum(..count..))), stat = 'count',
position = position_stack(0.5),
hjust = 0,
angle = 45) +
geom_hline(yintercept = 0.5) +
scale_y_continuous(labels = scales::percent) +
coord_flip(xlim = c(0.555, 1.4), clip = 'off',expand = F) +
theme(plot.margin = margin(0, 0, 20, 10),
legend.position = 'none')
Add a dot in at the midpoint of the stack for the value of company “e”.
This is pretty hack-y. Using the same y values as in geom_text, use geom_point to plot a point for every value of Reviewed, then use position_stack(0.5) to nudge them to the center of the bar. Then use scale_color_manual to only color "Weekly" values (which is the corresponding value of Reviewed for Company "e"). I'm sure there's a way to do this more programmatically.
ggplot(Data, aes(x="Question", fill=Reviewed)) +
geom_bar(position = 'fill') +
geom_text(aes(label = Reviewed, x = 0.45,
y = stat(..count../sum(..count..))), stat = 'count',
position = position_stack(0.5),
hjust = 0,
angle = 45) +
geom_hline(yintercept = 0.5) +
geom_point(aes(y = stat(..count../sum(..count..)),
color = Reviewed), stat = 'count',
position = position_stack(0.5), size = 5) +
scale_color_manual(values = 'black', limits = 'Weekly') +
scale_y_continuous(labels = scales::percent) +
coord_flip(xlim = c(0.555, 1.4), clip = 'off',expand = F) +
theme(plot.margin = margin(0, 0, 20, 10),
legend.position = 'none')
This is what I'm hoping the finished graph will look like.
Prettying things up:
ggplot(Data, aes(x="Question", fill = Reviewed)) +
geom_bar(position = 'fill') +
geom_text(aes(label = Reviewed, x = 0.45,
y = stat(..count../sum(..count..))), stat = 'count',
position = position_stack(0.5),
hjust = 0,
angle = 45) +
geom_hline(yintercept = 0.5) +
geom_point(aes(y = stat(..count../sum(..count..)),
color = Reviewed), stat = 'count',
position = position_stack(0.5), size = 5) +
scale_color_manual(values = 'black', limits = 'Weekly') +
scale_y_continuous(labels = scales::percent) +
coord_flip(xlim = c(0.555, 1.4), clip = 'off', expand = F) +
labs(x = NULL, y = NULL) +
theme_minimal() +
theme(plot.margin = margin(0, 0, 35, 10),
legend.position = 'none')
This question already has an answer here:
Position geom_text on dodged barplot
(1 answer)
Closed 2 years ago.
With the code below,
library(ggplot2)
load(url("http://murraylax.org/datasets/cps2016.RData"))
ggplot(df, aes(industry, usualhrs, fill=as.factor(sex))) +
stat_summary(geom = "bar", fun = mean, position = "dodge", width=0.7) +
stat_summary(geom = "errorbar", fun.data = mean_se, position = "dodge", width=0.7) +
stat_summary(aes(label = round(..y..,0)), fun = mean, geom = "text", size = 3, vjust = -1) +
xlab("Industry") + ylab("Usual Hourly Earnings") +
scale_x_discrete(labels = function(x) str_wrap(x, width = 12)) +
theme(legend.position = "bottom") +
labs(fill = "Gender") +
theme_bw()
I am producing this barplot (with error bars):
The labels are centered according to the x-axis, but I would like to have the labels centered in each bar. In the first two bars, for example, I would like to have 27 at the center of the "Female" bar and 46 at the center of "Male" bar. I would also like to move the labels to the top of the error bars.
Add position = position_dodge(width = 1)) to your stat_summary(aes(label...)) call, outside of aes to move the labels above their respective bars.
To move the labels above the error bars I used geom_text with a y position slightly above the error bars, which required calculating the error bar position ahead of time using dplyr::summarize
library(dplyr)
df %>%
group_by(industry, sex) %>%
summarise(usualhrs_mean = mean(usualhrs, na.rm = TRUE),
count = n(),
usualhrs_se = sd(usualhrs, na.rm = TRUE)/sqrt(count)) %>%
ggplot(aes(x = industry, y = usualhrs_mean, fill = as.factor(sex))) +
geom_bar(stat = "identity", position = position_dodge(width = 1)) +
geom_errorbar(aes(ymin = usualhrs_mean - usualhrs_se,
ymax = usualhrs_mean + usualhrs_se),
position = position_dodge(width = 1)) +
geom_text(aes(label=round(..y.., 0), y = (usualhrs_mean + usualhrs_se + 0.1)), vjust = -1.5, position = position_dodge(width = 1)) +
scale_x_discrete(
labels = function(x)
str_wrap(x, width = 12)
) +
coord_cartesian(ylim = c(0, 55)) +
theme(legend.position = "bottom") +
labs(fill = "Gender",
y = "Usual Hourly Earnings") +
theme_bw()
This question already has answers here:
ggplot with 2 y axes on each side and different scales
(18 answers)
Closed 4 years ago.
I am trying to make a plot with ggplot in a Shiny app in R and I need to set a second Y-axis in it. This plot has two types of graphics: lines and bars. I would like to represent the bars (depth of precipitation) on the left, and the lines (flows) on the right.
My current code is:
output$plotRout <- renderPlot({
ggplot(totalRR(),aes(x=time)) +
geom_bar(aes(y=mm), stat = "identity",fill = "dodgerblue",color = "black") +
geom_bar(aes(y=NetRain), stat = "identity",fill = "Cyan",color = "black") +
geom_line(aes(y=DirRun, colour = "Direct Runoff"), stat = "identity",color = "Red") +
geom_line(aes(y=BF, colour = "Baseflow"), stat = "identity",color = "Darkorange", linetype = "longdash") +
scale_y_continuous("Rainfall (mm)", sec.axis = sec_axis(~.*10, name = "Flow (m3/s)")) +
xlab("Time (h)")
})
The result is:
This plot has on the left the values of the flows, the values that should be on the right, whereas the values of rainfall (the bars) are not displayed on the plot.
How could I make this plot putting the values of the bars (rainfall) on the left and the second y-axis on the right showing the values of the lines (flows)?
Many thanks in advance.
Victor
One solution would be to make the Flow axis your primary y axis. This involves 1) scaling the data using *10 and then 2) transforming the secondary axis using /10 to get back the correct numbers for the Rainfall axis:
ggplot(totalRR(),aes(x=time)) +
geom_bar(aes(y=10*mm), stat = "identity",fill = "dodgerblue",color = "black") +
geom_bar(aes(y=10*NetRain), stat = "identity",fill = "Cyan",color = "black") +
geom_line(aes(y=10*DirRun, colour = "Direct Runoff"), stat = "identity",color = "Red") +
geom_line(aes(y=10*BF, colour = "Baseflow"), stat = "identity",color = "Darkorange", linetype = "longdash") +
scale_y_continuous("Flow (m3/s)", sec.axis = sec_axis(~./10, name = "Rainfall (mm)")) +
xlab("Time (h)")
I'm plotting summary stats in front of individual geom_points, but can't figure out how to add jitter to the plots. I think the issue is that I'm already using the position argument to move the High and Low water points away from each other.
waterSymPop_p <- ggplot(aes(x = SymPop, y = Finish, fill = Water, color = Water), data = xanFull) +
geom_point(position = position_dodge(width = 0.9)) +
stat_summary(fun.data = "mean_cl_normal", geom = "pointrange", position = position_dodge(width = 0.9)) +
coord_flip()
Here's the plot that produces (obviously not finished with the color scheme, etc)
I'd like the point to be slightly jittered within each point group (ie, not in a straight line). Thanks for the help!
Answer: use position_jitterdodge
Amended code and new figure:
ggplot(aes(x = SymPop, y = Finish, fill = Water, color = Water), data = xanFull) +
geom_point(position = position_jitterdodge(dodge.width = 0.9, jitter.width = 0.2)) +
stat_summary(fun.data = "mean_cl_normal", geom = "pointrange", position = position_dodge(width = 0.9)) +
coord_flip()
Drey answered this.
Answer: use position_jitterdodge
Amended code and new figure:
ggplot(aes(x = SymPop, y = Finish, fill = Water, color = Water), data = xanFull) +
geom_point(position = position_jitterdodge(dodge.width = 0.9, jitter.width = 0.2)) +
stat_summary(fun.data = "mean_cl_normal", geom = "pointrange", position = position_dodge(width = 0.9)) +
coord_flip()