How do I create a categorical scatterplot in R like boxplots? - r

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

Related

Why is my ggplot2 bar graph not displaying?

I'm trying to plot bar graphs in ggplot2 and running into an issue.
Starting with the variables as this
PalList <- c(9, 9009, 906609, 99000099)
PalList1 <- as_tibble(PalList)
Index <- c(1,2,3,4)
PalPlotList <- cbind(Index, PalList)
PPL <- as_tibble(PalPlotList)
and loading the tidyverse library(tidyverse), I tried plotting like this:
PPL %>%
ggplot(aes(x=PalList)) +
geom_bar()
It doesn't matter whether I'm accessing PPL or PalList, I'm still ending up with this (axes and labels may change, but not the chart area):
Even this still gave a blank plot, only now in classic styling:
ggplot(PalList1, aes(value)) +
geom_bar() +
theme_classic()
If I try barplot(PalList), I get an expected result. But I want the control of ggplot. Any suggestions on how to fix this?
An option is to specify the x, y in aes, create the geom_bar with stat as 'identity', and change the x-axis tick labels
library(ggplot2)
ggplot(PPL, aes(x = Index, y = PalList)) +
geom_bar(stat = 'identity') +
scale_x_continuous(breaks = Index, labels = PalList)

plotting multiple geom-vline in a graph

I am trying to plot two ´geom_vline()´ in a graph.
The code below works fine for one vertical line:
x=1:7
y=1:7
df1 = data.frame(x=x,y=y)
vertical.lines <- c(2.5)
ggplot(df1,aes(x=x, y=y)) +
geom_line()+
geom_vline(aes(xintercept = vertical.lines))
However, when I add the second desired vertical line by changing
vertical.lines <- c(2.5,4), I get the error:
´Error: Aesthetics must be either length 1 or the same as the data (7): xintercept´
How do I fix that?
Just remove aes() when you use + geom_vline:
ggplot(df1,aes(x=x, y=y)) +
geom_line()+
geom_vline(xintercept = vertical.lines)
It's not working because the second aes() conflicts with the first, it has to do with the grammar of ggplot.
You should see +geom_vline as a layer of annotation to the graph, not like +geom_points or +geom_line which are for mapping data to the plot. (See here how they are in two different sections).
All the aesthetics need to have either length 1 or the same as the data, as the error tells you. But the annotations can have different lengths.
Data:
x=1:7
y=1:7
df1 = data.frame(x=x,y=y)
vertical.lines <- c(2.5,4)
ggplot(df1, aes(x = x, y = y)) +
geom_line() +
sapply(vertical.lines, function(xint) geom_vline(aes(xintercept = xint)))

3-variables plotting heatmap ggplot2

I'm currently working on a very simple data.frame, containing three columns:
x contains x-coordinates of a set of points,
y contains y-coordinates of the set of points, and
weight contains a value associated to each point;
Now, working in ggplot2 I seem to be able to plot contour levels for these data, but i can't manage to find a way to fill the plot according to the variable weight. Here's the code that I used:
ggplot(df, aes(x,y, fill=weight)) +
geom_density_2d() +
coord_fixed(ratio = 1)
You can see that there's no filling whatsoever, sadly.
I've been trying for three days now, and I'm starting to get depressed.
Specifying fill=weight and/or color = weight in the general ggplot call, resulted in nothing. I've tried to use different geoms (tile, raster, polygon...), still nothing. Tried to specify the aes directly into the geom layer, also didn't work.
Tried to convert the object as a ppp but ggplot can't handle them, and also using base-R plotting didn't work. I have honestly no idea of what's wrong!
I'm attaching the first 10 points' data, which is spaced on an irregular grid:
x = c(-0.13397460,-0.31698730,-0.13397460,0.13397460,-0.28867513,-0.13397460,-0.31698730,-0.13397460,-0.28867513,-0.26794919)
y = c(-0.5000000,-0.6830127,-0.5000000,-0.2320508,-0.6547005,-0.5000000,-0.6830127,-0.5000000,-0.6547005,0.0000000)
weight = c(4.799250e-01,5.500250e-01,4.799250e-01,-2.130287e+12,5.798250e-01,4.799250e-01,5.500250e-01,4.799250e-01,5.798250e-01,6.618956e-01)
any advise? The desired output would be something along these lines:
click
Thank you in advance.
From your description geom_density doesn't sound right.
You could try geom_raster:
ggplot(df, aes(x,y, fill = weight)) +
geom_raster() +
coord_fixed(ratio = 1) +
scale_fill_gradientn(colours = rev(rainbow(7)) # colourmap
Here is a second-best using fill=..level... There is a good explanation on ..level.. here.
# load libraries
library(ggplot2)
library(RColorBrewer)
library(ggthemes)
# build your data.frame
df <- data.frame(x=x, y=y, weight=weight)
# build color Palette
myPalette <- colorRampPalette(rev(brewer.pal(11, "Spectral")), space="Lab")
# Plot
ggplot(df, aes(x,y, fill=..level..) ) +
stat_density_2d( bins=11, geom = "polygon") +
scale_fill_gradientn(colours = myPalette(11)) +
theme_minimal() +
coord_fixed(ratio = 1)

Whisker plots to compare mean and variance between clusters [duplicate]

I am trying to recreate a figure from a GGplot2 seminar http://dl.dropbox.com/u/42707925/ggplot2/ggplot2slides.pdf.
In this case, I am trying to generate Example 5, with jittered data points subject to a dodge. When I run the code, the points are centered around the correct line, but have no jitter.
Here is the code directly from the presentation.
set.seed(12345)
hillest<-c(rep(1.1,100*4*3)+rnorm(100*4*3,sd=0.2),
rep(1.9,100*4*3)+rnorm(100*4*3,sd=0.2))
rep<-rep(1:100,4*3*2)
process<-rep(rep(c("Process 1","Process 2","Process 3","Process 4"),each=100),3*2)
memorypar<-rep(rep(c("0.1","0.2","0.3"),each=4*100),2)
tailindex<-rep(c("1.1","1.9"),each=3*4*100)
ex5<-data.frame(hillest=hillest,rep=rep,process=process,memorypar=memorypar, tailindex=tailindex)
stat_sum_df <- function(fun, geom="crossbar", ...) {stat_summary(fun.data=fun, geom=geom, ...) }
dodge <- position_dodge(width=0.9)
p<- ggplot(ex5,aes(x=tailindex ,y=hillest,color=memorypar))
p<- p + facet_wrap(~process,nrow=2) + geom_jitter(position=dodge) +geom_boxplot(position=dodge)
p
In ggplot2 version 1.0.0 there is new position named position_jitterdodge() that is made for such situation. This postion should be used inside the geom_point() and there should be fill= used inside the aes() to show by which variable to dodge your data. To control the width of dodging argument dodge.width= should be used.
ggplot(ex5, aes(x=tailindex, y=hillest, color=memorypar, fill=memorypar)) +
facet_wrap(~process, nrow=2) +
geom_point(position=position_jitterdodge(dodge.width=0.9)) +
geom_boxplot(fill="white", outlier.colour=NA, position=position_dodge(width=0.9))
EDIT: There is a better solution with ggplot2 version 1.0.0 using position_jitterdodge. See #Didzis Elferts' answer. Note that dodge.width controls the width of the dodging and jitter.width controls the width of the jittering.
I'm not sure how the code produced the graph in the pdf.
But does something like this get you close to what you're after?
I convert tailindex and memorypar to numeric; add them together; and the result is the x coordinate for the geom_jitter layer. There's probably a more effective way to do it. Also, I'd like to see how dodging geom_boxplot and geom_jitter, and with no jittering, will produce the graph in the pdf.
library(ggplot2)
dodge <- position_dodge(width = 0.9)
ex5$memorypar2 <- as.numeric(ex5$tailindex) +
3 * (as.numeric(as.character(ex5$memorypar)) - 0.2)
p <- ggplot(ex5,aes(x=tailindex , y=hillest)) +
scale_x_discrete() +
geom_jitter(aes(colour = memorypar, x = memorypar2),
position = position_jitter(width = .05), alpha = 0.5) +
geom_boxplot(aes(colour = memorypar), outlier.colour = NA, position = dodge) +
facet_wrap(~ process, nrow = 2)
p

How to obtain y-axis-labels in ggplot2? [duplicate]

I have created a function for creating a barchart using ggplot.
In my figure I want to overlay the plot with white horizontal bars at the position of the tick marks like in the plot below
p <- ggplot(iris, aes(x = Species, y = Sepal.Width)) +
geom_bar(stat = 'identity')
# By inspection I found the y-tick postions to be c(50,100,150)
p + geom_hline(aes(yintercept = seq(50,150,50)), colour = 'white')
However, I would like to be able to change the data, so I can't use static positions for the lines like in the example. For example I might change Sepal.With to Sepal.Height in the example above.
Can you tell me how to:
get the tick positions from my ggplot; or
get the function that ggplot uses for tick positions so that I can use this to position my lines.
so I can do something like
tickpositions <- ggplot_tickpostion_fun(iris$Sepal.Width)
p + scale_y_continuous(breaks = tickpositions) +
geom_hline(aes(yintercept = tickpositions), colour = 'white')
A possible solution for (1) is to use ggplot_build to grab the content of the plot object. ggplot_build results in "[...] a panel object, which contain all information about [...] breaks".
ggplot_build(p)$layout$panel_ranges[[1]]$y.major_source
# [1] 0 50 100 150
See edit for pre-ggplot2 2.2.0 alternative.
Check out ggplot2::ggplot_build - it can show you lots of details about the plot object. You have to give it a plot object as input. I usually like to str() the result of ggplot_build to see what all the different values it has are.
For example, I see that there is a panel --> ranges --> y.major_source vector that seems to be what you're looking for. So to complete your example:
p <- ggplot() +
geom_bar(data = iris, aes(x = Species, y = Sepal.Width), stat = 'identity')
pb <- ggplot_build(p)
str(p)
y.ticks <- pb$panel$ranges[[1]]$y.major_source
p + geom_hline(aes(yintercept = y.ticks), colour = 'white')
Note that I moved the data argument from the main ggplot function to inside geom_bar, so that geom_line would not try to use the same dataset and throw errors when the number in iris is not a multiple of the number of lines we're drawing. Another option would be to pass a data = data.frame() argument to geom_line; I cannot comment on which one is a more correct solution, or if there's a nicer solution altogether. But the gist of my code still holds :)
For ggplot 3.1.0 this worked for me:
ggplot_build(p)$layout$panel_params[[1]]$y.major_source
#[1] 0 50 100 150
for sure you can. Read the help file for the seq() function.
seq(from = min(), to = max(), len = 5)
and do something like this.
p <- ggplot(iris, aes(x = Species, y = Sepal.Width)) +
geom_bar(stat = 'identity')
p + geom_hline(aes(yintercept = seq(from = min(), to = max(), len = 5)), colour = 'white')

Resources