I want to separate my histogram into two parts and zoom the second part. In short, I want to keep the histogram in the original shape, just zoom the x-axis tail.
Using mpg dataset as an example, I create a facet label according to 'displ' column and create a histogram plot.
mpg$displn<-scale(mpg$displ)
mpg$myFacet<-"01"
mpg$myFacet[mpg$displn>1]<-"02"
library(ggh4x)
ggplot(mpg,aes(x=displn))+geom_histogram(aes(y=..density..),binwidth = 0.1)+ facet_grid(. ~ myFacet, scales="free", space="free") + scale_x_continuous(breaks = seq(-1.5, 2.5, 1)) + theme(strip.text.x = element_blank())+ theme(panel.spacing=unit(0,'npc')) +force_panelsizes(cols = c(0.3, 1))
The question is the two facets using different 'y=..density..' and looks different from the original figure.
Is there any suggestion on how should I improve this?
Thanks in advance!
Typically, one would use ggforce::facet_zoom() for this purpose:
library(ggplot2)
library(ggforce)
ggplot(mpg, aes(x = scale(displ))) +
geom_histogram(aes(y = after_stat(density)), binwidth = 0.1) +
facet_zoom(xlim = c(1, 3))
Created on 2022-01-13 by the reprex package (v2.0.1)
The reason your original approach doesn't work is because densities are calculated by group, and data belonging to different panels are automatically separated into different groups.
Related
This question already has answers here:
How to add legend to plot with data from multiple data frames
(2 answers)
Closed 2 years ago.
I am using ggplot to create two overlapping density from two different data frames. I need to create a legend for each of the densities.
I have been trying to follow these two posts, but still cannot get it to work:
How to add legend to plot with data from multiple data frames
ggplot legends when plot is built from two data frames
Sample code of what I am trying to do:
df1 = data.frame(x=rnorm(1000,0))
df2 = data.frame(y=rnorm(2500,0.5))
ggplot() +
geom_density(data=df1, aes(x=x), color='darkblue', fill='lightblue', alpha=0.5) +
geom_density(data=df2, aes(x=y), color='darkred', fill='indianred1', alpha=0.5) +
scale_color_manual('Legend Title', limits=c('x', 'y'), values = c('darkblue','darkred')) +
guides(colour = guide_legend(override.aes = list(pch = c(21, 21), fill = c('darkblue','darkred')))) +
theme(legend.position = 'bottom')
Is it possible to manually create a legend?
Or do I need to restructure the data as per this post?
Adding legend to ggplot made from multiple data frames with controlled colors
I'm newish to R so hoping to avoid stacking the data into a single dataframe if I can avoid it as they are weighted densities so have to multiply by different weights as well.
Unlike x, y, label etc., when using the density geom, the color aesthetic can be used within aes(). In order to accomplish what you are looking for, the color aesthetic needs to be moved into aes() enabling you to utilize scale_color_manual. Within that, you can change the values= to whatever you like.
library(tidyverse)
ggplot() +
geom_density(data=df1, aes(x=x, color='darkblue'), fill='lightblue', alpha=0.5) +
geom_density(data=df2, aes(x=y, color='darkred'), fill='indianred1', alpha=0.5) +
scale_color_manual('Legend Title', limits=c('x', 'y'), values = c('darkblue','darkred')) +
guides(colour = guide_legend(override.aes = list(pch = c(21, 21), fill = c('darkblue','darkred')))) +
theme(legend.position = 'bottom')+
scale_color_manual("Legend title", values = c("blue", "red"))
Created on 2020-08-09 by the reprex package (v0.3.0)
I have several paired data points, representing the mean observation of various groups -/+ treatment, and I'd like to plot them side-by-side, organized by groups, with diagonal lines connecting the paired observations. Here is a toy example of the data, and what I have managed to come up with so far for graphing.
counts.example <- tibble(line=c('line1','line1','line2','line2'),
treatment=c('no','yes','no','yes'),
counts=c(150, 2000, 250, 300))
ggplot(counts.example, aes(x=line, y=counts)) + geom_point() + geom_line()
ggplot(counts.example, aes(x=1:nrow(counts.example), y=counts, group=line)) + geom_point() + geom_line()
The first example give the paired points aligned vertically, with the correct line labels underneath.
The second example has the desired staggered/diagonal organization, but it's kludgy and also doesn't permit labeling by line.
I suspect there is a simple and elegant way to do this with ggplot, but I haven't figured it out yet. Would appreciate any advice!
Maybe not the most elegant solution, but you can facet your plot and modify the facetting labeling to mimick the use of line as x labeling:
ggplot(counts.example,
aes(x= treatment, y = counts, group = line))+
geom_line()+
geom_point()+
facet_wrap(~line, switch = "x")+
theme(axis.text.x = element_blank(),
axis.ticks = element_blank(),
strip.background = element_blank(),
panel.spacing = unit(-1,"lines"))
Does it answer your question ?
You can create a manual dodge, use a continuous axis and fake a discrete axis.
library(tidyverse)
counts.example <- tibble(line=c('line1','line1','line2','line2'),
treatment=c('no','yes','no','yes'),
counts=c(150, 2000, 250, 300))
counts_df <- counts.example %>%
mutate(dodged = ifelse(treatment == 'no',
as.numeric(as.factor(line))-0.1,
as.numeric(as.factor(line))+0.1))
ggplot(counts_df, aes(x=dodged, y=counts)) +
geom_point() +
geom_line(aes( group = line)) +
scale_x_continuous(breaks = 1:2, labels = unique(counts_df$line))
Created on 2020-04-22 by the reprex package (v0.3.0)
But may I allow myself to suggest a simpler and possibly more convincing way of visualising your data. With the connecting lines - a fancy feature on a plot - you want to visualise change. But why not visualising it directly. I assume that this is what your story is about..
I am using geom_point, but as you are showing counts, you could actually use bar plots!
counts_wide <- counts.example %>%
pivot_wider(names_from = "treatment", values_from = "counts") %>%
mutate(change = yes-no)
ggplot(counts_wide, aes(x=no, y=change)) +
geom_point(aes(color = line)) +
labs(x = 'Baseline count')
Created on 2020-04-22 by the reprex package (v0.3.0)
I wanted to add significant stars over 3 facets to compare them.
I google online but it is so complicated to add things outside plot. There is a ggsignif package but it does nothing to facets (https://github.com/const-ae/ggsignif/issues/22). It seems possible using gridExtra but I cannot make it.
The stars can be draw easily in a single plot, not facets. But I have to use facets to have separate rugs on the left. If you know how to have separate rugs inside a single plot, it should also solve the problem.
Here is the code and plot I want to add things on:
library(ggplot2)
ToothGrowth$dose = factor(ToothGrowth$dose)
ggplot(ToothGrowth, aes(x='', y=len, color=dose)) +
geom_boxplot() +
geom_rug(sides="l") +
facet_grid(. ~ dose)
What I want is:
Sorry for the drawing. The line width should be the same. The final result should be really similar to this but for facets:
This is a workaround - plot two plots (one for significance annotation, another for boxplots).
library(ggplot2)
library(ggsignif)
ToothGrowth$dose <- factor(ToothGrowth$dose)
Plot significance annotation. Don't use boxplot here and set tips to 0 (using only one comparison here as others return error from statistical test, but I'm assuming that this is only an example dataset).
p1 <- ggplot(ToothGrowth, aes(as.factor(dose), len)) +
geom_signif(comparisons = list(c("1", "2")), tip_length = 0.005) +
coord_cartesian(ylim = c(35, 35.5)) +
theme_void()
Plot boxplots with different x axis (need this to specify comparisons groups in ggsignif)
p2 <- ggplot(ToothGrowth, aes(factor(dose), len)) +
geom_boxplot() +
geom_rug(sides = "l") +
facet_grid(. ~ dose, scales = "free_x") +
labs(x = NULL) +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank())
Draw plots together geom_signif on-top of geom_boxplot with facet_wrap
egg::ggarrange(p1, p2, heights = c(2, 10))
I'm using ggplot2 to make line graphs of some log-transformed data that all have large values (between 10^6 and 10^8); since the axes doesn't start at zero, I'd prefer not to have them intersect at the "origin."
Here's what the axes currently look like:
I'd prefer something more like one gets from base graphics (but I'm additionally using geom_ribbon and other fancy things I really like in ggplot2, so I'd prefer to find a ggplot2 solution):
Here's what I'm doing currently:
mydata <- data.frame(Day = rep(1:8, 3),
Treatment = rep(c("A", "B", "C"), each=8),
Value = c(7.415929, 7.200486, 7.040555, 7.096490, 7.056413, 7.143981, 7.429724, 7.332760, 7.643673, 7.303994, 7.343151, 6.923636, 6.923478, 7.249170, 7.513370, 7.438630, 7.209895, 7.000063, 7.160154, 6.677734, 7.026307, 6.830495, 6.863329, 7.319219))
ggplot(mydata, aes(x=Day, y=Value, group=Treatment))
+ theme_classic()
+ geom_line(aes(color = Treatment), size=1)
+ scale_y_continuous(labels = math_format(10^.x))
+ coord_cartesian(ylim = c(6.4, 7.75), xlim=c(0.5, 8))
plot(mydata$Day, mydata$Value, frame.plot = F) #non-intersecting axes
Workaround for this problem would be to remove axis lines with theme(axis.line=element_blank()) and then add false axis lines with geom_segment() - one for x axis and second for y axis. x, y , xend and yend values are determined from your plot (taken as the smallest and the largest values shown on plot for each corresponding axis) and axis limits used in coord_cartesian() (minimal value of limits to ensure that segment is plotted in place of axis).
ggplot(mydata, aes(x=Day, y=Value, group=Treatment)) +theme_classic() +
geom_line(aes(color = Treatment), size=1) +
scale_y_continuous(labels = math_format(10^.x))+
coord_cartesian(ylim = c(6.4, 7.75), xlim=c(0.5, 8))+
theme(axis.line=element_blank())+
geom_segment(x=2,xend=8,y=6.4,yend=6.4)+
geom_segment(x=0.5,xend=0.5,y=6.5,yend=7.75)
An older question. But since I was looking for this functionality recently I thought I'd flag the ggh4x package, which adds guides for truncating axes.
library(ggh4x)
#> Loading required package: ggplot2
ggplot(data.frame(x=0:10, y=0:10), aes(x, y)) +
geom_point() +
theme_classic() +
guides(x = "axis_truncated", y = "axis_truncated")
Created on 2023-02-17 with reprex v2.0.2
Apart from convenience, two nice things about the ggh4x option are that 1) it is stable across more complex plot compositions like faceting and 2) its dependencies are a subset of those belonging to ggplot2, so you aren't introducing a bunch of additional imports.
P.S. There's an open GitHub issue to bring this kind of "floating axes" functionality to the main ggplot2 library. It looks like it will eventually be incorporated.
Does anyone know how to create a scatterplot in R to create plots like these in PRISM's graphpad:
I tried using boxplots but they don't display the data the way I want it. These column scatterplots that graphpad can generate show the data better for me.
Any suggestions would be appreciated.
As #smillig mentioned, you can achieve this using ggplot2. The code below reproduces the plot that you are after pretty well - warning it is quite tricky. First load the ggplot2 package and generate some data:
library(ggplot2)
dd = data.frame(values=runif(21), type = c("Control", "Treated", "Treated + A"))
Next change the default theme:
theme_set(theme_bw())
Now we build the plot.
Construct a base object - nothing is plotted:
g = ggplot(dd, aes(type, values))
Add on the points: adjust the default jitter and change glyph according to type:
g = g + geom_jitter(aes(pch=type), position=position_jitter(width=0.1))
Add on the "box": calculate where the box ends. In this case, I've chosen the average value. If you don't want the box, just omit this step.
g = g + stat_summary(fun.y = function(i) mean(i),
geom="bar", fill="white", colour="black")
Add on some error bars: calculate the upper/lower bounds and adjust the bar width:
g = g + stat_summary(
fun.ymax=function(i) mean(i) + qt(0.975, length(i))*sd(i)/length(i),
fun.ymin=function(i) mean(i) - qt(0.975, length(i)) *sd(i)/length(i),
geom="errorbar", width=0.2)
Display the plot
g
In my R code above I used stat_summary to calculate the values needed on the fly. You could also create separate data frames and use geom_errorbar and geom_bar.
To use base R, have a look at my answer to this question.
If you don't mind using the ggplot2 package, there's an easy way to make similar graphics with geom_boxplot and geom_jitter. Using the mtcars example data:
library(ggplot2)
p <- ggplot(mtcars, aes(factor(cyl), mpg))
p + geom_boxplot() + geom_jitter() + theme_bw()
which produces the following graphic:
The documentation can be seen here: http://had.co.nz/ggplot2/geom_boxplot.html
I recently faced the same problem and found my own solution, using ggplot2.
As an example, I created a subset of the chickwts dataset.
library(ggplot2)
library(dplyr)
data(chickwts)
Dataset <- chickwts %>%
filter(feed == "sunflower" | feed == "soybean")
Since in geom_dotplot() is not possible to change the dots to symbols, I used the geom_jitter() as follow:
Dataset %>%
ggplot(aes(feed, weight, fill = feed)) +
geom_jitter(aes(shape = feed, col = feed), size = 2.5, width = 0.1)+
stat_summary(fun = mean, geom = "crossbar", width = 0.7,
col = c("#9E0142","#3288BD")) +
scale_fill_manual(values = c("#9E0142","#3288BD")) +
scale_colour_manual(values = c("#9E0142","#3288BD")) +
theme_bw()
This is the final plot:
For more details, you can have a look at this post:
http://withheadintheclouds1.blogspot.com/2021/04/building-dot-plot-in-r-similar-to-those.html?m=1