How to make Ladder plot? - r

how can you make a ladder plot in R, please.
Here is a data example:
d <- data.frame("Subject" = 1:10,
"Group" = c(rep(1, 6), rep(2, 4)),
"Gender" = c(rep("male" ,2), rep("female", 6), rep("male", 2)),
"Y1" = rnorm(10, 100, 30),
"Y2" = rnorm(10, 3000, 1000))
in this ladderplot:
Need to show those with high Y1 also have high Y2
display the correlations for the "Group" and "Gender" factors
show the Y axis ticks on the left for Y1 and on the right for Y2
The two variables (Y1 and Y2) are to be connected for each subject with solid lines for Group 1 and dotted lines for Group 2, red for males and blue for females.
There is something about package plotrix but I cant seem to find details.

The ggplot2 library is so flexible, I'd use that, instead of looking for a canned routine. Here's code that has the basics of the ladder graph. Look at the existing documentation for things like secondary axes, and changing the scales of color & linetype. I'm leaving this so your post feels like it's asking a focused question (and won't be flagged as a request for a code writing service).
The important step below actually comes before the graphing call. Change your 'wide' format to 'long.
library(magrittr)
library(ggplot2)
set.seed(100)
d <- data.frame(
Subject = 1:10,
Group = c(rep(1, 6), rep(2, 4)),
Gender = c(rep("male" ,2), rep("female", 6), rep("male", 2)),
Y1 = rnorm(10, 100, 30),
Y2 = rnorm(10, 3000, 1000)
)
d_long <- d %>%
tidyr::gather(key=Time, value=Score, -Subject, -Group, -Gender) %>%
dplyr::mutate(
Group = factor(Group)
)
ggplot(d_long, aes(x=Time, y=Score, group=Subject, linetype=Group, color=Gender)) +
geom_line()
Results
> head(d_long)
Subject Group Gender Time Score
1 1 1 male Y1 84.93423
2 2 1 male Y1 103.94593
3 3 1 female Y1 97.63249
4 4 1 female Y1 126.60354
5 5 1 female Y1 103.50914
6 6 1 female Y1 109.55890

Thank you wibeasley for your input! it was greatly helpful. I used however the following code to generate my results.
# Melt dataset for plot:
library(reshape)
melted_data<-melt(d, id.vars=c("Subject","Group","Sex"),measure.vars= c("Y1","Y2"))
melted_data$Group<-as.factor(melted_data$Group)
# calcuate R2 per Group and Sex combination
require(plyr)
func <- function(xx)
{ return(data.frame(R2 = round (cor(xx$Y1, xx$Y2),6)))}
CorrDataset<-ddply(d, .(Group,Sex), func)
# plot:
library(gridExtra)
library(ggplot2)
set.seed(1)
p <-ggplot(melted_data, aes(x=variable, y=value, group=Subject, linetype=Group, color=Sex)) +
geom_line(size=1)
#p <- p + scale_y_continuous(sec.axis = sec_axis(~ scale(.), name = "Y2"))
p+theme(legend.position="top",
axis.line.x = element_line(color="black", size = 2),
axis.line.y = element_line(color="black", size = 2),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_blank())+
annotation_custom(tableGrob(CorrDataset,rows = rownames(CorrDataset)), ymin=4000, ymax=4000)
Please note: For the second Y axis, its commented out in the code above.

Related

How Insert an expression in legend in ggplot2?:: correct color + multiple lines and point

I am new to R and have not been able to correct the following graph.
Xb_exp, it should have blue dots.
Xb_dw, solid red line.
Xb_f, dotted line.
Xb_s, longdash line.
The legend expression should be as shown with the subscript.
I have not been able to correct it.
Is there a way to do this?
enter image description here
my data
CA <- c(3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30)
Xb_exp <- c(0.0231,0.0519,0.0839,0.1197,0.1595,0.1996,0.2384,0.2772,0.3153,0.3520,0.3887,0.4254,0.4615,0.4978,0.5339,0.5685,0.6000,0.6279,0.6528,0.6762,0.6974,0.7166,0.7346,0.7516,0.7669,0.7810,0.7940,0.8059)
Xb_dw <- c(0.0160,0.0516,0.0886,0.1259,0.1633,0.2006,0.2377,0.2749,0.3122,0.3496,0.3870,0.4245,0.4617,0.4984,0.5339,0.5678,0.5996,0.6288,0.6551,0.6786,0.6994,0.7179,0.7346,0.7499,0.7641,0.7774,0.7899,0.8018)
Xb_f <- c(0.0021,0.0031,0.0046,0.0067,0.0095,0.0131,0.0177,0.0234,0,0387,0.0483,0.0591,0.0709,0.0832,0.0955,0.1073,0.1181,0.1272,0.1345,0.1398,0.1443,0.1456,0.1468,0.1474,0.1476,0.1477,0.1477,0.1477,0.1477)
Xb_s <- c(0.0139,0.0484,0.0839,0.1192,0.1538,0.1874,0.2200,0.2515,0.2818,0.3108,0.3387,0.3653,0.3908,0.4151,0.4383,0.4604,0.4815,0.5015,0.5206,0.5387,0.5559,0.5722,0.5877,0.6024,0.6164,0.6264,0.6421,0.6040)
dat <- c(CA, Xb_exp, Xb_dw, Xb_f, Xb_s)
my code
labels = c(expression(X[b_exp]),expression(X[b_dw]),expression(X[b_f]),expression(X[b_s]))
color4 <- c("Xb_exp"="#3C5488FF", "Xb_dw"="#DC0000FF", "Xb_f"="#00A087FF", "Xb_s"="#4DBBD5FF")
Xb_D1 <- ggplot(data = dat) +
theme_bw() +
labs(x="Crank position (ºCA)", y= bquote('Burn fraction ('~X[b]~')')) +
geom_point(aes(x=CA, y=Xb_exp, colour="Xb_exp"), size=3) +
geom_line(aes(x=CA, y=Xb_dw,colour="Xb_dw"), size=1,linetype="solid") +
geom_line(aes(x=CA, y=Xb_f,colour="Xb_f"), size=1,linetype="dotted") +
geom_line(aes(x=CA, y=Xb_s,colour="Xb_s"), size=1,linetype="longdash") +
scale_colour_manual(values=color4, labels=labels) +
theme(legend.title = element_blank(),legend.position = c(0.8, 0.5),
legend.text = element_text(size = 12)) +
scale_x_continuous(limits = c(2,80))
plot(Xb_D1)
ggplot() requires a dataframe not a vector. If you modify your code with:
dat <- data.frame(CA, Xb_exp, Xb_dw, Xb_f, Xb_s)
and fix the typo in your Xb_f vector
Xb_f <- c(0.0021,0.0031,0.0046,0.0067,0.0095,0.0131,0.0177,0.0234,0.0387,0.0483,0.0591,0.0709,0.0832,0.0955,0.1073,0.1181,0.1272,0.1345,0.1398,0.1443,0.1456,0.1468,0.1474,0.1476,0.1477,0.1477,0.1477,0.1477)
Your remaining code will work as but could be achieved more simply using the tidyverse approach below. Use pivot_longer to stack the y variables against your x variable.
dat %>%
pivot_longer(Xb_exp:Xb_s) %>%
ggplot(aes(x = CA, y = value, colour = name)) +
geom_point() +
geom_line() +
scale_colour_manual(values=color4, labels=labels) +
theme_bw() +
theme(legend.title = element_blank(),legend.position = c(0.8, 0.5),
legend.text = element_text(size = 12)) +
scale_x_continuous(limits = c(2,80)) +
labs(x="Crank position (ºCA)", y= bquote('Burn fraction ('~X[b]~')')) ```
Ironically, setting this up with conventional ploting is rather simple:
Given all the data above:
linetypes4 <- c( Xb_exp=NA, Xb_dw="solid", Xb_f="dotted", Xb_s="longdash" )
plot(
NA, type="n", xlim=c(0,30), ylim=c(0,0.8),
xlab = "Crank position (ºCA)", ylab = bquote('Burn fraction ('~X[b]~')'),
panel.first = grid()
)
with( dat, {
points( x=CA, y=Xb_exp, pch=19, col=color4["Xb_exp"], size=3 )
for( n in c("Xb_dw", "Xb_f", "Xb_s")) {
lines( x=CA, y=get(n), lty=linetypes[n], col=color4[n], lwd=2 )
}
})
legend(
x = "right",
legend = labels,
col = color4,
lty = linetypes4,
pch = c(19,NA,NA,NA),
box.lwd = 0,
inset = .02
)
There are some errors in your code suggesting you didn't try what you pasted.
0,0387, in your data should likely be 0.0387, otherwise nothing is right (no data measures several hundreds in there)
c(CA, ... ) should likely be data.frame( CA, ... )
Now, the first problem is you are doing all the heavy lifting yourself, while ggplot sits there with nothing left to do. It was designed to set up colors and line types by group. You however need to transform the data first to take full advantage of that:
library(tidyr)
CA <- c(3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30)
Xb_exp <- c(0.0231,0.0519,0.0839,0.1197,0.1595,0.1996,0.2384,0.2772,0.3153,0.3520,0.3887,0.4254,0.4615,0.4978,0.5339,0.5685,0.6000,0.6279,0.6528,0.6762,0.6974,0.7166,0.7346,0.7516,0.7669,0.7810,0.7940,0.8059)
Xb_dw <- c(0.0160,0.0516,0.0886,0.1259,0.1633,0.2006,0.2377,0.2749,0.3122,0.3496,0.3870,0.4245,0.4617,0.4984,0.5339,0.5678,0.5996,0.6288,0.6551,0.6786,0.6994,0.7179,0.7346,0.7499,0.7641,0.7774,0.7899,0.8018)
Xb_f <- c(0.0021,0.0031,0.0046,0.0067,0.0095,0.0131,0.0177,0.0234,0.0387,0.0483,0.0591,0.0709,0.0832,0.0955,0.1073,0.1181,0.1272,0.1345,0.1398,0.1443,0.1456,0.1468,0.1474,0.1476,0.1477,0.1477,0.1477,0.1477)
Xb_s <- c(0.0139,0.0484,0.0839,0.1192,0.1538,0.1874,0.2200,0.2515,0.2818,0.3108,0.3387,0.3653,0.3908,0.4151,0.4383,0.4604,0.4815,0.5015,0.5206,0.5387,0.5559,0.5722,0.5877,0.6024,0.6164,0.6264,0.6421,0.6040)
dat <- data.frame(CA, Xb_exp, Xb_dw, Xb_f, Xb_s)
color4 <- c("Xb_exp"="#3C5488FF", "Xb_dw"="#DC0000FF", "Xb_f"="#00A087FF", "Xb_s"="#4DBBD5FF")
linetypes <- c( Xb_dw="solid", Xb_f="dotted", Xb_s="longdash" )
dat2 <- pivot_longer( dat, cols=starts_with("Xb_") )
dat2.line <- dat2 %>% filter( name != "Xb_exp" )
dat2.point <- dat2 %>% filter( name == "Xb_exp" )
dat2 is now a long data set, with data category as a variable, not with a separate column for each data series. This is how ggplot likes it:
dat2
# A tibble: 112 x 3
CA name value
<dbl> <fct> <dbl>
1 3 Xb_exp 0.0231
2 3 Xb_dw 0.016
3 3 Xb_f 0.0021
4 3 Xb_s 0.0139
5 4 Xb_exp 0.0519
6 4 Xb_dw 0.0516
7 4 Xb_f 0.0031
8 4 Xb_s 0.0484
9 5 Xb_exp 0.0839
10 5 Xb_dw 0.0886
# … with 102 more rows
I then split the data on what later goes to points and what goes ot lines, just not to make the plot code uglier than it has to be:
Xb_D1 <- ggplot(data = dat2.line, aes(x=CA,y=value,color=name)) +
theme_bw() +
labs(x="Crank position (ºCA)", y= bquote('Burn fraction ('~X[b]~')')) +
geom_point( data = dat2.point, size=3) +
geom_line( aes(col=name,lty=name), size=1 ) +
scale_colour_manual(values=color4) +
scale_linetype_manual( values=linetypes, guide=FALSE ) +
guides(
color = guide_legend( override.aes=list( shape=c(NA,19,NA,NA), linetype=c("solid","solid","dashed","dotted") ) )
) +
theme(legend.title = element_blank(),legend.position = c(0.8, 0.5),
legend.text.align = 0,
legend.text = element_text(size = 12)) +
scale_x_continuous(limits = c(2,30))
print(Xb_D1)
no need to supply labels
use line type as you would use color with ggplot, its just one more channel that can carry information (or aesthetic as they like to call it over there)
align the legends left, looks nicer that way
more sophisticated is the use of override.aes to take away the points from the legend categories who shouldn't have them.
Now, I was unable to change the order of the data series in the labels, that can be a hazzle. Is it still ok for you the order they are?

Barplots in pairs for each row of a dataframe

i'm fairly new to R so please excuse me for the noob question.
I have a dataframe that looks like this:
gene ctrl treated
gene_1 100 37.5
gene_2 100 20.2
... ... ...
For each row (ie each gene) in the df, I want to plot the values in such a way that ctrl and treated are one next to the other.
The code below gives something close to what i want, but the output is not grouped as it should: the bars for controls are plotted before the ones for treated samples.
barplot(height = df$df.ctrl1, df$df.avg_treated), names.arg = df$df.gene)
I know there are many similar questions, but i've gone through them with no success.
Anyone can help me understand what am i doing wrong?
Second (optional) question: what if i want to color-code the bars according to the gene id?
Many thanks.
I would use ggplot for this. Let's start with a slightly expanded example:
df <- data.frame(genes = c("gene_1", "gene_2", "gene_3", "gene_4"),
ctrl = c(50, 60, 70, 80),
treated = c(55, 64, 75, 83))
df
#> genes ctrl treated
#> 1 gene_1 50 55
#> 2 gene_2 60 64
#> 3 gene_3 70 75
#> 4 gene_4 80 83
The first thing we need to do is switch the dataframe to long format using tidyr::pivot_longer to put all your values in one column, and the labels of "ctrl" and "treatment" in another column. Then we can use ggplot to build our output:
library(tidyr)
library(ggplot2)
df %>%
pivot_longer(cols = c("ctrl", "treated")) %>%
ggplot(aes(name, value, fill = genes, alpha = name)) +
geom_col(position = position_dodge(), color = "black") +
scale_alpha_manual(values = c(0.5, 1), guide = guide_none()) +
facet_grid(~genes, scales = "free_x", switch = "x") +
theme(strip.placement = "outside",
panel.spacing = unit(0, "points"),
strip.background = element_blank(),
strip.text = element_text(face = "bold", size = 12)) +
labs(x = "Gene")
Created on 2020-08-22 by the reprex package (v0.3.0)
Consider transposing your data, converting into matrix with dimnames. Then run barplot with legend. Below demonstrates with random data. Note: ylim is adjusted for pretty range limit.
set.seed(92220)
df <- data.frame(gene = paste("gene", 1:30),
ctrl = runif(30, 50, 100),
treated = runif(30, 50, 100))
head(df)
# gene ctrl treated
# 1 gene 1 75.74607 76.15832
# 2 gene 2 61.73860 70.19874
# 3 gene 3 56.57906 63.67602
# 4 gene 4 60.23045 80.21108
# 5 gene 5 62.52773 60.86909
# 6 gene 6 85.71849 61.25974
# TRANSPOSE INTO MATRIX WITH DIMNAMES
dat <- `dimnames<-`(t(as.matrix(df[c("ctrl", "treated")])),
list(c("ctrl", "treated"), df$gene))
barplot(dat, beside=TRUE, col=c("blue", "red"), las=3,
main="Control Vs. Treatment",
ylim=range(pretty(c(0, dat*1.05))))
legend("top", legend=row.names(dat),
fill=c("blue", "red"), ncol=2, cex=0.75)

Split dataframe and Create multipanel scatterplots from list of data frames

I have a dataframe like so:
set.seed(453)
year= as.factor(c(rep("1998", 20), rep("1999", 16)))
lepsp= c(letters[seq(from = 1, to = 20 )], c('a','b','c'),letters[seq(from =8, to = 20 )])
freq= c(sample(1:15, 20, replace=T), sample(1:18, 16,replace=T))
df<-data.frame(year, lepsp, freq)
df<-
df %>%
group_by(year) %>%
mutate(rank = dense_rank(-freq))
Frequencies freq of each lepsp within each year are ranked in the rank column. Larger freq values correspond to the smallest rank value and smaller freq values have the largest rank values. Some rankings are repeated if levels of lepsp have the same abundance.
I would like to split the df into multiple subsets by year. Then I would like to plot each subsetted dataframe in a multipanel figure. Essentially this is to create species abundance curves. The x-axis would be rank and the yaxis needs to be freq.
In my real dataframe I have 22 years of data. I would prefer the graphs to be displayed as 2 columns of 4 rows for a total of 8 graphs per page. Essentially I would have to repeat the solution offered here 3 times.
I also need to demarcate the 25%, 50% and 75% quartiles with vertical lines to look like this (desired result):
It would be great if each graph specified the year to which it belonged, but since all axis are the same name, I do not want x and y labels to be repeated for each graph.
I have tried to plot multiple lines on the same graph but it gets messy.
year.vec<-unique(df$year)
plot(sort(df$freq[df$year==year.vec[1]],
decreasing=TRUE),bg=1,type="b", ylab="Abundance", xlab="Rank",
pch=21, ylim=c(0, max(df$freq)))
for (i in 2:22){
points(sort(df$freq[df$year==year.vec[i]], decreasing=TRUE), bg=i,
type="b", pch=21)
}
legend("topright", legend=year.vec, pt.bg=1:22, pch=21)
I have also tried a loop, however it does not produce an output and is missing some of the arguments I would like to include:
jpeg('pract.jpg')
par(mfrow = c(6, 4)) # 4 rows and 2 columns
for (i in unique(levels(year))) {
plot(df$rank,df$freq, type="p", main = i)
}
dev.off()
Update
(Attempted result)
I found the following code after my post which gets me a little closer, but is still missing all the features I would like:
library(reshape2)
library(ggplot2)
library (ggthemes)
x <- ggplot(data = df2, aes(x = rank, y = rabun)) +
geom_point(aes(fill = "dodgerblue4")) +
theme_few() +
ylab("Abundance") + xlab("Rank") +
theme(axis.title.x = element_text(size = 15),
axis.title.y = element_text(size = 15),
axis.text.x = element_text(size = 15),
axis.text.y = element_text(size = 15),
plot.title = element_blank(), # we don't want individual plot titles as the facet "strip" will give us this
legend.position = "none", # we don't want a legend either
panel.border = element_rect(fill = NA, color = "darkgrey", size = 1.25, linetype = "solid"),
axis.ticks = element_line(colour = 'darkgrey', size = 1.25, linetype = 'solid')) # here, I just alter to colour and thickness of the plot outline and tick marks. You generally have to do this when faceting, as well as alter the text sizes (= element_text() in theme also)
x
x <- x + facet_wrap( ~ year, ncol = 4)
x
I prefer base R to modify graph features, and have not been able to find a method using base R that meets all my criteria above. Any help is appreciated.
Here's a ggplot approach. First off, I made some more data to get the 3x2 layout:
df = rbind(df, mutate(df, year = year + 4), mutate(df, year = year + 8))
Then We do a little manipulation to generate the quantiles and labels by group:
df_summ =
df %>% group_by(year) %>%
do(as.data.frame(t(quantile(.$rank, probs = c(0, 0.25, 0.5, 0.75)))))
names(df_summ)[2:5] = paste0("q", 0:3)
df_summ_long = gather(df_summ, key = "q", value = "value", -year) %>%
inner_join(data.frame(q = paste0("q", 0:3), lab = c("Common", "Rare-75% -->", "Rare-50% -->", "Rare-25% -->"), stringsAsFactors = FALSE))
With the data in good shape, plotting is fairly simple:
library(ggthemes)
library(ggplot2)
ggplot(df, aes(x = rank, y = freq)) +
geom_point() +
theme_few() +
labs(y = "Abundance (% of total)", x = "Rank") +
geom_vline(data = df_summ_long[df_summ_long$q != "q0", ], aes(xintercept = value), linetype = 4, size = 0.2) +
geom_text(data = df_summ_long, aes(x = value, y = Inf, label = lab), size = 3, vjust = 1.2, hjust = 0) +
facet_wrap(~ year, ncol = 2)
There's some work left to do - mostly in the rarity text overlapping. It might not be such an issue with your actual data, but if it is you could pull the max y values into df_summ_long and stagger them a little bit, actually using y coordinates instead of just Inf to get it at the top like I did.

Add ticks in-between discrete groups on x-axis

I want to replace one of my grouped boxplots (below) to before-after kind, but keep it grouped. This one was made using ggboxplot() from ggpubr. I know there's also ggpaired() but I couldn't manage to make it grouped like this one.
Thanks to this question I was able to create grouped before-after graph like this one. I would now like to change the axis from 4 marks to just 2 (just "yes" and "no", since "before" and "after" are still in the legend.
Here's my code with dummy data:
library(tidyverse)
set.seed(123)
data.frame(ID = rep(LETTERS[1:10], 2),
consent = rep(sample(c("Yes", "No"), 10, replace = T), 2),
height = sample(rnorm(20, 170, sd = 10)),
ind = rep(c("before", "after"), each = 2)
) %>%
ggplot(aes(x = interaction(ind, consent), y = height, color = ind))+
geom_point()+
geom_line(aes(group = interaction(ID, consent)), color = "black")+
scale_x_discrete("response")
Is it even possible to reduce number of categories on axis? Or can I create grouped plot using ggpaired(), but without using facets?
Solution can be to create dummy numeric variable (in-between before and after) and put it on the x-axis. Then you can change it's names.
# Generate OP data
library(tidyverse)
set.seed(123)
df <- data.frame(ID = rep(LETTERS[1:10], 2),
consent = rep(sample(c("Yes", "No"), 10, replace = T), 2),
height = sample(rnorm(20, 170, sd = 10)),
ind = rep(c("before", "after"), each = 2)
)
df$name <- paste(df$consent, df$ind)
# Generate dummy numeric variable for `name` combinations
foo <- data.frame(name = c("Yes before", "Yes", "Yes after",
"No before", "No", "No after"),
X = 1:6)
# name X
# 1 Yes before 1
# 2 Yes 2
# 3 Yes after 3
# 4 No before 4
# 5 No 5
# 6 No after 6
And now we just need to map name to X and put it on x-axis:
df <- merge(foo, df)
ggplot(df, aes(X, height))+
geom_point(aes(color = ind)) +
geom_line(aes(group = interaction(ID, consent))) +
scale_x_continuous(breaks = c(2, 5), labels = foo$name[c(2, 5)])
#camille made me think about facety solution. Apparently, it is possible to put facet labels not just to the bottom of the plot, but even under the axis. Which solved my problem without having to modify my dataframe:
library(ggpubr) #for theme_pubr and JCO palette
ggplot(df, aes(x = ind, y = height, group = ID))+
geom_point(aes(color = ind), size = 3)+
geom_line()+
labs(y = "Height")+
facet_wrap(~ consent,
strip.position = "bottom", ncol = 5)+ #put facet label to the bottom
theme_pubr()+
color_palette("jco")+
theme(strip.placement = "outside", #move the facet label under axis
strip.text = element_text(size = 12),
strip.background = element_blank(),
axis.title.x = element_blank(),
legend.position = "none")
Result with dataframe from the question:

Using ggplot to plot occupied parking spaces in a parking lot

I’d like to use ggplot to draw a grid plot of the following scenario which I’ve attempted to depict in the picture below... I could use some guidance on how to logically think about the approach. Thank you for the guidance.
--
Each aisle in the example picture below has an odd number side—and an even number side
The spaces on the odd-side are listed ascending from 1… K where K is odd
The spaces on the even-side are listed ascending from 2…N where N is even
This pattern exists for each aisle in the parking lot
If a car is parked in a space—we track that spot in a database.
How can I reproduce a grid-level ggplot to indicate with a symbol on the plot all spaces where a car is parked?
The listing of occupied spaces would be “fed” into the ggplot logic via a .csv file: the format of the .csv would look something like this:
A01
A04
A05
A08
A09
A15
A20
A33
B07
B31
B44
C01
C04
C36
...
Image credit: Michael Layefsky, 2010, Google Images
My experience with direct use of grid is limited, so I can't say how hard this would be with grid functions, but it seems reasonably straightforward in ggplot2. Here's a simple example that is (I hope) not too far off from what you're looking for:
library(ggplot2)
# Set up grid of space identifiers
df = data.frame(y=1:10, x=rep(c(0:1, 3:4, 6:7), each=10),
space=paste0(rep(c("A","B","C"), each=20),
rep(c(seq(2,20,2),seq(1,20,2)), 3)),
stringsAsFactors=FALSE)
# Assume we have a vector of occupied spaces
set.seed(194)
occupied = sample(df$space, 30)
# Mark occupied spaces in data frame
df$status = ifelse(df$space %in% occupied, "Occupied", "Available")
ggplot(df) +
geom_segment(aes(x=x - 0.5, xend=x + 0.5, y=y, yend=y - 1)) +
geom_label(aes(label=space, x=x, y=y, fill=status), colour="blue", label.size=0) +
annotate(geom="segment", x=seq(0.5,6.5,3), xend=seq(0.5,6.5,3),
y=rep(0,3), yend=rep(10,3), lty="11") +
theme_bw(base_size=14) +
scale_fill_manual(values=c(hcl(c(105,15),100,65))) +
#scale_fill_manual(values=c(NA, hcl(15,100,65))) + # Color only occupied spaces
theme(axis.text = element_blank(),
axis.ticks = element_blank(),
panel.grid = element_blank()) +
labs(x="",y="",fill="")
If you are taking a list of only the occupied spots as input in the form that you showed, and then you want to produce a visualization of occupied spots using ggplot2, this approach will work. First, I process the input, turning it into something that I can give ggplot easily.
# the provided example data
d <- read.table(text="
A01
A04
A05
A08
A09
A15
A20
A33
B07
B31
B44
C01
C04
C36", stringsAsFactors=FALSE)
Split the "spaces" into meaningful coordinates. I kept the original space names around for later labeling. What follows is all manipulation used to get the plot set up correctly.
cars <- strsplit(d[,1], "(?<=[A-Z])", perl=TRUE) # split the raw data
# turn resulting list into data.frame and give it names
cars <- setNames(do.call(rbind.data.frame, cars), c("aisle","spot.num"))
# convert the from factors to numeric,
# and turn the aisle letter into numeric data for plotting
# retain the original spot id for labeling the plot
cars <- with(cars, data.frame(
spot.num = as.numeric(as.character(spot.num)),
aisle = aisle, # keep this around for faceting
aisle.coord = 2 * (utf8ToInt(paste(as.character(aisle), collapse="")) - utf8ToInt("A")),
spot.id = d[,1]))
I multiplied the aisle by 2 after converting A to 1, B to 2, and so on, to make a new variable called aisle.coord. The reason for multiplying by 2 is to set up a variable where each aisle can be composed of two lines:
# if the spot number is even, increment aisle by 1 (put it on the right).
# This is possible because I multiplied by 2 earlier
cars$aisle.coord[cars$spot.num %% 2 == 0] <- cars$aisle.coord[cars$spot.num %% 2 == 0] + 1
# We need to adjust the spot numbers to real row numbers
# i.e. A02 is in row 1, not row 2, A10 is in row 5, etc.
cars$spot <- ceiling(cars$spot.num / 2)
Now, the plotting:
library(ggplot2)
library(grid) # for unit()
ggplot(cars, aes(x = aisle.coord %% 2, y = spot)) +
geom_tile(width = 0.5, height = 0.8) +
facet_grid(~aisle) +
geom_text( aes(x = aisle.coord %% 2, y = spot, label = spot.id), color = "white")
That is a bare-bones attempt at the graph. Lots of room for you to improve and adjust it. Here is another attempt with a little more effort. Still, plenty of room for adjustment (e.g. you could adjust the plot so that a the full lot appears, not just the part of the lot up to the maximum spot: B44):
ggplot(cars, aes(x = aisle.coord %% 2, y = spot)) +
geom_tile(width = 0.5, height = 0.8, fill = "orange") +
facet_grid(~aisle) +
geom_text( aes(x = aisle.coord %% 2, y = spot, label = spot.id), color = "white", size = 4) +
annotate("rect", ymin = 0, ymax = max(cars$spot)+0.5, xmin = 0.3, xmax = 0.7, fill = "grey40") +
theme(panel.margin.x = unit(0.05, "lines"),
plot.background = element_rect("grey40"),
panel.background = element_rect("grey40"),
panel.grid.minor = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
strip.text = element_blank(),
strip.background = element_blank()) +
scale_y_continuous(breaks = seq(0.5, (max(cars$spot) + 0.5), 1)) +
scale_x_continuous(breaks = c(-0.3, 1.3)) +
geom_text(data=data.frame(x = 0.5, y = 10, aisle = LETTERS[1:length(unique(cars$aisle))]),
aes(x = x, y = y, label = aisle), inherit.aes = FALSE, color = "white")

Resources