geom_tile fill in confusion matrix correspond to value - r

I am trying to get the colours of a confusion matrix to correspond to the percent value in the middle of each matrix.
I have tried adjusting the geom_tile section fill to various options of Freq, or percentage, but with no luck.
valid_actualFunc <- as.factor(c(conf$ObsFunc))
valid_predFunc <- as.factor(c(conf$PredFunc))
cfmFunc <- confusionMatrix(valid_actualFunc, valid_predFunc)
ggplotConfusionMatrix <- function(m){
mytitle <- paste("Accuracy", percent_format()(m$overall[1]),
"Kappa", percent_format()(m$overall[2]))
data_c <- mutate(group_by(as.data.frame(m$table), Prediction ),
percentage=percent(Freq/sum(Freq)))
p <-
ggplot(data = data_c,
aes(x = Reference, y = Prediction)) +
geom_tile(aes(fill = Freq/sum(Freq)), colour = "white") +
scale_fill_gradient(low = "white", high = "red", na.value="white") +
geom_text(aes(x = Reference, y = Prediction, label = percentage)) +
theme(axis.text.x=element_text(angle = -90, hjust = 0),
axis.ticks=element_blank(), legend.position="none") +
ggtitle(mytitle)+
scale_y_discrete(limits = rev(levels(as.factor(valid_predFunc))))
return(p)
}
conf2Func=ggplotConfusionMatrix(cfmFunc)
conf2Func
Currently the fill is not equal to the value in the middle, i.e. a tile with 89% is lighter than one with 70%
As per the comment the return is
dput(head(cfmFunc))
list(positive = NULL, table = structure(c(2331L, 102L, 262L,
52L, 290L, 1986L, 178L, 89L, 495L, 74L, 2966L, 52L, 189L, 58L,
92L, 800L), .Dim = c(4L, 4L), .Dimnames = list(Prediction = c("Algae",
"Hard Coral", "Other", "Other Inv"), Reference = c("Algae", "Hard Coral",
"Other", "Other Inv")), class = "table"), overall = c(Accuracy =
0.807008785942492,
Kappa = 0.730790156424558, AccuracyLower = 0.799141307917932,
AccuracyUpper = 0.814697342402988, AccuracyNull = 0.358126996805112,
AccuracyPValue = 0, McnemarPValue = 6.95780670112837e-62), byClass =
structure(c(0.848562067710229,
0.780967361384192, 0.826874825759688, 0.702370500438982,
0.866006328243225,
0.968687274187073, 0.917249961113703, 0.978258420637603,
0.705295007564297,
0.894594594594595, 0.847913093196112, 0.805639476334341,
0.938012218745343,
0.928553104155977, 0.904725375882172, 0.962429347223761,
0.705295007564297,
0.894594594594595, 0.847913093196112, 0.80563947633434, 0.848562067710229,
0.780967361384192, 0.826874825759688, 0.702370500438982,
0.770323859881031,
0.833928196514802, 0.837261820748059, 0.75046904315197, 0.274261182108626,
0.253893769968051, 0.358126996805112, 0.113718051118211,
0.232727635782748,
0.198282747603834, 0.296126198083067, 0.0798722044728434,
0.329972044728434,
0.221645367412141, 0.349241214057508, 0.0991413738019169,
0.857284197976727,
0.874827317785633, 0.872062393436696, 0.840314460538292), .Dim = c(4L,
11L), .Dimnames = list(c("Class: Algae", "Class: Hard Coral",
"Class: Other", "Class: Other Inv"), c("Sensitivity", "Specificity",
"Pos Pred Value", "Neg Pred Value", "Precision", "Recall", "F1",
"Prevalence", "Detection Rate", "Detection Prevalence", "Balanced
Accuracy"
))), mode = "sens_spec", dots = list())

If you check the structure of your dataset to be plotted str(data_c), you will see that percentage is a character vector, and needs to be converted to numeric to be used as continuous input to the fill gradient.
data_c$percentage.numeric <- as.numeric(gsub("%", "", data_c$percentage))
You can use percentage.numeric for aes fill and percentage for aes label.
ggplot(data = data_c,
aes(x = Reference, y = Prediction)) +
geom_tile(aes(fill = percentage.numeric), colour = "white") +
scale_fill_gradient(low = "white", high = "red", na.value="white") +
geom_text(aes(x = Reference, y = Prediction, label = percentage)) +
theme(axis.text.x=element_text(angle = -90, hjust = 0),
axis.ticks=element_blank(), legend.position="none") +
ggtitle(mytitle)
Note scale_y_discrete(limits = rev(levels(as.factor(valid_predFunc)))) produces an error in your example
Error in as.factor(valid_predFunc) : object 'valid_predFunc' not found

Related

How to right-justify with hjust

from what I have been reading hjust takes a value from 0 to 1. 0 means left justified, 1 means right justified.
As you can see in my example it does not work like this for me. This is my code:
library(ggplot2)
abundance_environment <- read.table('/home/agalvez/data/environmental_data/vanellid/environmental_parameters.csv', sep="\t", header=TRUE)
lineplot9 <- ggplot(abundance_environment, aes( x = abundance_environment$Chlorophyll_A..mg.m..3., y = abundance_environment$log, group = abundance_environment$Depth_Nominal , colour = abundance_environment$Depth_Nominal)) +
geom_point( size =2, shape =16) +
xlab("Chlorophyll A (mg/m³)") + ylab("Relative abundance") + ggtitle("Abundance-Chlorophyll A") +
theme_bw() +
labs(colour = "Depth") +
stat_cor(method = "spearman", size= 3, p.accuracy = 0.001, r.accuracy = 0.001, hjust=1) +
geom_smooth(method= lm, se= FALSE, size= 1)
lineplot9
cor(x= abundance_environment$Chlorophyll_A..mg.m..3., y= abundance_environment$log, method = "spearman", use = "complete.obs")
As you can see, my correlation values appear in the wrong position. How could I solve that?
EDIT:
Result of
stat_cor(label.y.npc="top", label.x.npc = "right", method = "spearman", size= 3, p.accuracy = 0.001, r.accuracy = 0.001)
> dput(head(abundance_environment))
structure(list(OGA_ID = c(20L, 22L, 66L, 75L, 91L, 126L), sample_ID = structure(c(8L,
3L, 4L, 6L, 7L, 5L), .Label = c("TARA_A100001640", "TARA_N000000077",
"TARA_N010000218", "TARA_N010000238", "TARA_N010000586", "TARA_N010000911",
"TARA_N010000955", "TARA_N010000980"), class = "factor"), log = c(-5.57153717588776,
-6.37156046083652, -6.50881538403584, -6.32529538161919, -6.19086429282228,
-6.38251610427271), Chlorophyll_A..mg.m..3. = c(-0.0018, 1.98441,
-0.0081, 2.6546, -0.0018, 0.83187), Depth..m. = c(391L, 5L, 491L,
17L, 391L, 5L), PAR..mol.quanta.m..2.day. = c(0, NA, NA, NA,
0, 14.83323), O2..µmol.kg. = c(271.8744, 353.1935, 227.316,
373.061, 271.8744, 271.064125), NO3..µmol.l. = c(16.017641,
3.880872, 22.810319, NA, 16.017641, 4.467439), Iron_5m...µmol.l. = c(0.000208521,
0.000596423, 0.000596423, 0.001304139, 0.000208521, 0.000426156
), Ammonium_5m...µmol.l. = c(0.035179306, 0.018947516, 0.018947516,
0.002257904, 0.035179306, 0.007189205), Nitrite_5m...µmol.l. = c(0.348001957,
0.152390116, 0.152390116, 0.010750825, 0.348001957, 0.010129768
), Nitrate_5m...µmol.l. = c(2.06166782, 1.684819688, 1.684819688,
4.442976594, 2.06166782, 0.689068984)), row.names = c(NA, 6L), class = "data.frame")
Looks a bit as if you misinterpreted the working of hjust.
hjust=0 will align the label to the right of the label position,
hjust=1 will align the label to the left of the label position.
dat <- data.frame(
x = factor(1),
y = c(3, 2, 1),
hjust = c(0, .5, 1),
label = c("hjust = 0: right-aligned", "hjust = .5: aligned to the middle", "hjust = 1: left-aligned")
)
library(ggplot2)
ggplot(dat, aes(x, y)) +
geom_text(aes(label = label, hjust = hjust))
Created on 2022-09-28 with reprex v2.0.2
And for your example code and data you could use hjust=0 when you place the label on the left and hjust=1 in case you place it on the right:
library(ggplot2)
ggplot(abundance_environment, aes(x = Chlorophyll_A..mg.m..3., y = log, group = Depth..m., colour = Depth..m.)) +
geom_point(size = 2, shape = 16) +
xlab("Chlorophyll A (mg/m³)") +
ylab("Relative abundance") +
ggtitle("Abundance-Chlorophyll A") +
theme_bw() +
labs(colour = "Depth") +
# Placed on the left, aligned to the right = hjust = 0
ggpubr::stat_cor(method = "spearman", size = 3, p.accuracy = 0.001, r.accuracy = 0.001, hjust = 0) +
# Placed on the right, aligned to the left = hjust = 1
ggpubr::stat_cor(label.x.npc = "right", method = "spearman", size = 3, p.accuracy = 0.001, r.accuracy = 0.001, hjust = 1) +
geom_smooth(method = lm, se = FALSE, size = 1)

Fixing elongated figures next to each other in R

I'm trying to replicate the theme of these graph using ggplot, I searched online for articles and question to show me how to assign these plots the right size and position and also to assign the tight dot shape, and I found few articles that discussed changing position, I tried the following:
d1<-read.csv("./data/games.csv")
p.1<-ggplot(d1, aes(x=cream_rating, y=charcoal_rating)) +
# Map winner on color. Add some transparency in case of overplotting
geom_point(aes(color = winner), alpha = 0.2) +
# Add the cross: Add geom_pints with one variable fixed on its mean
geom_point(aes(x = mean(cream_rating), color = winner), alpha = 0.2) +
geom_point(aes(y = mean(charcoal_rating), color = winner), alpha = 0.2) +
scale_shape_manual(values=c(16, 17)) +
# "draw"s should be dropped and removed from the title
scale_color_manual(values = c(cream = "seagreen4", charcoal = "chocolate3", draw = NA)) +
ggtitle("Rating of Cream vs Charcoal") +
xlab("rating of cream") + ylab("rating of charcoal") + theme_classic() + theme(plot.title = element_text(hjust = 0.5))
I tried the following to place them together:
require(gridExtra)
plot.1<-p.1
plot.2<-ggExtra::ggMarginal(p.1, type = "histogram")
grid.arrange(plot.1, plot.2, ncol=3)
library(cowplot)
theme_set(theme_cowplot())
plot.1<-p.1
plot.2<-ggExtra::ggMarginal(p.1, type = "histogram")
plot_grid(plot.1, plot.2, labels = "AUTO")
cowplot::plot_grid(plot.1, plot.2, labels = "AUTO")
library(magrittr)
library(multipanelfigure)
figure1 <- multi_panel_figure(columns = 2, rows = 1, panel_label_type = "none")
# show the layout
figure1
figure1 %<>%
fill_panel(plot.1, column = 1, row = 1) %<>%
fill_panel(plot.2, column = 2, row = 1) %<>%
figure1
This is my data set structure:
structure(list(rated = c(FALSE, TRUE, TRUE, TRUE, TRUE, FALSE,
TRUE, FALSE, TRUE, TRUE), turns = c(13L, 16L, 61L, 61L, 95L,
5L, 33L, 9L, 66L, 119L), victory_status = structure(c(3L, 4L,
2L, 2L, 2L, 1L, 4L, 4L, 4L, 2L), .Label = c("draw", "mate", "outoftime",
"resign"), class = "factor"), winner = structure(c(2L, 1L, 2L,
2L, 2L, 3L, 2L, 1L, 1L, 2L), .Label = c("charcoal", "cream",
"draw"), class = "factor"), increment_code = structure(c(3L,
7L, 7L, 5L, 6L, 1L, 1L, 4L, 2L, 1L), .Label = c("10+0", "15+0",
"15+2", "15+30", "20+0", "30+3", "5+10"), class = "factor"),
cream_rating = c(1500L, 1322L, 1496L, 1439L, 1523L, 1250L,
1520L, 1413L, 1439L, 1381L), charcoal_rating = c(1191L, 1261L,
1500L, 1454L, 1469L, 1002L, 1423L, 2108L, 1392L, 1209L)), row.names = c(NA,
10L), class = "data.frame")
This is what I want to achieve:
I tried Stefan's suggestion (which was great help) with some modifications:
d1<-read.csv("./data/games.csv")
ggplot(d1, aes(x=cream_rating, y=charcoal_rating)) +
##### Map winner on color. Add some transparency in case of overplotting
geom_point(aes(color = winner), alpha = 0.2) +
##### Add the cross: Add geom_pints with one variable fixed on its mean
geom_point(aes(x = mean(cream_rating), color = winner), alpha = 0.2) +
geom_point(aes(y = mean(charcoal_rating), color = winner), alpha = 0.2) +
scale_shape_manual(values=c(16, 17)) +
##### "draw"s should be dropped and removed from the title
scale_color_manual(values = c(cream = "seagreen4", charcoal = "chocolate3", draw = NA)) +
ggtitle("Rating of Cream vs Charcoal") +
xlab("rating of cream") + ylab("rating of charcoal") + theme_bw() + theme(plot.title = element_text(hjust = 0.5))
I want to filter out "draw" from the plot, also when I change the dot shapes to triangles and circle, they don't seem to be changing, in addition I get this error:
Warning message:
“Removed 950 rows containing missing values (geom_point).”
Warning message:
“Removed 950 rows containing missing values (geom_point).”
Warning message:
“Removed 950 rows containing missing values (geom_point).”
One more thing that I noticed, I get double cross instead of one!
This is my output:
When I try the first code block in this question, I get long distorted figures not square next to each other.
Maybe this fits your need. To glue the three plots together I make use of the cowplot package. The legend is probably still not perfect.
To get only one legend but still a nice alignment of the plots I made the legends for the first and the third plot "transparent" vis guide_legend and theme options
To make all plots the same size I added transparent marginals to the scatter plot
To fix the position and make the plots square I set the same limits for both axes via xlim and ylim and set the aspect ratio to 1 using theme()
library(ggplot2)
library(dplyr)
library(cowplot)
# Add a second draw to the example data to make the density work
d1 <- d1 %>%
add_row(winner = "draw", cream_rating = 1002, charcoal_rating = 1250)
# Get the limits
lims <- c(floor(min(d1$cream_rating, d1$charcoal_rating)), ceiling(max(d1$cream_rating, d1$charcoal_rating)))
p1 <- d1 %>%
ggplot(aes(x=cream_rating, y=charcoal_rating, color = winner, shape = winner)) +
geom_point(alpha = 0.2, na.rm = TRUE) +
scale_color_manual(values = c(cream = "seagreen4", charcoal = "chocolate3", draw = "blue")) +
scale_shape_manual(values = c(cream = 16, charcoal = 17, draw = 15)) +
xlim(lims) +
ylim(lims) +
labs(x = "rating of cream", y = "rating of charcoal") +
theme_classic() +
theme(plot.title = element_text(hjust = 0.5), legend.position = "bottom") +
theme(aspect.ratio = 1)
p1_1 <- p1 +
guides(color = guide_legend(override.aes = list(color = c(NA, NA, NA)))) +
theme(legend.text = element_blank(), legend.title = element_blank())
p1_1 <- ggExtra::ggMarginal(p1_1, type = "histogram",
margins = 'both',
size = 5,
position = "identity",
color = NA,
fill= NA)
p2 <- ggExtra::ggMarginal(p1, type = "histogram",
margins = 'both',
size = 5,
groupColour = TRUE,
groupFill = TRUE,
position = "identity"
)
# Make legend transparent
p1 <- p1 +
guides(color = guide_legend(override.aes = list(color = c(NA, NA, NA)))) +
theme(legend.text = element_blank(), legend.title = element_blank())
p3 <- d1 %>%
ggplot(aes(x=cream_rating, y=charcoal_rating, color = winner, shape = winner)) +
geom_density_2d(na.rm = TRUE) +
geom_point(alpha = 0, show.legend = FALSE) +
scale_color_manual(values = c(cream = "seagreen4", charcoal = "chocolate3", draw = "blue")) +
xlim(lims) +
ylim(lims) +
labs(x = "rating of cream", y = "rating of charcoal") +
theme_classic() +
theme(plot.title = element_text(hjust = 0.5),
legend.position = "bottom") +
theme(aspect.ratio = 1)
# Make legend transparent
p3 <- p3 +
guides(color = guide_legend(override.aes = list(color = c(NA, NA, NA)))) +
theme(legend.text = element_blank(), legend.title = element_blank())
p3 <- ggExtra::ggMarginal(p3, d1, type = "density",
margins = 'both',
size = 5,
groupColour = TRUE,
groupFill = TRUE,
position = "identity"
)
plot_row <- plot_grid(p1_1, p2, p3, nrow = 1)
# now add the title
title <- ggdraw() +
draw_label(
"Rating of Cream vs Charcoal",
fontface = 'bold',
x = 0,
hjust = 0
)
final <- plot_grid(
title, plot_row,
ncol = 1,
# rel_heights values control vertical title margins
rel_heights = c(0.1, 1)
)
final
Note Depending on the width and heigth of your plotting device, fixing the aspect ratio adds some white space at the top and bottom. Depending on your final output you probably have to play a bit around with the width and height (and scale), e.g. using
ggsave("final.png", width = 18, height = 6, units = "cm", scale = 1.5)
gives

adjusting position of text above an error bar in ggplot

I have the following data frame:
df <- structure(list(Gender = c("M", "M", "M", "M", "F", "F", "F",
"F"), HGGroup = structure(c(1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L), .Label =
c("Low: \n F: <11.5, M: <12.5",
"Medium: \n F: > 11.5 & < 13, M: >12.5 & < 14.5", "High: \n F: >= 13, M >=
14.5", "No data"), class = "factor"), MeanBlood = c(0.240740740740741,
1.20689655172414, 0.38150289017341, 0.265957446808511, 0.272727272727273,
1.07821229050279, 0.257309941520468, 0.288776796973518), SEBlood =
c(0.0694516553311722, 0.154646785911315, 0.0687932999815165,
0.0383529942166715, 0.0406072582435844, 0.0971802933392401,
0.0327856332532931, 0.0289636037703526),
N = c(108L, 116L, 173L, 376L, 319L, 179L, 342L, 793L)), row.names = c(NA,
-8L), class = c("tbl_df", "tbl", "data.frame"))
I have the following command for plotting the means and confidence intervals for each group:
ggplot(df, aes(x = Gender, y = MeanBlood, colour = Gender)) +
geom_errorbar(aes(ymin = MeanBlood - SEBlood*qnorm(0.975), ymax = MeanBlood
+ SEBlood*qnorm(0.975)), width = 0.3, stat = "identity") +
geom_point(size = 3) + facet_grid(~HGGroup) + theme(legend.position =
"none") +
geom_text(aes(label = N, x = Gender), vjust = -5)
I am trying to get the text exactly on top of the error bar, but it needs to be in a different location for each group and currently comes out weird.
I think the problem originates from the fact that the confidence interval has a different length for each group, so that a constant justification would not work - it has to be relative to the lower quartile.
Any suggestions?
This seems to work, the y of your label, as you want it, is not the y set in the aes of ggplot, but is ymax:
ggplot(df, aes(x = Gender, y = MeanBlood, colour = Gender)) +
geom_errorbar(aes(ymin = MeanBlood - SEBlood*qnorm(0.975), ymax = MeanBlood
+ SEBlood*qnorm(0.975)), width = 0.3, stat = "identity") +
geom_point(size = 3) + facet_grid(~HGGroup) + theme(legend.position =
"none") +
geom_text(aes(y = MeanBlood + SEBlood*qnorm(0.975), label = N, x = Gender), vjust = -1)
If you move ymax to the ggplot call other layers will be able to access it so no need to redefine it:
ggplot(df, aes(x = Gender, y = MeanBlood, colour = Gender,
ymin = MeanBlood - SEBlood*qnorm(0.975), ymax = MeanBlood
+ SEBlood*qnorm(0.975))) +
geom_errorbar(aes(width = 0.3), stat = "identity") +
geom_point(size = 3) + facet_grid(~HGGroup) + theme(legend.position =
"none") +
geom_text(aes(y = stat(ymax), label = N, x = Gender), vjust = -1)

Using ggplot Geom_Ribbon in R to fill under a continuous line

I am trying to use geom_ribbon to fill an area under a geom_smooth line in ggplot and there are gaps under the curve where the color is not shaded. My data consists of six discrete values for proportion values on the y axis. Is there a way to use ymax in geom_ribbon differently to have the color meet the curved line better?
Here is the reproducible code for the data:
q1 <- structure(list(Session = 1:6, Counts = c(244L, 358L, 322L, 210L,
156L, 100L), Density_1000 = c(NA, NA, NA, NA, NA, NA), Proportion_Activity = c(0.175539568,
0.257553957, 0.231654676, 0.151079137, 0.112230216, 0.071942446
), Lifestage = structure(c(3L, 3L, 3L, 3L, 3L, 3L), .Label = c("Adult",
"Nymph", "Larvae"), class = "factor")), .Names = c("Session",
"Counts", "Density_1000", "Proportion_Activity", "Lifestage"), row.names = 13:18, class = "data.frame")
Here is the ggplot code:
ggplot(q1,aes(x=Session, y=Proportion_Activity, col = Lifestage,fill=Lifestage))
+ geom_smooth(method = 'loess')
+ geom_ribbon(data = q1,aes(x = Session, ymin=0, ymax=Proportion_Activity, alpha=0.5))
You can just use the area geom with the stat_smooth layer. For example
ggplot(q1,aes(x=Session, y=Proportion_Activity, col = Lifestage,fill=Lifestage)) +
geom_smooth(method = 'loess') +
stat_smooth(se=FALSE, geom="area", method = 'loess', alpha=.5)
Thou I really think smoothing should be used when you have a lot of data and want to show a general pattern. Using it like this to "smooth" the line to make it look pretty doesn't make it clear that you have modeled the results and shows data in places where you did not observe it.
You can do something like this.
p1 <- ggplot(q1,aes(x=Session, y=Proportion_Activity)) +
geom_smooth(method = 'loess', aes(color = Lifestage))
g1 <- ggplot_build(p1)
p2 <- data.frame(Session = g1$data[[1]]$x,
Proportion_Activity = g1$data[[1]]$y,
Lifestage = structure(g1$data[[1]]$group, .Label = c("Larvae", "Nymph", "Adult"), class = "factor"))
p1 + geom_ribbon(data = p2, aes(x = Session, ymin = 0, ymax = Proportion_Activity, fill = Lifestage), alpha = 0.5)
You can also use geom_line instead of geom_smooth.
geom_line(stat = "smooth", method = 'loess', alpha = 0.5, aes(color = Lifestage))
And remove the color from geom_smooth/geom_line if you want. Just add guides(color = FALSE) or fill if you want to remove that.

ggplot2 dotplot with facet_grid with labels on top ala facet_wrap (but w/ space = "free_x")?

I really like how my dotplot looks with facet_wrap (facet labels on top) but I'd ideally like to be able to pass it a space = "free_x" so the facets are sized appropriately. The problem with facet_grid is that the facet labels move to the side of the plot, which in this case doesn't work well because I want each panel to be separated.
Code follows:
# load data
plotdat <- structure(list(level = c("Lost (N =328)", "Won (N =75)", "Lost (N =10)",
"Won (N =65)", "Challenger (N =318)", "Incumbent (N =85)", "Arab (N =7)",
"Black (N =222)", "East Asian (N =40)", "Latino (N =107)", "Other (N =10)",
"South Asian (N =17)", "Not (N =252)", "Statewide (N =151)"),
mean = c(0.59834264517378, 0.645308353066667, 0.6382179387,
0.646399186046154, 0.595756747751572, 0.649457274258823,
0.682776774142857, 0.557334915725225, 0.6654738063, 0.68260777364486,
0.6061308922, 0.613378378411765, 0.616298597519841, 0.591703758423841
), se = c(0.00597842210656315, 0.0113080614816089, 0.044927778673023,
0.011274258338002, 0.00622316181664198, 0.00900474213888581,
0.0247451786416615, 0.00690804451732034, 0.0116899960061005,
0.00777478853477299, 0.0183766282892234, 0.0166464474073244,
0.00669527297092827, 0.00887170639612841), N = c(328L, 75L,
10L, 65L, 318L, 85L, 7L, 222L, 40L, 107L, 10L, 17L, 252L,
151L), var = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L,
4L, 4L, 4L, 4L, 5L, 5L), .Label = c("Primary Election", "General Election",
"Incumbency", "Race", "Statewide District"), class = "factor")), .Names = c("level",
"mean", "se", "N", "var"), row.names = c(NA, 14L), class = "data.frame")
library('ggplot2')
# with facet_wrap:
ggplot(plotdat, aes(x = mean, xmin = mean-se, xmax = mean+se, y = level)) +
geom_point() + geom_segment( aes(x = mean-se, xend = mean+se,
y = level, yend=level)) +
facet_wrap(~var, ncol=1, scales = "free_y") +
theme_bw() + opts(axis.title.x = theme_text(size = 12, vjust = .25))+
xlab("Mean V (Brightness) for Candidate's Face") + ylab("") +
opts(title = expression("Skin Complexion for 2010 Minority Candidates"))
# with facet_grid:
ggplot(plotdat, aes(x = mean, xmin = mean-se, xmax = mean+se, y = level)) +
geom_point() + geom_segment( aes(x = mean-se, xend = mean+se,
y = level, yend=level)) +
facet_grid(var~., scales = "free_y", space = "free_y") +
theme_bw() + opts(axis.title.x = theme_text(size = 12, vjust = .25))+
xlab("Mean V (Brightness) for Candidate's Face") + ylab("") +
opts(title = expression("Skin Complexion for 2010 Minority Candidates"))
Any suggestions? Thanks very much!
Update Using the ggplot grob, this is fairly easy to do. See here or here
ggplot grob version
library(ggplot2)
library(dplyr)
library(grid)
# Get the plot; plotdat data frame is below
p = ggplot(plotdat, aes(x = mean, xmin = mean-se, xmax = mean+se, y = level)) +
geom_point() + geom_segment( aes(x = mean-se, xend = mean+se,
y = level, yend=level)) +
facet_wrap(~var, ncol=1, scales = "free_y") +
theme_bw() + theme(axis.title.x = element_text(size = 12, vjust = .25))+
xlab("Mean V (Brightness) for Candidate's Face") + ylab("") +
ggtitle("Skin Complexion for 2010 Minority Candidates")
# From 'plotdat', get the number of 'levels' for each 'var'.
# That is, the number y-breaks in each panel.
N <- plotdat %>% group_by(var) %>%
summarise(count = n()) %>%
`[[`(2)
# Get the ggplot grob
gt = ggplotGrob(p)
# Get the locations of the panels in the gtable layout.
panels <- gt$layout$t[grepl("panel", gt$layout$name)]
# Replace the default panel heights with relative heights
gt$heights[panels] <- unit(N, "null")
## Draw gt
grid.newpage()
grid.draw(gt)
Original answer
EDIT: Updated to ggplot2 version 0.9.3.1
This is not going to answer your question. It tweaks the facet_grid look.
I'm not sure what you mean by "each panel being separated". If you are concerned that the strip text in the facet_grid plot extends beyond the boundaries of the strip, the text can be rotated using theme(strip.text.y = element_text(angle = 0)). Furthermore, the text can be made to wrap round to multiple lines using str_wrap from the stingr package.
# load data
plotdat <- structure(list(level = c("Lost (N =328)", "Won (N =75)", "Lost (N =10)",
"Won (N =65)", "Challenger (N =318)", "Incumbent (N =85)", "Arab (N =7)",
"Black (N =222)", "East Asian (N =40)", "Latino (N =107)", "Other (N =10)",
"South Asian (N =17)", "Not (N =252)", "Statewide (N =151)"),
mean = c(0.59834264517378, 0.645308353066667, 0.6382179387,
0.646399186046154, 0.595756747751572, 0.649457274258823,
0.682776774142857, 0.557334915725225, 0.6654738063, 0.68260777364486,
0.6061308922, 0.613378378411765, 0.616298597519841, 0.591703758423841
), se = c(0.00597842210656315, 0.0113080614816089, 0.044927778673023,
0.011274258338002, 0.00622316181664198, 0.00900474213888581,
0.0247451786416615, 0.00690804451732034, 0.0116899960061005,
0.00777478853477299, 0.0183766282892234, 0.0166464474073244,
0.00669527297092827, 0.00887170639612841), N = c(328L, 75L,
10L, 65L, 318L, 85L, 7L, 222L, 40L, 107L, 10L, 17L, 252L,
151L), var = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L,
4L, 4L, 4L, 4L, 5L, 5L), .Label = c("Primary Election", "General Election",
"Incumbency", "Race", "Statewide District"), class = "factor")), .Names = c("level",
"mean", "se", "N", "var"), row.names = c(NA, 14L), class = "data.frame")
library('ggplot2')
library(stringr)
plotdat$var = str_wrap(plotdat$var, width = 10)
# with facet_grid:
ggplot(plotdat, aes(x = mean, xmin = mean-se, xmax = mean+se, y = level)) +
geom_point() + geom_segment( aes(x = mean-se, xend = mean+se,
y = level, yend=level)) +
facet_grid(var~., scales = "free_y", space = "free_y") +
theme_bw() +
ggtitle("Skin Complexion for 2010 Minority Candidates") +
xlab("Mean V (Brightness) for Candidate's Face") + ylab("") +
theme(axis.title.x = element_text(size = 12, vjust = .25),
strip.text.y = element_text(angle = 0))
If "panels to be separated" means "additional space between the panels", use theme(panel.margin = unit(2, "line"), after loading grid.
library(grid)
ggplot(plotdat, aes(x = mean, xmin = mean-se, xmax = mean+se, y = level)) +
geom_point() + geom_segment( aes(x = mean-se, xend = mean+se,
y = level, yend=level)) +
facet_grid(var~., scales = "free_y", space = "free_y") +
theme_bw() +
ggtitle("Skin Complexion for 2010 Minority Candidates") +
xlab("Mean V (Brightness) for Candidate's Face") + ylab("") +
theme(axis.title.x = element_text(size = 12, vjust = .25),
strip.text.y = element_text(angle = 0),
panel.margin = unit(2, "lines"))

Resources