I have a dataframe which I've used to create a ggplot object faceted into three separate plots.
max_24h_lactate_cpet.long
First_24h_Lactate_Max, Lactate_Above_Threshold, Metric, Value
2.3, High, AT_VO2_mL.kg.min, 17.00
2.3, High, VO2_Peak, 84.07
2.3, High, AT_VE_VCO2, 35.00
In dput format:
dput(max_24h_lactate_cpet.long)
structure(list(First_24h_Lactate_Max = c(2.3, 2.3, 2.3), Lactate_Above_Threshold = structure(c(1L,
1L, 1L),
.Label = c("High", "Normal"), class = "factor"), Metric = structure(1:3, .Label = c("AT_VO2_mL.kg.min",
"VO2_Peak", "AT_VE_VCO2"), class = "factor"), Value = c(17, 84.07,
35)), .Names = c("First_24h_Lactate_Max", "Lactate_Above_Threshold",
"Metric", "Value"), row.names = c(44L, 192L, 340L), class = "data.frame")
I want to put geom_rect() objects on each of these facets, but with different ymin and ymax values for each plot.
Here's my current code:
max_24h_lac_vs_cpet <- ggplot(max_24h_lactate_cpet.long,
aes(x = max_24h_lactate_cpet.long$First_24h_Lactate_Max,
y = max_24h_lactate_cpet.long$Value))
max_24h_lac_vs_cpet + geom_point() +
facet_wrap( ~ Metric, scales="free_y") +
scale_color_brewer(palette="Set1") +
labs(x = "Max Lactate Value < 24h after surgery (mmol)",
y = "Test Metric Value") +
stat_smooth(method="lm") +
annotate("rect", xmin=-Inf, xmax=1.6, ymin=-Inf, ymax=Inf,alpha=0.1,fill="blue")
This gives the following plot:
I've got my thresholds (x and y limits for geom_rect() objects) in a separate dataframe as follows:
Metric xmin xmax ymin ymax
AT_VO2_mL.kg.min -Inf Inf -Inf 10.2
VO2_Peak -Inf Inf -Inf 75.0
AT_VE_VCO2 -Inf Inf 42 Inf
Dput code:
dput(thresholds)
structure(list(Metric = structure(c(2L, 3L, 1L), .Label = c("AT_VE_VCO2",
"AT_VO2_mL.kg.min", "VO2_Peak"), class = "factor"), xmin = c(-Inf,
-Inf, -Inf), xmax = c(Inf, Inf, Inf), ymin = c(-Inf, -Inf, 42
), ymax = c(10.2, 75, Inf)), .Names = c("Metric", "xmin", "xmax",
"ymin", "ymax"), class = "data.frame", row.names = c(NA, -3L))
And have added this code snippet to my ggplot call
+ geom_rect(data=thresholds$Metric, aes(xmin=xmin, xmax=xmax,
ymin=ymin, ymax=ymax,
alpha=0.1,fill="red"))
Which gives an error as follows:
Error: ggplot2 doesn't know how to deal with data of class factor
Using the following also gives an error:
+ geom_rect(data=thresholds, aes(xmin=xmin, xmax=xmax,
ymin=ymin, ymax=ymax,
alpha=0.1,fill="red"))
Error: Aesthetics must either be length one, or the same length as the
dataProblems:xmin, xmax, ymin, ymax
I've looked at examples on other questions, but am struggling to translate their answers to my own problem. Any help would be appreciated!
So you didn't provide us with labels, and only three rows of the first data set, so what follows is incomplete, but should demonstrate how to get the rect's working:
max_24h_lac_vs_cpet <- ggplot(max_24h_lactate_cpet.long,
aes(x = First_24h_Lactate_Max,
y = Value))
max_24h_lac_vs_cpet + geom_point() +
facet_wrap( ~ Metric, scales="free_y") +
scale_color_brewer(palette="Set1") +
labs(x = "Max Lactate Value < 24h after surgery (mmol)",
y = "Test Metric Value") +
stat_smooth(method="lm") +
geom_rect(data=thresholds, aes(x = NULL,y = NULL,xmin=xmin, xmax=xmax,
ymin=ymin, ymax=ymax,
alpha=0.1,fill="red"))
You were using $ in the first aes() call. Never do that. Then you need to un-map x and y in the geom_rect layer, since they are inherited from the top level ggplot call. The other option would be to use inherit.aes = FALSE.
Related
I've created a bar graph in R and now I tried to add the significant differences to the bar graph.
I've tried using geom_signif from the ggsignif package and stat_compare_means from the ggpubr package (based on these suggestions/examples: Put stars on ggplot barplots and boxplots - to indicate the level of significance (p-value) or https://cran.r-project.org/web/packages/ggsignif/vignettes/intro.html)
I was only able to add the significance levels when using geom_signif and choose the parameters as in https://cran.r-project.org/web/packages/ggsignif/vignettes/intro.html.
This is an example of what I would like to get:
And this is what I get:
So when I want to add the asterisks, it shifts the bars from the bar graph. I don't know how to change it...
This is a part of what I wrote:
bargraph = ggplot(dataPlotROI, aes(x = ROI, y=mean, fill = Group))
bargraph +
geom_bar(position = position_dodge(.5), width = 0.5, stat = "identity") +
geom_errorbar(position = position_dodge(width = 0.5), width = .2,
aes(ymin = mean-SEM, ymax = mean+SEM)) +
geom_signif(y_position = c(4.5,10,10), xmin=c(0.85,0.85,4.3), xmax = c(5,4,7.45),
annotation=c("***"), tip_length = 0.03, inherit.aes = TRUE) +
facet_grid(.~ROI, space= "free_x", scales = "free_x", switch = "x")
This is the output from dput(dataPlotROI):
> Dput <- dput(dataPlotROI)
structure(list(Group = structure(c(1L, 1L, 1L, 2L, 2L, 2L), .Label = c("1",
"2"), class = "factor"), ROI = structure(c(1L, 2L, 3L, 1L, 2L,
3L), .Label = c("LOT", "MO", "ROT"), class = "factor"), mean = c(2.56175803333696,
7.50825658538044, 3.34290874605435, 2.41750375190217, 6.90310020776087,
3.03040666678261), SD = c(1.15192431061913, 4.30564383354597,
2.01581544982848, 1.11404900115086, 3.35276625079825, 1.23786817391241
), SEM = c(0.120096411333424, 0.448894400545147, 0.210163288684092,
0.11614763735292, 0.349550045127766, 0.129056678481624)), class = "data.frame", row.names = c(NA,
-6L))
> Dput
Group ROI mean SD SEM
1 1 LOT 2.561758 1.151924 0.1200964
2 1 MO 7.508257 4.305644 0.4488944
3 1 ROT 3.342909 2.015815 0.2101633
4 2 LOT 2.417504 1.114049 0.1161476
5 2 MO 6.903100 3.352766 0.3495500
6 2 ROT 3.030407 1.237868 0.1290567
Does anyone know what I am doing wrong and how I can fix it?
Thanks!
I don't think geom_signif is meant to span across the facets, but in your case, I don't see any real need for facets anyway. See if the following works for you:
ggplot(dataPlotROI,
aes(x = ROI, y = mean, fill = Group)) +
# geom_col is equivalent to geom_bar(stat = "identity")
geom_col(position = position_dodge(0.5), width = 0.5) +
geom_errorbar(position = position_dodge(0.5), width = 0.2,
aes(ymin = mean - SEM, ymax = mean + SEM)) +
# xmin / xmax positions should match the x-axis labels' positions
geom_signif(y_position = c(4.5, 10, 10),
xmin = c(1, 1, 2.05),
xmax = c(3, 1.95, 3),
annotation = "***",
tip_length = 0.03)
I have two confusion matrices with calculated values as true positive (tp), false positives (fp), true negatives(tn) and false negatives (fn), corresponding to two different methods. I want to represent them as
I believe facet grid or facet wrap can do this, but I find difficult to start.
Here is the data of two confusion matrices corresponding to method1 and method2
dframe<-structure(list(label = structure(c(4L, 2L, 1L, 3L, 4L, 2L, 1L,
3L), .Label = c("fn", "fp", "tn", "tp"), class = "factor"), value = c(9,
0, 3, 1716, 6, 3, 6, 1713), method = structure(c(1L, 1L, 1L,
1L, 2L, 2L, 2L, 2L), .Label = c("method1", "method2"), class = "factor")), .Names = c("label",
"value", "method"), row.names = c(NA, -8L), class = "data.frame")
This could be a good start
library(ggplot2)
ggplot(data = dframe, mapping = aes(x = label, y = method)) +
geom_tile(aes(fill = value), colour = "white") +
geom_text(aes(label = sprintf("%1.0f",value)), vjust = 1) +
scale_fill_gradient(low = "white", high = "steelblue")
Edited
TClass <- factor(c(0, 0, 1, 1))
PClass <- factor(c(0, 1, 0, 1))
Y <- c(2816, 248, 34, 235)
df <- data.frame(TClass, PClass, Y)
library(ggplot2)
ggplot(data = df, mapping = aes(x = TClass, y = PClass)) +
geom_tile(aes(fill = Y), colour = "white") +
geom_text(aes(label = sprintf("%1.0f", Y)), vjust = 1) +
scale_fill_gradient(low = "blue", high = "red") +
theme_bw() + theme(legend.position = "none")
It is a very old question, still it seems there is a quite straight forward solution to that using ggplot2 which hasn't been mentioned.
Hope it might be helpful to someone:
cm <- confusionMatrix(factor(y.pred), factor(y.test), dnn = c("Prediction", "Reference"))
plt <- as.data.frame(cm$table)
plt$Prediction <- factor(plt$Prediction, levels=rev(levels(plt$Prediction)))
ggplot(plt, aes(Prediction,Reference, fill= Freq)) +
geom_tile() + geom_text(aes(label=Freq)) +
scale_fill_gradient(low="white", high="#009194") +
labs(x = "Reference",y = "Prediction") +
scale_x_discrete(labels=c("Class_1","Class_2","Class_3","Class_4")) +
scale_y_discrete(labels=c("Class_4","Class_3","Class_2","Class_1"))
A slightly more modular solution based on MYaseen208's answer. Might be more effective for large datasets / multinomial classification:
confusion_matrix <- as.data.frame(table(predicted_class, actual_class))
ggplot(data = confusion_matrix
mapping = aes(x = Var1,
y = Var2)) +
geom_tile(aes(fill = Freq)) +
geom_text(aes(label = sprintf("%1.0f", Freq)), vjust = 1) +
scale_fill_gradient(low = "blue",
high = "red",
trans = "log") # if your results aren't quite as clear as the above example
Here's another ggplot2 based option; first the data (from caret):
library(caret)
# data/code from "2 class example" example courtesy of ?caret::confusionMatrix
lvs <- c("normal", "abnormal")
truth <- factor(rep(lvs, times = c(86, 258)),
levels = rev(lvs))
pred <- factor(
c(
rep(lvs, times = c(54, 32)),
rep(lvs, times = c(27, 231))),
levels = rev(lvs))
confusionMatrix(pred, truth)
And to construct the plots (substitute your own matrix below as needed when setting up "table"):
library(ggplot2)
library(dplyr)
table <- data.frame(confusionMatrix(pred, truth)$table)
plotTable <- table %>%
mutate(goodbad = ifelse(table$Prediction == table$Reference, "good", "bad")) %>%
group_by(Reference) %>%
mutate(prop = Freq/sum(Freq))
# fill alpha relative to sensitivity/specificity by proportional outcomes within reference groups (see dplyr code above as well as original confusion matrix for comparison)
ggplot(data = plotTable, mapping = aes(x = Reference, y = Prediction, fill = goodbad, alpha = prop)) +
geom_tile() +
geom_text(aes(label = Freq), vjust = .5, fontface = "bold", alpha = 1) +
scale_fill_manual(values = c(good = "green", bad = "red")) +
theme_bw() +
xlim(rev(levels(table$Reference)))
# note: for simple alpha shading by frequency across the table at large, simply use "alpha = Freq" in place of "alpha = prop" when setting up the ggplot call above, e.g.,
ggplot(data = plotTable, mapping = aes(x = Reference, y = Prediction, fill = goodbad, alpha = Freq)) +
geom_tile() +
geom_text(aes(label = Freq), vjust = .5, fontface = "bold", alpha = 1) +
scale_fill_manual(values = c(good = "green", bad = "red")) +
theme_bw() +
xlim(rev(levels(table$Reference)))
Here it is a reprex using cvms package i.e., Wrapper function for ggplot2 to make confusion matrix.
library(cvms)
library(broom)
library(tibble)
library(ggimage)
#> Loading required package: ggplot2
library(rsvg)
set.seed(1)
d_multi <- tibble("target" = floor(runif(100) * 3),
"prediction" = floor(runif(100) * 3))
conf_mat <- confusion_matrix(targets = d_multi$target,
predictions = d_multi$prediction)
# plot_confusion_matrix(conf_mat$`Confusion Matrix`[[1]], add_sums = TRUE)
plot_confusion_matrix(
conf_mat$`Confusion Matrix`[[1]],
add_sums = TRUE,
sums_settings = sum_tile_settings(
palette = "Oranges",
label = "Total",
tc_tile_border_color = "black"
)
)
Created on 2021-01-19 by the reprex package (v0.3.0)
Old question, but I wrote this function which I think makes a prettier answer. Results in a divergent color palette (or whatever you want, but default is divergent):
prettyConfused<-function(Actual,Predict,colors=c("white","red4","dodgerblue3"),text.scl=5){
actual = as.data.frame(table(Actual))
names(actual) = c("Actual","ActualFreq")
#build confusion matrix
confusion = as.data.frame(table(Actual, Predict))
names(confusion) = c("Actual","Predicted","Freq")
#calculate percentage of test cases based on actual frequency
confusion = merge(confusion, actual, by=c('Actual','Actual'))
confusion$Percent = confusion$Freq/confusion$ActualFreq*100
confusion$ColorScale<-confusion$Percent*-1
confusion[which(confusion$Actual==confusion$Predicted),]$ColorScale<-confusion[which(confusion$Actual==confusion$Predicted),]$ColorScale*-1
confusion$Label<-paste(round(confusion$Percent,0),"%, n=",confusion$Freq,sep="")
tile <- ggplot() +
geom_tile(aes(x=Actual, y=Predicted,fill=ColorScale),data=confusion, color="black",size=0.1) +
labs(x="Actual",y="Predicted")
tile = tile +
geom_text(aes(x=Actual,y=Predicted, label=Label),data=confusion, size=text.scl, colour="black") +
scale_fill_gradient2(low=colors[2],high=colors[3],mid=colors[1],midpoint = 0,guide='none')
}
My data looks something like this:
df1 <-
structure(
list(
y = c(-0.19, 0.3,-0.05, 0.15,-0.05, 0.15),
lb = c(-0.61,
0.1,-0.19,-0.06,-0.19,-0.06),
ub = c(0.22, 0.51, 0.09, 0.36,
0.09, 0.36),
x = structure(
c(1L, 2L, 1L, 2L, 1L, 2L),
.Label = c("X1",
"X2"),
class = "factor"
),
Group = c("A", "A", "B", "B", "C",
"C")
),
.Names = c("y", "lb", "ub", "x", "Group"),
row.names = c(NA,-6L),
class = "data.frame"
)
I want to use ggplot2 to plotthe points x,y colored by group with error bars lb, ub. Because x is discrete, I want to jitter so the points and bars don't overlap. Right now, I can jitter the points but not the lines. Additionally, I would like to have the order of the point to be A,B,C
ggplot(data = df1, aes(x, y, color = Group)) + geom_point(size = 4, position = "jitter") +
geom_errorbar(
aes(ymin = lb, ymax = ub),
width = 0.1,
linetype = "dotted"
) +
geom_hline(aes(yintercept = 0), linetype = "dashed") + theme_bw()
You can use position_dodge to achieve both the desired order and the error bars being drawn at the location of the points
ggplot(data = df1, aes(x, y, color = Group)) +
geom_point(size = 4, position=position_dodge(width=0.5)) +
geom_errorbar(
aes(ymin = lb, ymax = ub),
width = 0.1,
linetype = "dotted",
position=position_dodge(width=0.5)) +
geom_hline(aes(yintercept = 0), linetype = "dashed") +
theme_bw()
If you want jitter, I do like this:
ggplot(data = df1, aes(x, y, color = Group)) +
geom_pointrange(aes(ymin = lb, ymax = ub),
position=position_jitter(width=0.5),
linetype='dotted') +
theme_bw()
I want to plot estimates for three age groups (agecat) by two exposures (expo). The code below produced overlapped plots with alphabetically rearranged age groups. How could I avoid overlap of the plots and plot maintain the existing order of the age groups?
I used this code:
ggplot(mydf, aes(x = agecat, y = est,ymin = lcl, ymax = ucl, group=agecat,color=agecat,shape=agecat)) +
geom_point(position="dodge",size = 4) +
geom_linerange(position="dodge",size =0.7) +
geom_hline(aes(yintercept = 0)) +
labs(colour="Age Group", shape="Age Group") + theme(axis.title=element_text(face="bold",size="12"),axis.text=element_text(size=12,face="bold"))
Sample data:
> dput(mydf)
structure(list(expo = c(0, 1, 0, 1, 0, 1), est = c(0.290780632898979,
0.208093573361601, 0.140524761247529, 0.156713614649751, 0.444402395010579,
0.711469870845916), lcl = c(0.0679784035303221, -0.00413163014975071,
-0.208866152400888, -0.175393089838871, -0.227660022186016, 0.0755871550441212
), ucl = c(0.514078933380535, 0.420769190852455, 0.491138970050864,
0.489925205664665, 1.12099179726843, 1.35139300089608), agecat = c("young",
"young", "middle", "middle", "old", "old")), .Names = c("expo",
"est", "lcl", "ucl", "agecat"), row.names = c(2L, 4L, 6L, 8L,
10L, 12L), class = "data.frame")
I would do this by using expo as a variable in the plot. This would let ggplot know that you have overlap and so you need dodging at each level of your x variable. Once you do this, you can use position = position_dodge() directly in the two geoms and set the width argument to whatever you'd like. See the help page for position_dodge for examples of when you need to set width explicitly.
Here I'll replace group = agecat with group = expo. Using group instead of an aesthetic like shape means that there is no indication which point represents which expo level on the graphic.
mydf$agecat = factor(mydf$agecat, levels = c("young", "middle", "old"))
ggplot(mydf, aes(x = agecat, y = est, ymin = lcl, ymax = ucl, group = expo, color = agecat, shape = agecat)) +
geom_point(position = position_dodge(width = .5), size = 4) +
geom_linerange(position = position_dodge(width = .5), size = 0.7) +
geom_hline(aes(yintercept = 0)) +
labs(colour="Age Group", shape="Age Group") +
theme(axis.title = element_text(face="bold", size="12"),
axis.text = element_text(size=12, face="bold"))
You can convert the column agecat to factor with the levels in the desired order. Then, as Heroka pointed out in the comments, we can achieve a similar effect using facet_wrap:
mydf$agecat <- factor(mydf$agecat, levels=c("young", "middle", "old"))
ggplot(mydf, aes(x = agecat, y = est, ymin = lcl, ymax = ucl, group=agecat,color=agecat, shape=agecat)) +
geom_linerange(size =0.7) +
geom_hline(aes(yintercept = 0)) + labs(colour="Age Group", shape="Age Group") +
facet_wrap(agecat~est, scales="free_x", ncol=6) + geom_point(size = 4)+ theme(axis.title=element_text(face="bold",size="12"),axis.text=element_text(size=12,face="bold"),strip.text.x = element_blank())
I am using ggplot to plot time course data (fixation proportions over time to different objects on the screen) and want to use a ribbon to show the SE, but the ribbon itself has lines at the top and bottom edges, which makes reading the graph a bit harder. I haven't been able to figure out how to get rid of those edge lines. Here is my plot code:
ggplot(d, aes(Time, y, color = Object, fill = Object)) +
stat_summary(fun.y = "mean", geom = "line", size = 2) +
stat_summary(fun.data = "mean_se", geom = "ribbon", alpha = .3)
Any suggestions?
Here is a minimal working example. I've compressed my data to:
Time Object y lower upper
1 1000 C 0.12453389 0.04510504 0.2039627
2 1000 T 0.58826856 0.37615078 0.8003864
3 1000 U 0.09437160 0.03278069 0.1559625
4 1100 C 0.12140127 0.03943988 0.2033627
5 1100 T 0.64560823 0.44898727 0.8422292
6 1100 U 0.06725172 0.01584248 0.1186610
d <- structure(list(Time = c(1000L, 1000L, 1000L, 1100L, 1100L, 1100L), Object = structure(c(1L, 2L, 3L, 1L, 2L, 3L), .Label = c("C",
"T", "U"), class = "factor"), y = c(0.12453389, 0.58826856, 0.0943716,
0.12140127, 0.64560823, 0.06725172), lower = c(0.04510504, 0.37615078,
0.03278069, 0.03943988, 0.44898727, 0.01584248), upper = c(0.2039627,
0.8003864, 0.1559625, 0.2033627, 0.8422292, 0.118661)), .Names = c("Time",
"Object", "y", "lower", "upper"), class = "data.frame", row.names = c("1",
"2", "3", "4", "5", "6"))
and here is the new plot code:
ggplot(d, aes(Time, y, color = Object, fill = Object)) +
geom_line(size = 2) +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = .3)
You can remove the border using the colour argument:
ggplot(d, aes(Time, y, color = Object, fill = Object)) +
geom_line(size = 2) +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = .3, colour = NA)
geom_ribbon understands linetype aesthetic. If you want to map linetype to a variable include it in the aes() argument, otherwise, place linetype outside and just give it 0, like so:
ggplot(d, aes(Time, y, color = Object, fill = Object)) +
geom_line(size = 2) +
geom_ribbon(aes(ymin = lower, ymax = upper), linetype = 0, alpha = .3)
More info here: http://docs.ggplot2.org/current/geom_ribbon.html
ggplot2's geom_ribbon() now includes an outline.type argument that helps control how the ribbon outlines are displayed.
Outline Type
library(tidyverse)
huron <- tibble(year = 1875:1972, level = as.vector(LakeHuron))
huron %>%
ggplot(aes(year, level)) +
geom_ribbon(aes(ymin = level - 1, ymax = level + 1),
fill = "grey70", color = "red",
outline.type = "lower") +
geom_line(aes(y = level))
Created on 2020-05-28 by the reprex package (v0.3.0)
Linetype = 0
Alternatively, as suggested we can set linetype = 0 to remove all lines.
library(tidyverse)
huron <- tibble(year = 1875:1972, level = as.vector(LakeHuron))
huron %>%
ggplot(aes(year, level)) +
geom_ribbon(aes(ymin = level - 1, ymax = level + 1),
fill = "grey70", color = "red", linetype = 0) +
geom_line(aes(y = level))
Created on 2020-05-28 by the reprex package (v0.3.0)
Here you go
ggplot(d, aes(Time, y, fill=Object)) +
geom_line(size=2, aes(colour = Object)) +
geom_ribbon(aes(ymin=lower, ymax=upper), alpha=.3)