Related
I'm attempting to create a composite plot in r, the code for which is below:
#Adding initial data
ggp <- ggplot(NULL, aes(x = date, y = covid)) +
geom_spline(data = onsdf,
aes(x = date, y = covid, colour = "ONS Modelled Estimates"), nknots = 90, size = 1.3) +
geom_spline(data = gvtdf,
aes(x = date, y = covid, colour = "Gvt Reported Positive Tests"), nknots = 90, size = 1.3)
#Creating function to add stringency bars
barfunction <- function(date1, date2, alpha){
a <- annotate(geom = "rect",
xmin = as.Date(date1), xmax = as.Date(date2), ymin = 0, ymax = Inf, alpha = alpha, fill = "red")
return(a)
}
#Adding lockdown stringency bars
ggp <- ggp +
barfunction("2020-05-03", "2020-06-01", 0.5) +
barfunction("2020-06-01", "2020-06-15", 0.4) +
barfunction("2020-06-15", "2020-09-14", 0.3) +
barfunction("2020-09-14", "2020-11-05", 0.3) +
barfunction("2020-11-05", "2020-12-02", 0.5) +
barfunction("2020-12-02", "2021-01-06", 0.4) +
barfunction("2021-01-06", "2021-03-29", 0.5) +
barfunction("2021-03-29", "2021-04-12", 0.4) +
barfunction("2021-04-12", "2021-05-17", 0.3) +
barfunction("2021-05-17", "2021-07-19", 0.2) +
barfunction("2021-07-19", "2021-12-08", 0.1) +
barfunction("2021-12-08", "2022-02-24", 0.2) +
#Adding plot labels
ggp <- ggp + labs(title = "Estimated Total Covid-19 Cases vs Reported Positive Cases",
subtitle = "From ONS and HMGvt datasets",
x = "Date (year - month)", y = "Covid Levels") +
scale_y_continuous(labels = scales::comma) +
scale_x_date(limits = as.Date(c("2020-05-03", NA ))) +
scale_colour_manual(name = "Measurement Method",
values = c("ONS Modelled Estimates"="purple",
"Gvt Reported Positive Tests" = "blue"))
The output of this code looks like this:
Rendered graph
As you can see, I have a very repetitive function (barfunction) in this code that I would like to change. I thought the best way to do this was to convert the data barfunction() was applying to the graph into a dataframe, and then try to use a function on said data frame. Here is a head of the data frame (called strindf)
date1 date2 alpha
2020-05-03 2020-06-01 0.5
2020-06-01 2020-06-15 0.4
2020-06-15 2020-09-14 0.3
2020-09-14 2020-11-05 0.3
I initially tried to use apply() to add the strindf data to my plot, however I got an error message (Error in as.Date(date2) : argument "date2" is missing, with no default). Here is how I implemented it into the original code
ggptest <- ggplot(NULL, aes(x = date, y = covid)) +
geom_spline(data = onsdf,
aes(x = date, y = covid, colour = "ONS Modelled Estimates"), nknots = 90, size = 1.3) +
geom_spline(data = gvtdf,
aes(x = date, y = covid, colour = "Gvt Reported Positive Tests"), nknots = 90, size = 1.3) +
apply(strindf, MARGIN = 1 , barfunction) +
theme_minimal() +
scale_y_continuous(labels = scales::comma) +
scale_x_date(limits = as.Date(c("2020-05-03", NA ))) +
scale_colour_manual(name = "Legend",
I'm quite new to r so I'm a bit stumped, does anyone have any suggestions?
Thanks in advance!
Your idea was right. But you have chosen the wrong function from the apply family of functions. As you have a function of multiple arguments use mapply or as I do below purrr::pmap:
Using some fake random example data:
library(ggplot2)
library(ggformula)
barfunction <- function(date1, date2, alpha) {
annotate(geom = "rect", xmin = as.Date(date1), xmax = as.Date(date2), ymin = 0, ymax = Inf, alpha = alpha, fill = "red")
}
ggplot(NULL, aes(x = date, y = covid)) +
geom_spline(data = df, aes(colour = "ONS Modelled Estimates"), nknots = 90, size = 1.3) +
purrr::pmap(strindf, barfunction) +
theme_minimal() +
scale_y_continuous(labels = scales::comma) +
scale_x_date(limits = as.Date(c("2020-05-03", NA))) +
scale_colour_manual(
name = "Measurement Method",
values = c(
"ONS Modelled Estimates" = "purple",
"Gvt Reported Positive Tests" = "blue"
)
)
#> Warning: Removed 123 rows containing non-finite values (stat_spline).
DATA
set.seed(123)
df <- data.frame(
date = seq.Date(as.Date("2020-01-01"), as.Date("2020-12-31"), by = "day"),
covid = runif(366)
)
strindf <- structure(list(date1 = c(
"2020-05-03", "2020-06-01", "2020-06-15",
"2020-09-14"
), date2 = c(
"2020-06-01", "2020-06-15", "2020-09-14",
"2020-11-05"
), alpha = c(0.5, 0.4, 0.3, 0.3)), class = "data.frame", row.names = c(
NA,
-4L
))
And I am trying to do a chart like this one
... but instead of a pie chart I wanna do a Donut chart.
However I can't figure out how to do that. This is my chart until now:
My data:
Quantidade_de_ativos_por_setor = data.frame(
Setor = c("Outros","Lajes corporativas", "Logística", "Shoppings", "Híbridos", "Hotel", "Residencial", "Hospital", "Títulos e Val Mob"),
Ativos_por_setor = c(198, 155, 111, 92, 83, 28, 4, 3, 1),
Porcentagem_por_Setor = c(29.33, 22.96, 16.44, 13.63,12.30, 4.15, 0.59, 0.44, 0.15))
My code:
Quantidade_de_ativos_por_setor <- FIIS %>%
group_by(Setor)%>%
summarize(Ativos_por_setor = sum(Quantidade_de_Ativos))%>%
mutate(Porcentagem_por_Setor = (Ativos_por_setor/sum(Ativos_por_setor))*100)%>%
arrange(desc(Ativos_por_setor))
Quantidade_de_ativos_por_setor$Porcentagem_por_Setor <- round(Quantidade_de_ativos_por_setor$Porcentagem_por_Setor, digit=2)
Hsize<- 1.5
ggplot(Quantidade_de_ativos_por_setor, aes(x = Hsize, y = Ativos_por_setor, fill = Setor)) +
geom_col(color = "black") +
geom_text(aes(label = paste0("n = ", Ativos_por_setor, ", \n", Porcentagem_por_Setor, "%")), position = position_stack(vjust = 0.5 )) +
coord_polar(theta = "y") +
scale_fill_brewer(palette = "Dark2") +
xlim(c(0.1, Hsize + 0.5)) +
theme(panel.background = element_rect(fill = "white"),
panel.grid = element_blank(),
axis.title = element_blank(),
axis.ticks = element_blank(),
axis.text = element_blank())
Thank you.
Here is a solution.
It uses a pipe and mutate to compute
More than the maximum 8 colors allowed by the palette "Dark";
coordinates for geom_text and geom_text_repel;
the labels to be displayed, inside the donut they have 3 lines of text, outside only one line.
The code is inspired in this R Graph Gallery post and on this R-bloggers post.
library(ggplot2)
library(ggrepel)
library(RColorBrewer)
library(scales)
library(dplyr)
colorcount <- nrow(Quantidade_de_ativos_por_setor)
getPalette <- colorRampPalette(brewer.pal(colorcount, "Dark2"))
Quantidade_de_ativos_por_setor %>%
mutate(fraction = Porcentagem_por_Setor/sum(Porcentagem_por_Setor),
ymax = cumsum(fraction),
ymin = c(0, head(ymax, n = -1)),
xlabel = ifelse(fraction > 0.04, 3.5, NA_real_),
xlabel_repel = ifelse(fraction < 0.04, 4.25, NA_real_),
ylabel = (ymax + ymin) / 2,
label = ifelse(fraction > 0.04,
paste(Setor, "\n n =", Ativos_por_setor, "\n", percent(fraction)),
paste0(Setor, ", n =", Ativos_por_setor, ", ", percent(fraction)))) %>%
ggplot(aes(ymax = ymax, ymin = ymin, xmax = 4, xmin = 3, fill = Setor)) +
geom_rect() +
geom_text(aes(x = xlabel, y = ylabel, label = label)) +
geom_text_repel(aes(x = xlabel_repel, y = ylabel, label = label)) +
scale_fill_manual(
labels = Quantidade_de_ativos_por_setor$Setor,
values = getPalette(colorcount)
) +
coord_polar(theta = "y") +
xlim(c(2, 4.5)) +
theme_void()
I am plotting a boxplot to represent the rainfall forecast quality in weather forecast model. The x-axis is forecast time (day) and the y-axis being the ensemble spread of the forecast results. The blue boxes are the hindcast (past 20-year re-forecast) and the red ones are the forecast data.
# library
library(ggplot2)
library(readr)
library(forcats)
model_name <- "ecmwf"
hens <- 11
fens <- 51
ys <- 1999
ye <- 2017
# Observation
clim_obs <- as.factor(rep("clim_obs",20))
pcp_obs <- c(80.9737,229.319,111.603,24.0906,53.037,165.04,28.6957,120.151,387.85,155.383,434.328,184.369,169.443,176.654,14.1557,223.796,105.595,56.6908,89.8277,74.0017)
pcp_obs <- as.vector(t(pcp_obs))
obs = data.frame(clim_obs, pcp_obs)
# create a data frame for forecast/hindcast results
lead_time <- factor(rep(seq(1,40),each=hens*(ye-ys+1)+fens),ordered = TRUE,levels = c(seq(1,40)))
Groups <- factor(rep(c("hindcast","forecast"),c(hens*(ye-ys+1),fens)), ordered = TRUE, levels = c("hindcast","forecast"))
pcp <- read_csv(paste(model_name, "_hind_fcst.csv", sep=""))
pcp <- as.vector(t(pcp))
data = data.frame(lead_time, Groups, pcp)
str(data)
# grouped boxplot
p <- ggplot() +
varwidth = FALSE) +
# geom_boxplot(data=obs, aes(x=clim_obs, y=pcp_obs), alpha = 0.7, outlier.shape = NA, varwidth = FALSE) +
geom_boxplot(data=data, aes(x=fct_relevel(lead_time), y=pcp, fill=Groups), alpha = 0.7, outlier.shape = NA, varwidth = FALSE) +
labs(x = 'Lead time (day)',
y = '15-day accumulative rainfall',
title = '(c) ECMWF') +
theme_classic() +
theme(legend.position = 'bottom', aspect.ratio = 0.35,
axis.text.x = element_text(angle = 45, vjust = 0.5, hjust=0.5)) +
scale_y_continuous(breaks=seq(0,600,50), minor_breaks = seq(0,600,by=10),limits=c(0,600)) +
scale_fill_manual(values=c("deepskyblue" , "coral1")) +
geom_vline(xintercept = seq(0.5,40.5,by=7), #linetype="dotted",
color = "gray", size=0.25) +
ggsave(paste(model_name, "_hind_fcst.pdf", sep=""))
The resultant figure is here:
There is another box in white in the end of the plot, which is the observation data for comparison. Therefore, I add
geom_boxplot(data=obs, aes(x=clim_obs, y=pcp_obs), alpha = 0.7, outlier.shape = NA, varwidth = FALSE) +
but the order of the forecast time is wrong. The revised figure shows that the x-axis is in alphabetical oder (i.e. 1, 10, 11, 12, ..., 2, 21, 22, ... clim_obs) but I hope it can be numerical order (i.e. 1, 2, 3, 4, 5, ..., clim_obs)
How can I fix the problem?
The file to generate the data is here: link
Thanks for spending your time here!
You can use scale_x_discrete to arrange the x-axis :
library(ggplot2)
ggplot() +
geom_boxplot(data=obs, aes(x=clim_obs, y=pcp_obs), alpha = 0.7, outlier.shape = NA, varwidth = FALSE) +
geom_boxplot(data=data, aes(x=lead_time, y=pcp, fill=Groups), alpha = 0.7, outlier.shape = NA, varwidth = FALSE) +
labs(x = 'Lead time (day)',
y = '15-day accumulative rainfall',
title = '(c) ECMWF') +
theme_classic() +
theme(legend.position = 'bottom', aspect.ratio = 0.35,
axis.text.x = element_text(angle = 45, vjust = 0.5, hjust=0.5)) +
scale_y_continuous(breaks=seq(0,600,50), minor_breaks = seq(0,600,by=10),limits=c(0,600)) +
scale_fill_manual(values=c("deepskyblue" , "coral1")) +
geom_vline(xintercept = seq(0.5,40.5,by=7), #linetype="dotted",
color = "gray", size=0.25) +
scale_x_discrete(limits=c(1:40, 'clim_obs'))
What I have here are two graphs "PlotA" and "PlotB", however I want a combined graph with geom_pointranges showing points, geom_line showing the line and geom_ribbon showing the standard deviation.
water <- c(35,40,42,46,48,50)
depth <- c(1,2,3,4,5,6)
sd <- c(10,10,10,10,10,10)
dataA <- data.frame(depth, water, sd)
from <- c(0.5, 1.5, 2.5, 3.5, 4.5, 5.5)
to <- c(1.5, 2.5, 3.5, 4.5, 5.5, 6.5)
depth1 <- c(1,2,3,4,5,6)
water1 <- c(40,32,50,55,62,30)
dataB <- data.frame(from,to,depth1, water1)
# Load necessary packages
require(ggplot2)
# Plotting Started
#PlotA
ggplot(data=dataA, aes(x = water, y = depth), na.rm=T) +
geom_path(size=0.4, color="black")+
geom_pointrange(data=dataB, aes(water1, depth1, ymin=from, ymax=to), size=0.1, color='black') +
scale_y_reverse(lim = c(10,0), breaks = seq(0,10,1)) +
theme_bw(12) +
scale_x_continuous(lim =c(0,100), breaks = seq(0,100,20))
#PlotB
ggplot() + geom_ribbon(data=dataA, aes(x=depth, y=water, ymin = water - sd, ymax = water + sd), alpha=0.3, fill='grey12') + coord_flip() +
scale_x_reverse(lim = c(10,0), breaks = seq(0,10,1)) + theme_bw(12) +
scale_y_continuous(lim =c(0,100), breaks = seq(0,100,20))
coord_flip is difficult to use well in the middle of a plot. I strongly recommend debugging plots without it and then adding it as the last step.
I think this is what you're looking for. If not, please describe your desired result in more detail.
ggplot(data = dataA, aes(x = depth, y = water)) +
geom_ribbon(
data = dataA,
aes(
x = depth,
ymin = water - sd,
ymax = water + sd
),
alpha = 0.3,
fill = 'grey12'
) +
geom_path(size = 0.4, color = "black") +
geom_point(
data = dataB,
aes(x = depth1, y = water1),
size = 0.1,
color = 'black'
) +
geom_errorbarh(
data = dataB,
aes(
x = depth1,
xmin = from,
xmax = to,
y = water1
),
size = 0.1,
height = 0
) +
theme_bw(12) +
scale_x_reverse(lim = c(10, 0), breaks = seq(0, 10, 1)) +
scale_y_continuous(lim = c(0, 100), breaks = seq(0, 100, 20)) +
coord_flip()
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
CODE UPDATED
I have some angle data from an animal behavior study that I would like to plot for publication using ggplot2. What follows is my current workflow with some example data and how it would look using the generic plot function.
### Create two data frames of random Cartesian coordinates ###
df1 <- data.frame(
x = sample(10, 11, replace = TRUE),
y = sample(10, 11, replace = TRUE))
df2 <- data.frame(
x = sample(10, 11, replace = TRUE),
y = sample(10, 11, replace = TRUE))
### Write a function that converts continuous Cartesian coordinates to velocities ###
get.polar <- function(df)
{
x <- diff(df$x)
y <- diff(df$y)
d <- complex(real = x, imaginary = y)
steps <- data.frame(speed = Mod(d), angle = Arg(d))
steps[-1,] # Deletes the first row as it does not contain an angle measurement
steps$time <- (1:nrow(steps))/30 # generates a time column in seconds (1 data point = 1/30 of a second)
return(steps)
}
df1_polar <- get.polar(df1)
df2_polar <- get.polar(df2)
require(circular)
### Convert angles into an object of type 'circular' ###
df1_rad <- circular(df1_polar$angle, type = 'angles', units = 'radians', zero=0, rotation = "counter")
df2_rad <- circular(df2_polar$angle, type = 'angles', units = 'radians', zero=0, rotation = "counter")
### Convert radians to degrees with a clockwise rotation and zero at "north" ###
df1_deg <- conversion.circular(df1_rad, type = "angles", units = "degrees", zero = pi/2, rotation = "clock")
df2_deg <- conversion.circular(df2_rad, type = "angles", units = "degrees", zero = pi/2, rotation = "clock")
### Convert negative rotations to positive ###
df1_deg[df1_deg < 0] <- df1_deg[df1_deg < 0] + 360
df2_deg[df2_deg < 0] <- df2_deg[df2_deg < 0] + 360
par(pty = "s")
plot(df1_deg, units = "degrees")
ticks.circular(circular(seq(0,(11/6)*pi, pi/6)), zero = pi/2, rotation = "clock", tcl = 0.075)
points(df2_deg, zero = pi/2, rotation = "clock", pch = 16, col = "darkgrey", next.points = -0.2)
# Suggested solution by MLavoie with modifications
temp1 <- data.frame(Exercise = c(1, 1, 1, 1), Name = c(1, 2, 3, 4),
Score = c(90, 180, 270, 360))
temp2 <- data.frame(Name=c(replicate(length(df1_deg), 3)),
Score = c(df1_deg))
temp3 <- data.frame(Name=c(replicate(length(df2_deg), 4)),
Score = c(df2_deg))
temp4 <- data.frame(Name=c(4.8, 4.8, 4.8, 4.8, 4.8, 4.8, 4.8, 4.8),
Score = c(0, 45, 90, 135, 180, 225, 270, 315))
ggplot() +
geom_bar(data = temp1, aes(x = factor(Name), y = Score, fill = factor(Exercise)),
width = 1, stat = 'identity') +
geom_point(data = temp2, aes(x = Name, y = Score),
color = "green", size = 2) +
geom_point(data = temp3, aes(x = Name, y = Score),
color = "red", size = 2) +
geom_point(data = temp4, aes(x = Name, y = Score),
color = "black", shape = 8, size = 2) +
geom_vline(xintercept = 4.8) +
annotate("text", x = 0, y = 0, label = "+", size = 6) +
scale_y_continuous(breaks = c(0, 45, 90, 135, 180, 225, 270, 315)) +
coord_polar(theta = "y", start = 0) +
theme_bw() + ylab("") + xlab("") +
theme(panel.border = element_blank(),
panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
strip.text = element_blank(),
strip.background = element_blank(),
axis.text.y = element_blank(),
legend.position = "none",
axis.ticks = element_blank()) +
scale_fill_manual(values = c("transparent", "transparent", "transparent", "transparent"))
Some suggestions for turning this rough plot into something publishable using ggplot2?
Thank you!
What about this for a start:
temp <- data.frame(Exercise=c(1, 1, 1, 1), Name=c(1, 2, 3, 4), Score=c(90, 180, 270, 360))
temp2 <- data.frame(Name=c(2.8, 2.8, 2.8, 2.8), Score=c(90, 180, 270, 360))
temp3 <- data.frame(Name=c(4.2, 4.2, 4.2, 4.2), Score=c(90, 180, 270, 360))
temp4 <- data.frame(Name=c(0), Score=c(180))
temp5 <- data.frame(Name=c(4.8, 4.8, 4.8, 4.8, 4.8, 4.8, 4.8, 4.8), Score=c(45, 90, 135, 180, 225, 270, 305, 360))
ggplot() +
geom_bar(data=temp, aes(x = factor(Name), y=Score, fill = factor(Exercise)), width = 1, stat='identity') +
geom_point(data=temp2, aes(x=Name, y=Score), color="grey") +
coord_polar(theta = "y", start=0) +
theme_bw() + ylab("") + xlab("") +
scale_y_continuous(breaks = c(90, 180, 270, 360)) +
theme(panel.border=element_blank(),
panel.grid.minor=element_blank(),
panel.grid.major=element_blank(),
strip.text=element_blank(),
strip.background=element_blank(),
axis.text.y=element_blank(),
legend.position="none",
axis.ticks = element_blank()) +
scale_fill_manual(values = c("transparent", "transparent", "transparent", "transparent")) +
geom_vline(xintercept=4.8) +
geom_point(data=temp4, aes(x=Name, y=Score), color="black", shape=3, size=4) +
geom_point(data=temp3, aes(x=Name, y=Score), color="black") +
geom_point(data=temp5, aes(x=Name, y=Score), color="black", shape=3, size=2)