ggplot multiple lines colored as gradient - r

I'm currently struggling to wrap my head around the following objective:
a 2x2 facet grid
in each facet a couple of lines
each line colored according to some continuous variable
I not even get the simple example working. So far I have:
df <- data.frame(xval = rep(1:5, 8),
yval = runif(40),
pval = rep(c(rep(1,5), rep(2, 5)),4),
plt = rep(c(rep("mag", 10), rep("ph", 10)), 2),
p = c(rep("p1", 20), rep("p2", 20))
)
ggplot(df, aes(xval, yval)) +
geom_line(aes(colour = pval)) +
facet_grid(plt~p)
Would very much appreciate your help.

Since pval is not a factor variable you need to specify the grouping explicitly.
ggplot(df, aes(xval, yval)) +
geom_line(aes(colour = pval, group = pval)) +
facet_grid(plt~p)

Related

How to add captions outside the plot on individual facets in ggplot2?

I am trying to add a caption in each facet (I am using facet_grid). I have seen these approach and this one: but nothing gives me what I need. Also, the first approach returns a warning message that I didn't find any solution:
Warning message:
Vectorized input to `element_text()` is not officially supported.
Results may be unexpected or may change in future versions of ggplot2.
My example:
library(ggplot2)
library(datasets)
mydf <- CO2
a <- ggplot(data = mydf, aes(x = conc)) + geom_histogram(bins = 15, alpha = 0.75) +
labs(y = "Frequency") + facet_grid(Type ~ Treatment)
a
caption_df <- data.frame(
cyl = c(4,6),
txt = c("1st=4", "2nd=6")
)
a + coord_cartesian(clip="off", ylim=c(0, 3)) +
geom_text(
data=caption_df, y=1, x=100,
mapping=aes(label=txt), hjust=0,
fontface="italic", color="red"
) +
theme(plot.margin = margin(b=25))
The idea is to have 1 caption per plot, but with this approach it repeats the caption and it is overwritten.
Is it possible to have something like this? (caption OUTSIDE the plot) (but without the previous warning)
a + labs(caption = c("nonchilled=4", "chilled=6")) + theme(plot.caption = element_text(hjust=c(0, 1)))
NOTE: This is only an example, but I may need to put long captions (sentences) for each plot.
Example:
a + labs(caption = c("This is my first caption that maybe it will be large. Color red, n= 123", "This is my second caption that maybe it will be large. Color blue, n= 22")) +
theme(plot.caption = element_text(hjust=c(1, 0)))
Does anyone know how to do it?
Thanks in advance
You need to add the same faceting variable to your additional caption data frame as are present in your main data frame to specify the facets in which each should be placed. If you want some facets unlabelled, simply have an empty string.
caption_df <- data.frame(
cyl = c(4, 6, 8, 10),
conc = c(0, 1000, 0, 1000),
Freq = -1,
txt = c("1st=4", "2nd=6", '', ''),
Type = rep(c('Quebec', 'Mississippi'), each = 2),
Treatment = rep(c('chilled', 'nonchilled'), 2)
)
a + coord_cartesian(clip="off", ylim=c(0, 3), xlim = c(0, 1000)) +
geom_text(data = caption_df, aes(y = Freq, label = txt)) +
theme(plot.margin = margin(b=25))

Is there a way to create a ggplot facetted scatterplot with n colours, such that the colours alternate or are randomised from the palette?

I've got 40 subjects in my dataset, 4 in each group and I want to create a plot that shows a line for each subject replicate (3 replicates); colouring them by subject, shaping by replicate. The problem I have is that the colours are so similar in each facet (group) that I can't really tell them apart.
My main body of code for the plot is:
ggplot(T_S, aes(x=as.numeric(Day), y=variable, colour=as.factor(Subj))) +
geom_point(aes(shape=as.factor(Rep))) +
geom_line(aes(linetype=as.factor(Rep))) +
facet_wrap(.~Group,ncol=3) +
theme_bw() +
theme(legend.position="none")
And an example of what I mean by not being able to distinguish between colours is below using the viridis package. Is there a way to get the colours to alternate between the dark purple and yellow within each facet?
[Example with the Viridis Package][1]
Other things I've tried:
scale_color_brewer(palette="Dark2")
scale_fill_manual(values = wes_palette("GrandBudapest1", n = 38))
scale_color_gradientn(colours = rainbow(40))
I also looked into the PolyChrome and randomcoloR packages, but can't see how they work with ggplot2. Any other suggestions also welcome!
Thanks in advance for your help.
[1]: https://i.stack.imgur.com/2iHXY.png
It's difficult for anyone to give you a tested, working solution on Stack Overflow if you don't include a sample of your data in the question. However, after a bit of reverse-engineering I have created what should be a reasonable approximation of your data structure:
set.seed(69)
T_S <- data.frame(Day = rep(c(4, 11, 16, 25), 120),
Subj = rep(1:40, each = 12),
Rep = rep(rep(1:3, each = 4), 40),
Group = factor(rep(1:10, each = 48), c(2:10, 1)),
variable = c(replicate(120, cumsum(runif(4, 0, 400)) + 250)))
And we can see that with your plotting code, we get similar results:
library(ggplot2)
ggplot(T_S, aes(x=as.numeric(Day), y=variable, colour=as.factor(Subj))) +
geom_point(aes(shape=as.factor(Rep))) +
geom_line(aes(linetype=as.factor(Rep))) +
facet_wrap(.~Group,ncol=3) +
theme_bw() +
theme(legend.position="none") +
scale_colour_viridis_d()
The reason for this is that your subject numbers are consecutive and correlate completely with the group. For the purposes of plotting, we want just four colors - one for each subject in each panel. The easiest way to achieve this is to renumber the subjects to 1:4 within each panel.
T_S$Subj <- T_S$Subj %% 4 + 1
So now the exact same plotting code gives us:
ggplot(T_S, aes(x=as.numeric(Day), y=variable, colour=as.factor(Subj))) +
geom_point(aes(shape=as.factor(Rep))) +
geom_line(aes(linetype=as.factor(Rep))) +
facet_wrap(.~Group,ncol=3) +
theme_bw() +
theme(legend.position="none") +
scale_colour_viridis_d()
It appears that it can be done through the package "RColorBrewer", by the combination of colours through different palettes.
Using the simulated data from Allan Cameron:
require(ggplot2)
require(RColorBrewer)
set.seed(69)
T_S <- data.frame(Day = rep(c(4, 11, 16, 25), 120),
Subj = rep(1:40, each = 12),
Rep = rep(rep(1:3, each = 4), 40),
Group = factor(rep(1:10, each = 48), c(2:10, 1)),
variable = c(replicate(120, cumsum(runif(4, 0, 400)) + 250)))
Now we can combine the colours from different palettes:
mycolours = c(brewer.pal(name="Accent", n = 7),
brewer.pal(name="Dark2", n = 7),
brewer.pal(name="Paired", n = 7),
brewer.pal(name="Set3", n = 7),
brewer.pal(name="Dark2", n = 7),
brewer.pal(name="Set1", n = 7))
The palettes don't really matter in this instance, but I tried to choose them so they stood out. There is great documentation here for the full details on the colour palettes here: https://www.datanovia.com/en/blog/the-a-z-of-rcolorbrewer-palette/. More or fewer colours can be chosen as well, in this instance there are 42. Problems may occur if you need say, 1000 colours for instance, as there aren't that many in this package.
Finally the code to plot the data:
ggplot(T_S, aes(x=as.numeric(Day), y= variable, colour = as.factor(Subj))) +
geom_point(aes(shape = as.factor(Rep))) +
geom_line(aes(linetype = as.factor(Rep))) +
facet_wrap(.~Group, ncol = 3) +
theme_bw() +
theme(legend.position="none") +
scale_color_manual(values = mycolours)
https://imgur.com/fGsXy4k
GB

Adding Value Labels to Points from Two Lines Generated from One Dataframe

I need to add value labels for data points on two separate lines that are generated from a data frame in R using ggplot2. The following is the code snippet that I am using:
DataFrame = data.frame(Amount = c(results$Costs,
results$TotalPoC),
Legend = rep(c("Cost as % of initial costs",
"Revenue as % of cost"),
each = nrow(results)),
Year = rep(0:5,2))
p <- ggplot(ResultsCR, aes(x=Year, y=Amount, group=Legend)) +
geom_line(aes(linetype=Legend))+
geom_point(aes(shape=Legend))+
geom_text(aes(label=Amount))+
theme_classic(base_size = 15) +
ggtitle("Hospital Costs and Revenues")
print(p)
However, the graph is only displaying the labels on the second line, i.e. the one corresponding to the Legend "Revenue as % of cost". How can I generate labels for data points on all lines generated from the same data frame in ggplot2?
I am not able to reproduce your example. Can you please use this dataset to reproduce your problem or draw on it what you would like to change?
library(tidyverse)
set.seed(1)
df <-
tibble(
amount = sample(10:30, 10),
legend = rep(
c("Cost as % of initial costs",
"Revenue as % of cost"),
each = 5),
year = rep(1:5, 2)
)
ggplot(df, aes(x = year, y = amount, group = legend)) +
geom_line(aes(linetype = legend)) +
geom_point(aes(shape = legend)) +
geom_text(aes(label = amount), hjust = -1) +
theme_classic(base_size = 15) +
xlim(1, 5.5) +
ggtitle("Hospital Costs and Revenues")

Different size facets at x-axis

Length of x-axis is important for my plot because it allows one to compare between facets, therefore I want facets to have different x-axis sizes. Here is my example data:
group1 <- seq(1, 10, 2)
group2 <- seq(1, 20, 3)
x = c(group1, group2)
mydf <- data.frame (X =x , Y = rnorm (length (x),5,1),
groups = c(rep(1, length (group1)), rep(2, length(group2))))
And my code:
p1 = ggplot(data=mydf,aes(x=X,y=Y,color=factor(groups)) )+
geom_point(size=2)+
scale_x_continuous(labels=comma)+
theme_bw()
p1+facet_grid(groups ~ .,scales = "fixed",space="free_x")
And the resulting figure:
Panel-1 has x-axis values less then 10 whereas panel-2 has x-axis value extending to 20. Still both panels and have same size on x-axis. Is there any way to make x-axis panel size different for different panels, so that they correspond to their (x-axis) values?
I found an example from some different package that shows what I am trying to do, here is the figure:
Maybe something like this can get you started. There's still some formatting to do, though.
library(grid)
library(gridExtra)
library(dplyr)
library(ggplot2)
p1 <- ggplot(data=mydf[mydf$groups==1,],aes(x=X,y=Y))+
geom_point(size=2)+
theme_bw()
p2 <- ggplot(data=mydf[mydf$groups==2,],aes(x=X,y=Y))+
geom_point(size=2)+
theme_bw()
summ <- mydf %>% group_by(groups) %>% summarize(len=diff(range(X)))
summ$p <- summ$len/max(summ$len)
summ$q <- 1-summ$p
ng <- nullGrob()
grid.arrange(arrangeGrob(p1,ng,widths=summ[1,3:4]),
arrangeGrob(p2,ng,widths=summ[2,3:4]))
I'm sure there's a way to make this more general, and the axes don't line up perfectly yet, but it's a beginning.
Here is a solution following OP's clarifying comment ("I guess axis will be same but the boxes will be of variable size. Is it possible by plotting them separately and aligning in grid?").
library(plyr); library(ggplot2)
buffer <- 0.5 # Extra space around the box
#Calculate box parameters
mydf.box <- ddply(mydf, .(groups), summarise,
max.X = max(X) + buffer,
min.X = 0,
max.Y = max(Y) + buffer,
min.Y = 0,
X = mean(X), Y = mean(Y)) #Dummy values for X and Y needed for geom_rect
p2 <- ggplot(data=mydf,aes(x=X, y=Y) )+
geom_rect(data = mydf.box, aes( xmax = max.X, xmin = min.X,
ymax = max.Y, ymin = min.Y),
fill = "white", colour = "black", fill = NA) +
geom_point(size=2) + facet_grid(groups ~ .,scales = "free_y") +
theme_classic() +
#Extra formatting to make your plot like the example
theme(panel.background = element_rect(fill = "grey85"),
strip.text.y = element_text(angle = 0),
strip.background = element_rect(colour = NA, fill = "grey65"))

Any way to extend the line in the legend?

Let us say I have the following graph plotted using ggplot:
Is there anyway to extend how much line length is displayed in the legend? Sometimes, it just gets impossible to identify which line correspond to which line in the graph using the legend.
here is an option legend.key.width:
# sample data frame
df <- data.frame(x = c(rnorm(100, -3), rnorm(100), rnorm(100, 3)),
g = gl(3, 100))
df <- ddply(df, .(g), summarize, x = x, y = ecdf(x)(x))
ggplot(df, aes(x, y, colour = g, linetype = g)) +
geom_line() +
theme(legend.key.width = unit(10, "line"))
opts is not working with ggplot2. You need to use theme, so instead you need to type:
+ theme(legend.key.width = unit(10, "line"))

Resources