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)
Related
I am trying to recreate the graph that is provided by the function centralityPlot in qgraph. I got a dataframe that looks like this:
symptom structure(list(symptom = c("9", "8", "7", "6", "5", "4", "3",
"2", "1"), lower_bound = c(0.209023862993771, -0.656057911395765,
-0.144732954079441, -0.240150983834066, -2.09690619987396, -1.14713000698362,
-1.78304406354482, -1.31269792892215, -1.04552934099257), mean = c(1.35359542511945,
0.546873106351184, 0.787717966105717, 0.42221064177518, -1.18693181743255,
-0.284265955202698, -1.19008711707311, -0.377827032555581, -0.0712852170875892
), upper_bound = c(1.9749871489344, 1.54642345677796, 1.46727206716789,
1.10712439281518, -0.0748008645128608, 0.812125575894532, -0.510038969136605,
0.587753574399307, 0.981045133733119)), class = "data.frame", row.names = c(NA,
-9L))
it should look like a singular plot like this one
It's supposed to be doable in GGplot but so far What I've gotten is a complete mess:
temporal.dep.in.plot <- ggplot(temporal.dep.in, aes(x = symptom)) +
ylim(NA, 2.25) +
geom_errorbar(
aes(ymin = lower_bound, ymax = upper_bound),
width = 0.4,
color = "#56B4E9"
) +
geom_segment(
aes(y = lower_bound, yend = upper_bound, xend = symptom),
linetype = "solid",
color = "#2166AC",
size = 6
) +
geom_point(
aes(y = mean),
shape = 16,
size = 9,
color = "#D6604D"
) +
theme_classic() +
coord_flip() +
ylab("Z-scores") + xlab("Symptoms") +
theme(axis.text.y = element_text(
face = "bold",
colour = c(
"#ff0000",
"#ffaa00",
"#aaff00",
"#00ff00",
"#00ffaa",
"#00aaff",
"#0000ff",
"#aa00ff",
"#ff00aa"
),
size = 14
))
which honestly only works trough sheer force of will.
If that's too much, the main part that I'm trying to achieve right now is actually connecting the dots (mean) with a line, which so far has not been working with many methods that I've tried.
Not sure how your final plot should look like. As is it looks a quite different from the one in your image. But to connect your mean points to could use a geom_line where the important step is to set group aes to a constant value e.g. 1.
library(ggplot2)
ggplot(temporal.dep.in, aes(x = symptom)) +
ylim(NA, 2.25) +
geom_errorbar(
aes(ymin = lower_bound, ymax = upper_bound),
width = 0.4,
color = "#56B4E9"
) +
geom_segment(
aes(y = lower_bound, yend = upper_bound, xend = symptom),
linetype = "solid",
color = "#2166AC",
size = 6
) +
geom_point(
aes(y = mean),
shape = 16,
size = 6,
color = "#D6604D"
) +
geom_line(aes(y = mean, group = 1), color = "#D6604D", size = 1) +
theme_classic() +
coord_flip() +
ylab("Z-scores") +
xlab("Symptoms") +
theme(axis.text.y = element_text(
face = "bold",
colour = c(
"#ff0000",
"#ffaa00",
"#aaff00",
"#00ff00",
"#00ffaa",
"#00aaff",
"#0000ff",
"#aa00ff",
"#ff00aa"
),
size = 14
))
library(ggplot2)
library(directlabels)
mydat <- structure(list(Name = c("Ana", "Josh", "Bart", "Ana", "Josh",
"Bart"), color_line = c("purple", "purple", "orange", "purple",
"purple", "orange"), x = c(0.864864864864865, 0.810810810810811,
0.472972972972973, 0.851351351351351, 0.702702702702703, 0.648648648648649
), y = c(0.702702702702703, 0.675675675675676, 0.797297297297297,
0.797297297297297, 0.72972972972973, 0.635135135135135), Class = c("A",
"A", "A", "B", "B", "B")), class = c("data.table", "data.frame"
), row.names = c(NA, -6L))
mydat
Name color_line x y Class
1: Ana purple 0.8648649 0.7027027 A
2: Josh purple 0.8108108 0.6756757 A
3: Bart orange 0.4729730 0.7972973 A
4: Ana purple 0.8513514 0.7972973 B
5: Josh purple 0.7027027 0.7297297 B
6: Bart orange 0.6486486 0.6351351 B
I have the above data set, and I plotted the results as follows:
g <- ggplot(mydat, aes(x = x, y = y, color = Class)) +
theme_classic() +
geom_line(mapping = aes(group = Name), color = mydat$color_line) +
geom_point() +
scale_color_manual(values=c("springgreen4", "royalblue3"))
g
Now, I would like to add the Name of each individual to each line. Something that might look like this:
The closest thing that I found is the angled.boxes in library(directlabels). You can see how it looks here.
However, when I tried the following, I got a different plot.
direct.label(g, "angled.boxes")
One option to achieve your desired result would be to use the geomtextpath package which adds lots of options to add direct labels to lines and even allows for curved text. For your use case you could simply replace geom_line by geomtextpath::geom_textline to add your labels.
Note: Additionally I slightly adjusted your code to make use of the color aes for the lines and the fill aes to color the points.
library(ggplot2)
library(geomtextpath)
pal_color <- c("purple", "purple", "orange")
names(pal_color) <- c("Ana", "Josh", "Bart")
pal_fill <- c("springgreen4", "royalblue3")
names(pal_fill) <- c("A", "B")
base <- ggplot(mydat, aes(x = x, y = y)) +
scale_color_manual(values = pal_color) +
scale_fill_manual(values= pal_fill) +
theme_classic() +
guides(color = "none")
base +
geomtextpath::geom_textline(
aes(group = Name, color = Name, label = Name), textcolour = "black") +
geom_point(aes(fill = Class), shape = 21, stroke = 0, size = 2)
Or using the offset and gap arguments you could add the labels on top of the lines:
base +
geomtextpath::geom_textline(
aes(group = Name, color = Name, label = Name),
offset = unit(5, "pt"), gap = FALSE, textcolour = "black") +
geom_point(aes(fill = Class), shape = 21, stroke = 0, size = 2)
It's not ideal, but I did this a long time ago using some math and manual adjustments
mydat %>%
group_by(Name) %>%
mutate(
posx = mean(x)*1.01,
posy = mean(y)*1.01,
angle = -60*diff(range(y))/diff(range(x))
) %>%
ggplot(aes(x = x, y = y, color = Class)) + theme_classic() +
geom_line(mapping = aes(group = Name), color = mydat$color_line) +
geom_point() + scale_color_manual(values=c("springgreen4", "royalblue3"))+
geom_text(aes(x = posx, y = posy, group = Name, label = Name, angle = angle),
size = 6, show.legend = FALSE, color = "black")
This is what is the output.I have a data set which contains unit, weight of each unit and compliance score for each unit in year 2016.
I was not able to add the table but here is the screenshot for the data in csv
I have named the columns in the data as unit, weight and year(which is compliance score) .
I want to create a sunburst chart where the first ring will be the unit divided based on weight and the second ring will be the same but will have labels compliance score.
The colour for each ring will be different.
I was able to do some code with the help from an online blog and the output I have gotten is similar to what I want but I am facing difficulty in positioning of the labels and also the colour coding for each ring
#using ggplot
library(ggplot2) # Visualisation
library(dplyr) # data wrangling
library(scales) # formatting
#read file
weight.eg = read.csv("Dummy Data.csv", header = FALSE, sep =
";",encoding = "UTF-8")
#change column names
colnames(weight.eg) <- c ("unit","weight","year")
#as weight column is factor change into integer
weight.eg$weight = as.numeric(levels(weight.eg$weight))
[as.integer(weight.eg$weight)]
weight.eg$year = as.numeric(levels(weight.eg$year))
[as.integer(weight.eg$year)]
#Nas are introduced, remove
weight.eg <- na.omit(weight.eg)
#Sum of the total weight
sum_total_weight = sum(weight.eg$weight)
#First layer
firstLevel = weight.eg %>% summarize(total_weight=sum(weight))
sunburst_0 = ggplot(firstLevel) # Just a foundation
#this will generate a bar chart
sunburst_1 =
sunburst_0 +
geom_bar(data=firstLevel, aes(x=1, y=total_weight),
fill='darkgrey', stat='identity') +
geom_text(aes(x=1, y=sum_total_weight/2, label=paste("Total
Weight", comma(total_weight))), color='black')
#View
sunburst_1
#this argument is used to rotate the plot around the y-axis which
the total weight
sunburst_1 + coord_polar(theta = "y")
sunburst_2=
sunburst_1 +
geom_bar(data=weight.eg,
aes(x=2, y=weight.eg$weight, fill=weight.eg$weight),
color='white', position='stack', stat='identity', size=0.6)
+
geom_text(data=weight.eg, aes(label=paste(weight.eg$unit,
weight.eg$weight), x=2, y=weight.eg$weight), position='stack')
sunburst_2 + coord_polar(theta = "y")
sunburst_3 =
sunburst_2 +
geom_bar(data=weight.eg,
aes(x=3, y=weight.eg$weight,fill=weight.eg$weight),
color='white', position='stack', stat='identity',
size=0.6)+
geom_text(data = weight.eg,
aes(label=paste(weight.eg$year),x=3,y=weight.eg$weight),position =
'stack')
sunburst_3 + coord_polar(theta = "y")
sunburst_3 + scale_y_continuous(labels=comma) +
scale_fill_continuous(low='white', high='darkred') +
coord_polar('y') + theme_minimal()
Output for dput(weight.eg)
structure(list(unit = structure(2:7, .Label = c("", "A", "B",
"C", "D", "E", "F", "Unit"), class = "factor"), weight = c(30,
25, 10, 17, 5, 13), year = c(70, 80, 50, 30, 60, 40)), .Names =
c("unit",
"weight", "year"), row.names = 2:7, class = "data.frame", na.action
= structure(c(1L,
8L), .Names = c("1", "8"), class = "omit"))
output for dput(firstLevel)
structure(list(total_weight = 100), .Names = "total_weight", row.names
= c(NA,
-1L), na.action = structure(c(1L, 8L), .Names = c("1", "8"), class =
"omit"), class = "data.frame")
So I think I might have some sort of solution for you. I wasn't sure what you wanted to color-code on the outer ring; from your code it seems you wanted it to be the weight again, but it was not obvious to me. For different colour scales per ring, you could use the ggnewscale package:
library(ggnewscale)
For the centering of the labels you could write a function:
cs_fun <- function(x){(cumsum(x) + c(0, cumsum(head(x , -1))))/ 2}
Now the plotting code could look something like this:
ggplot(weight.eg) +
# Note: geom_col is equivalent to geom_bar(stat = "identity")
geom_col(data = firstLevel,
aes(x = 1, y = total_weight)) +
geom_text(data = firstLevel,
aes(x = 1, y = total_weight / 2,
label = paste("Total Weight:", total_weight)),
colour = "black") +
geom_col(aes(x = 2,
y = weight, fill = weight),
colour = "white", size = 0.6) +
scale_fill_gradient(name = "Weight",
low = "white", high = "darkred") +
# Open up new fill scale for next ring
new_scale_fill() +
geom_text(aes(x = 2, y = cs_fun(weight),
label = paste(unit, weight))) +
geom_col(aes(x = 3, y = weight, fill = weight),
size = 0.6, colour = "white") +
scale_fill_gradient(name = "Another Weight?",
low = "forestgreen", high = "white") +
geom_text(aes(label = paste0(year), x = 3,
y = cs_fun(weight))) +
coord_polar(theta = "y")
Which looks like this:
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())