I'm trying avoid overlapping lines in a color scheme. Excuse the ugly plot, but in the following, how do I have the lines drawn in the order of y1, y2, y1Smooth, and y2Smooth?
foo <- tibble(x=1:100,y1=rnorm(100,1),y2=rnorm(100,2)) %>%
mutate(y1Spline = smooth.spline(y1,spar=0.5)$y,
y2Spline = smooth.spline(y2,spar=0.5)$y) %>%
pivot_longer(cols=-x)
cols = c("darkgreen","darkblue")
ggplot(foo,aes(x=x,y=value,col=name, alpha=name)) +
geom_line() +
scale_color_manual(values=rep(cols,each=2)) +
scale_alpha_manual(values=c(0.5,1,0.5,1))
Practically-speaking, the order of legend items for a character variable will be equal to the order of the levels when that column is coerced into a factor. So, the default ordering is exemplified by this:
> levels(factor(foo$name))
[1] "y1" "y1Spline" "y2" "y2Spline"
Look familiar? The answer is to set the levels yourself before plotting:
library(ggplot2)
set.seed(8675309)
foo <- tibble(x=1:100,y1=rnorm(100,1),y2=rnorm(100,2)) %>%
mutate(y1Spline = smooth.spline(y1,spar=0.5)$y,
y2Spline = smooth.spline(y2,spar=0.5)$y) %>%
pivot_longer(cols=-x)
# force factor level order
foo$name <- factor(foo$name, levels=c("y1", "y2", "y1Spline", "y2Spline"))
cols = c("darkgreen","darkblue")
ggplot(foo,aes(x=x,y=value,col=name, alpha=name)) +
geom_line() +
scale_color_manual(values=rep(cols,each=2)) +
scale_alpha_manual(values=c(0.5,1,0.5,1))
A special note, the lines are drawn in that order - this means the line for "y1" will be on top of "y1Spline". If you want the lines drawn in that order, but the legend reversed, you'll need to add something like guides(color=guide_legend(reverse=TRUE)) at the end of your plot code.
Related
I have a faceted plot wherein I'd like to have the Y-axis labels and the associated values appear in descending order of values (and thereby changing the order of the labels) for each facet. What I have is this, but the order of the labels (and the corresponding values) is the same for each facet.
ggplot(rf,
aes(x = revenues,
y = reorder(AgencyName, revenues))) +
geom_point(stat = "identity",
aes(color = AgencyName),
show.legend = FALSE) +
xlab(NULL) +
ylab(NULL) +
scale_x_continuous(label = scales::comma) +
facet_wrap(~year, ncol = 3, scales = "free_y") +
theme_minimal()
Can someone point me to the solution?
The functions reorder_within and scale_*_reordered from the tidytext package might come in handy.
reorder_within recodes the values into a factor with strings in the form of "VARIABLE___WITHIN". This factor is ordered by the values in each group of WITHIN.
scale_*_reordered removes the "___WITHIN" suffix when plotting the axis labels.
Add scales = "free_y" in facet_wrap to make it work as expected.
Here is an example with generated data:
library(tidyverse)
# Generate data
df <- expand.grid(
year = 2019:2021,
group = paste("Group", toupper(letters[1:8]))
)
set.seed(123)
df$value <- rnorm(nrow(df), mean = 10, sd = 2)
df %>%
mutate(group = tidytext::reorder_within(group, value, within = year)) %>%
ggplot(aes(value, group)) +
geom_point() +
tidytext::scale_y_reordered() +
facet_wrap(vars(year), scales = "free_y")
I'd like to add percentage labels per gear to the bars but keep the count y-scale.
E.g. 10% of all 'gear 3' are '4 cyl'
library(ggplot)
ds <- mtcars
ds$gear <- as.factor(ds$gear)
p1 <- ggplot(ds, aes(gear, fill=gear)) +
geom_bar() +
facet_grid(cols = vars(cyl), margins=T)
p1
Ideally only in ggplot, wihtout adding dplyr or tidy. I found some of these solutions but then I get other issues with my original data.
EDIT: Suggestions that this is a duplicate from:
enter link description here
I saw this also earlier, but wasn't able to integrate that code into what I want:
# i just copy paste some of the code bits and try to reconstruct what I had earlier
ggplot(ds, aes(gear, fill=gear)) +
facet_grid(cols = vars(cyl), margins=T) +
# ..prop.. meaning %, but i want to keep the y-axis as count
geom_bar(aes(y = ..prop.., fill = factor(..x..)), stat="count") +
# not sure why, but I only get 100%
geom_text(aes( label = scales::percent(..prop..),
y= ..prop.. ), stat= "count", vjust = -.5)
The issue is that ggplot doesn't know that each facet is one group. This very useful tutorial helps with a nice solution. Just add aes(group = 1)
P.S. At the beginning, I was often quite reluctant and feared myself to manipulate my data and pre-calculate data frames for plotting. But there is no need to fret! It is actually often much easier (and safer!) to first shape / aggregate your data into the right form and then plot/ analyse the new data.
library(tidyverse)
library(scales)
ds <- mtcars
ds$gear <- as.factor(ds$gear)
First solution:
ggplot(ds, aes(gear, fill = gear)) +
geom_bar() +
facet_grid(cols = vars(cyl), margins = T) +
geom_text(aes(label = scales::percent(..prop..), group = 1), stat= "count")
edit to reply to comment
Showing percentages across facets is quite confusing to the reader of the figure and I would probably recommend against such a visualization. You won't get around data manipulation here. The challenge is here to include your "facet margin". I create two summary data frames and bind them together.
ds_count <-
ds %>%
count(cyl, gear) %>%
group_by(gear) %>%
mutate(perc = n/sum(n)) %>%
ungroup %>%
mutate(cyl = as.character(cyl))
ds_all <-
ds %>%
count(cyl, gear) %>%
group_by(gear) %>%
summarise(n = sum(n)) %>%
mutate(cyl = 'all', perc = 1)
ds_new <- bind_rows(ds_count, ds_all)
ggplot(ds_new, aes(gear, fill = gear)) +
geom_col(aes(gear, n, fill = gear)) +
facet_grid(cols = vars(cyl)) +
geom_text(aes(label = scales::percent(perc)), stat= "count")
IMO, a better way would be to simply swap x and facetting variables. Then you can use ggplots summarising function as above.
ggplot(ds, aes(as.character(cyl), fill = gear)) +
geom_bar() +
facet_grid(cols = vars(gear), margins = T) +
geom_text(aes(label = scales::percent(..prop..), group = 1), stat= "count")
Created on 2020-02-07 by the reprex package (v0.3.0)
I am trying to get double the space between the groups Automatic and Manual on the x-axis compared to the spaces within these groups. I am using geom_col() and experimted with different arguments, suchs as position_dodge, width and preserve = "single". I can't get this to work. What I am aiming for is a graph such as I have added as an image.
library(ggplot2)
library(ggthemes)
library(plyr)
#dataset
df <- mtcars
df$cyl <- as.factor(df$cyl)
df$am <- as.factor(df$am)
df$am <- revalue(df$am, c("0"="Automatic", "1"="Manual"))
ggplot(df, aes(fill = cyl, x = am, y = mpg)) +
geom_col(position = position_dodge(width = 0.9)) +
theme_bw()
Try using a combination of position=position_dodge(width=...) and width=...
For example:
ggplot(df, aes(fill = cyl, x = am, y = mpg)) +
geom_col(position = position_dodge(width = 0.9), width=0.8) +
theme_bw()
The width() command gives the displayed width of individual bars, while the position(width=) gives the space that is reserved for the bars.
The difference between the two values gives the space between bars within a group, while 1 - position_dodge(width=) gives the space between the groups.
I am attempting to make a faceted t-chart using ggplot2, where the x-axis is represented a sequence of events and the y-axis represents the number of days between those events. The x-axis should be labelled with the event date, but it is not a time series since the distance between x-axis ticks should be uniform regardless of the real time between events.
Adding a faceting layer has been confusing me. Here's some sample data:
df <- data.frame(EventDT = as.POSIXct(c("2014-11-22 07:41:00", "2015-02-24 08:10:00",
"2015-06-10 13:54:00", "2015-07-11 02:43:00",
"2015-08-31 19:08:00", "2014-11-18 14:06:00",
"2015-06-09 23:10:00", "2016-02-29 07:55:00",
"2016-05-22 04:30:00", "2016-05-25 21:46:00",
"2014-12-22 16:19:00", "2015-05-13 16:38:00",
"2015-06-01 09:05:00", "2016-02-21 02:30:00",
"2016-05-13 01:36:00")),
EventNBR = rep(1:5, 3),
Group = c(rep('A', 5), rep('B',5), rep('C',5)),
Y = c(15.818750, 94.020139, 106.238889, 30.534028, 51.684028,
187.670139, 203.377778, 264.364583, 82.857639, 3.719444,
169.829861, 142.013194, 18.685417, 264.725694,81.962500))
Ignoring the date of the event, I can produce this:
g <- ggplot(df, aes(x=EventNBR, y=Y)) +
geom_point() +
geom_line() +
facet_wrap(~ Group, scales='free_x')
Plot should show EventDT along X-axis, not EventNBR
I have tried to use the labels parameter to scale_x_discrete without success:
xaxis.ticks <- function(x) {
df[which(df$EventNBR) == x] }
g + scale_x_discrete(labels = xaxis.ticks)
But that's wrong in a way I can't describe, because it cuts off my tick labels altogether.
Because there is a 1-1 correspondence between EventNBR and EventDT by Group for this dataset, it seems like there should be an easy solution, but I can't figure it out. Am I overlooking something painfully easy?
In general, this is a very problematic thing as mentioned here and there are several other topics on this.
But luckily in your case it is possible since you use scales='free_x'.
What you need to do is adding an unique index column like
df$id <- 1:nrow(df)
and afterwards you can overwrite these indexes with you column with correct labels.
g <- ggplot(df, aes(x=id, y=Y)) +
geom_point() +
geom_line() +
facet_wrap(~ Group, scales='free_x')
g + scale_x_continuous(breaks=df$id, labels=df$EventDT) +
theme(axis.text.x=element_text(angle=90, vjust=.5))
There might be easier solutions but this is working in your example.
Also, the labels seem to be gone since the x axis is numeric and not discrete. So using scale_x_continuous produces the correct labels.
EDIT:
So a full example looks like this
library(ggplot2)
df <- data.frame(EventDT = as.POSIXct(c("2014-11-22 07:41:00", "2015-02-24 08:10:00",
"2015-06-10 13:54:00", "2015-07-11 02:43:00",
"2015-08-31 19:08:00", "2014-11-18 14:06:00",
"2015-06-09 23:10:00", "2016-02-29 07:55:00",
"2016-05-22 04:30:00", "2016-05-25 21:46:00",
"2014-12-22 16:19:00", "2015-05-13 16:38:00",
"2015-06-01 09:05:00", "2016-02-21 02:30:00",
"2016-05-13 01:36:00")),
EventNBR = rep(1:5, 3),
Group = c(rep('A', 5), rep('B',5), rep('C',5)),
Y = c(15.818750, 94.020139, 106.238889, 30.534028, 51.684028,
187.670139, 203.377778, 264.364583, 82.857639, 3.719444,
169.829861, 142.013194, 18.685417, 264.725694,81.962500))
df$id <- 1:nrow(df)
g <- ggplot(df, aes(x=id, y=Y)) +
geom_point() +
geom_line() +
facet_wrap(~ Group, scales='free_x')
g + scale_x_continuous(breaks=df$id, labels=df$EventDT) +
theme(axis.text.x=element_text(angle=90, vjust=.5))
and produces the following output:
I have a ggplot in which I am using color for my geom_points as a function of one of my columns(my treatment) and then I am using the scale_color_manual to choose the colors.
I automatically get my legend right
The problem is I need to graph some horizontal lines that have to do with the experimental set up, which I am doing with geom_vline, but then I don't know how to manually add a separate legend that doesn't mess with the one I already have and that states what those lines are.
I have the following code
ggplot(dcons.summary, aes(x = meters, y = ymean, color = treatment, shape = treatment)) +
geom_point(size = 4) +
geom_errorbar(aes(ymin = ymin, ymax = ymax)) +
scale_color_manual(values=c("navy","seagreen3"))+
theme_classic() +
geom_vline(xintercept = c(0.23,3.23, 6.23,9.23), color= "bisque3", size=0.4) +
scale_x_continuous(limits = c(-5, 25)) +
labs(title= "Sediment erosion", subtitle= "-5 -> 25 meters; standard deviation; consistent measurements BESE & Control", x= "distance (meters)", y="erosion (cm)", color="Treatment", shape="Treatment")
So I would just need an extra legend beneath the "treatment" one that says "BESE PLOTS LOCATION" and that is related to the gray lines
I have been searching for a solution, I've tried using "scale_linetype_manual" and also "guides", but I'm not getting there
As you provided no reproducible example, I used data from the mtcars dataset.
In addition I modified this similar answer a little bit. As you already specified the color and in addition the fill factor is not working here, you can use the linetype as a second parameter within aes wich can be shown in the legend:
xid <- data.frame(xintercept = c(15,20,30), lty=factor(1))
mtcars %>%
ggplot(aes(mpg ,cyl, col=factor(gear))) +
geom_point() +
geom_vline(data=xid, aes(xintercept=xintercept, lty=lty) , col = "red", size=0.4) +
scale_linetype_manual(values = 1, name="",label="BESE PLOTS LOCATION")
Or without the second data.frame:
ggplot() +
geom_point(data = mtcars,aes(mpg ,cyl, col=factor(gear))) +
geom_vline(aes(xintercept=c(15,20,30), lty=factor(1) ), col = "red", size=0.4)+
scale_linetype_manual(values = 1, name="",label="BESE PLOTS LOCATION")