Related
I want this ggplot-facet to look like this
set.seed(1)
n10_sd1_arma0.5_0.3 <- arima.sim(n = 10, model = list(ar = c(0.5), ma = c(0.3), order = c(1, 0, 1)), sd = 1)
set.seed(1)
n10_sd1_arma0.5_0.4 <- arima.sim(n = 10, model = list(ar = c(0.5), ma = c(0.4), order = c(1, 0, 1)), sd = 1)
set.seed(1)
n10_sd1_arma0.35_0.6 <- arima.sim(n = 10, model = list(ar = c(0.35), ma = c(0.6), order = c(1, 0, 1)), sd = 1)
set.seed(1)
n10_sd3_arma0.5_0.3 <- arima.sim(n = 10, model = list(ar = c(0.5), ma = c(0.3), order = c(1, 0, 1)), sd = 3)
set.seed(1)
n10_sd3_arma0.5_0.4 <- arima.sim(n = 10, model = list(ar = c(0.5), ma = c(0.4), order = c(1, 0, 1)), sd = 3)
set.seed(1)
n10_sd3_arma0.35_0.6 <- arima.sim(n = 10, model = list(ar = c(0.35), ma = c(0.6), order = c(1, 0, 1)), sd = 3)
set.seed(1)
n10_sd5_arma0.5_0.3 <- arima.sim(n = 10, model = list(ar = c(0.5), ma = c(0.3), order = c(1, 0, 1)), sd = 5)
set.seed(1)
n10_sd5_arma0.5_0.4 <- arima.sim(n = 10, model = list(ar = c(0.5), ma = c(0.4), order = c(1, 0, 1)), sd = 5)
set.seed(1)
n10_sd5_arma0.35_0.6 <- arima.sim(n = 10, model = list(ar = c(0.35), ma = c(0.6), order = c(1, 0, 1)), sd = 5)
set.seed(1)
n10_sd10_arma0.5_0.3 <- arima.sim(n = 10, model = list(ar = c(0.5), ma = c(0.3), order = c(1, 0, 1)), sd = 10)
set.seed(1)
n10_sd10_arma0.5_0.4 <- arima.sim(n = 10, model = list(ar = c(0.5), ma = c(0.4), order = c(1, 0, 1)), sd = 10)
set.seed(1)
n10_sd10_arma0.35_0.6 <- arima.sim(n = 10, model = list(ar = c(0.35), ma = c(0.6), order = c(1, 0, 1)), sd = 10)
xx = 1:10
n10_df <- data.frame(xx = 1:10, x1 = n10_sd1_arma0.5_0.3, x2 = n10_sd1_arma0.5_0.4, x3 = n10_sd1_arma0.35_0.6, x4 = n10_sd3_arma0.5_0.3, x5 = n10_sd3_arma0.5_0.4, x6 = n10_sd3_arma0.35_0.6, x7 = n10_sd5_arma0.5_0.3, x8 = n10_sd5_arma0.5_0.4, x9 = n10_sd5_arma0.35_0.6, x10 = n10_sd10_arma0.5_0.3, x11 = n10_sd10_arma0.5_0.4, x12 = n10_sd10_arma0.35_0.6)
n10_df |>
tidyr::pivot_longer(-xx) |>
dplyr:: mutate(id = as.numeric(gsub("x", "", name))) |>
dplyr::arrange(id, xx) |>
dplyr::select(-id) |>
dplyr::mutate(sd = rep(rep(c(sd = 1, sd = 3, sd = 5, sd = 10), each = 10), each = 3),
psi = rep(rep(list(c(0.5, 0.3), c(0.5, 0.4), c(0.35, 0.6)), each = 10), 4)) |>
dplyr::mutate(sd = factor(sd, levels = sd, labels = paste("sd =", sd)),
psi = factor(psi, levels = psi, labels = gsub("c", "", paste("\U03A8 =", psi)))) |>
ggplot2::ggplot(aes(x = xx, y = value)) +
ggplot2::geom_line() +
ggplot2::geom_point() +
ggplot2::scale_y_continuous(expand = c(0.0, 0.00)) +
ggplot2::labs(x = "Time", y = "Series") +
ggplot2::facet_grid(sd ~ psi, scales = "free_y") +
ggplot2::theme_bw() + ggplot2::theme(strip.text.x = ggplot2::element_text(size = 20, face = "bold"), strip.text.y = ggplot2::element_text(size = 16, face = "bold"), axis.title = ggplot2::element_text(size = 20), axis.title.x = ggplot2::element_text(angle = 0, hjust = 0.5,
vjust = 0.5, size = 20), axis.title.y = ggplot2::element_text(angle = 90, hjust = 0.5, vjust = 0.5, size = 20))
I think my problem lies in how to twist this part rep(rep(list(c(0.5, 0.3), c(0.5, 0.4), c(0.35, 0.6)) to be what I want. Please help!
Edit
n10_df |>
tidyr::pivot_longer(-xx) |>
dplyr:: mutate(id = as.numeric(gsub("x", "", name))) |>
dplyr::arrange(id, xx) |>
dplyr::select(-id) |>
dplyr::mutate(sd = rep(rep(c(sd = 1, sd = 3, sd = 5, sd = 10), each = 10), each = 3),
psi = rep(rep(list(c(0.5, 0.3), c(0.5, 0.4), c(0.35, 0.6)), each = 10), 4)) |>
dplyr::mutate(sd = factor(sd, levels = sd, labels = paste("sd =", sd)),
psi = factor(psi, levels = psi, labels = sapply(psi, function(x) sprintf('\U03C6 = %s, \U1D717 = %s', x[1], x[2])))) |>
ggplot2::ggplot(aes(x = xx, y = value)) +
ggplot2::geom_line() +
ggplot2::geom_point() +
ggplot2::scale_y_continuous(expand = c(0.0, 0.00)) +
ggplot2::labs(x = "Time", y = "Series") +
ggplot2::facet_grid(sd ~ psi, scales = "free_y") +
ggplot2::theme_bw() + ggplot2::theme(strip.text.x = ggplot2::element_text(size = 20, face = "bold"), strip.text.y = ggplot2::element_text(size = 16, face = "bold"), axis.title = ggplot2::element_text(size = 20), axis.title.x = ggplot2::element_text(angle = 0, hjust = 0.5, vjust = 0.5, size = 20), axis.title.y = ggplot2::element_text(angle = 90, hjust = 0.5, vjust = 0.5, size = 20))
I want the column header and row header of this plot to be phi = 0.8, phi = 0.9, phi = 0.95 and sd = 1, sd = 3, sd = 5, sd = 10 respectively. The phi should appear as the Greek letter symbol while the sd remains the English letter.
## simulate ARIMA(1, 0, 0)
set.seed(289805)
x1 <- arima.sim(n = 10, model = list(ar = 0.8, order = c(1, 0, 0)), sd = 1)
set.seed(671086)
x2 <- arima.sim(n = 10, model = list(ar = 0.9, order = c(1, 0, 0)), sd = 1)
set.seed(799837)
x3 <- arima.sim(n = 10, model = list(ar = 0.95, order = c(1, 0, 0)), sd = 1)
set.seed(289805)
x4 <- arima.sim(n = 10, model = list(ar = 0.8, order = c(1, 0, 0)), sd = 3)
set.seed(671086)
x5 <- arima.sim(n = 10, model = list(ar = 0.9, order = c(1, 0, 0)), sd = 3)
set.seed(799837)
x6 <- arima.sim(n = 10, model = list(ar = 0.95, order = c(1, 0, 0)), sd = 3)
set.seed(289805)
x7 <- arima.sim(n = 10, model = list(ar = 0.8, order = c(1, 0, 0)), sd = 5)
set.seed(671086)
x8 <- arima.sim(n = 10, model = list(ar = 0.9, order = c(1, 0, 0)), sd = 5)
set.seed(799837)
x9 <- arima.sim(n = 10, model = list(ar = 0.95, order = c(1, 0, 0)), sd = 5)
set.seed(289805)
x10 <- arima.sim(n = 10, model = list(ar = 0.8, order = c(1, 0, 0)), sd = 10)
set.seed(671086)
x11 <- arima.sim(n = 10, model = list(ar = 0.9, order = c(1, 0, 0)), sd = 10)
set.seed(799837)
x12 <- arima.sim(n = 10, model = list(ar = 0.95, order = c(1, 0, 0)), sd = 10)
xx <- 1:10
df <- data.frame(xx, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)
reshapp <- reshape2::melt(df, id = "xx")
NEWDAT <- data.frame(y = reshapp$value, x = reshapp$xx, sd = rep(rep(c(sd=1, sd=3, sd=5, sd=10), each = 10), each = 3),phi = rep(rep(c(.8, .9, .95), each = 10), 4))
ggplot(NEWDAT, aes(x = x, y = y)) + geom_line() + geom_point() + labs(x = 'lb', y = 'RMSE') + facet_grid(sd ~ phi, scales = "free_y") +
theme_bw() + ggplot2::scale_y_continuous(expand = c(0.0, 0.00))
[Edited to account for the refactor in the third line of code]
A quick fix is to either create or rename the faceted key with Phi expressed in UTF8 encoding, plus the creation of the string you want (ie. "Phi|SD = N")
In this case I create a new variable:
NEWDAT %>%
mutate(phi_label = paste0("\U03D5 = ", phi), #"\U03D5" represents the character "ϕ"
sd_label = fct_reorder(.f = paste0("sd =", sd), .x = sd)) %>%
ggplot(aes(x = x, y = y)) + geom_line() + geom_point() + labs(x = 'lb', y = 'RMSE') +
facet_grid(sd_label ~ phi_label, scales = "free_y") +
theme_bw() + ggplot2::scale_y_continuous(expand = c(0.0, 0.00))
Here is a solution with plotmath using only standard characters, no special escape sequences.
NEWDAT <- data.frame(y = reshapp$value, x = reshapp$xx, sd = rep(rep(c(sd=1, sd=3, sd=5, sd=10), each = 10), each = 3),phi = rep(rep(c(.8, .9, .95), each = 10), 4))
NEWDAT$sd <- factor(NEWDAT$sd, levels = NEWDAT$sd, labels = paste("sd ==", NEWDAT$sd))
NEWDAT$phi <- with(NEWDAT, factor(phi, levels = phi, labels = paste("phi ==", phi)))
ggplot(NEWDAT, aes(x = x, y = y)) +
geom_line() +
geom_point() +
scale_y_continuous(expand = c(0.0, 0.00)) +
labs(x = 'lb', y = 'RMSE') +
facet_grid(
sd ~ phi,
scales = "free_y",
labeller = label_parsed
) +
theme_bw()
A partial answer is this: Use this facet_grid call instead of the one you're using right now.
facet_grid(sd ~ phi, scales = "free_y", labeller = . %>% label_both(sep = " = "))
Using bquote
facet_grid(sd ~ phi, scales = "free_y",
labeller =
label_bquote(rows = sigma == .(sd), cols = phi == .(phi))
)
This will yield the right labels.
Answer inspired from this post
Is there a straightforward way to use alpha on only one variable using ggplot2?
I would have imagined that scale_alpha_manual(values = c(0, 1)) would work like scale_color_manual(). Ultimately, I am interested in doing an animation where a colour appears gradually.
df = data.frame(time = 1:100, x1 = rnorm(100, 1, 5), x2 = rnorm(100, 1, 5)) %>%
melt(id.vars = 'time')
df %>%
ggplot(aes(time, value, colour = variable)) +
geom_line() +
scale_color_manual(values = c('black', 'blue')) +
scale_alpha_manual(values = c(0, 1))
I am trying to get something like this but with an alpha
You could use the alpha as an aesthetic:
df = data.frame(time = 1:100, x1 = rnorm(100, 1, 5), x2 = rnorm(100, 1, 5)) %>%
melt(id.vars = 'time')
df %>%
ggplot(aes(time, value, colour = variable, alpha=variable)) +
geom_line() +
scale_color_manual(values = c('black', 'blue')) +
scale_alpha_manual(values = c(0.3, 1))
I'm plotting a discrete CDF. I have a few questions regarding geom_step which I'm not finding by using Google.
Is it possible to make the line segment representing the jump dashed
rather than solid to better show whats going on?
Is it possible to add geom_point more efficiently than I do? (less
c/p).
Below is my current solution:
library(tidyverse)
library(ggthemes)
theme_set(theme_few())
x0 <- seq(-0.5, -0.01, by = 0.01)
x1 <- seq(0, 0.99, by = 0.02)
x2 <- seq(1, 1.99, by = 0.02)
x3 <- seq(2, 2.99, by = 0.02)
x35 <- seq(3, 3.49, by = 0.01)
x4 <- seq(3.5, 3.99, by = 0.01)
tibble_ex <- tibble(
x0 = x0,
x1 = x1,
x2 = x2,
x3 = x3,
x35 = x35,
x4 = x4
)
tibble_ex %>%
gather(x, xax, x0:x4) %>%
mutate(cdf = case_when(x == 'x0' ~ 0,
x == 'x1' ~ 1/2,
x == 'x2' ~ 3/5,
x == 'x3' ~ 4/5,
x == 'x35' ~ 9/10,
x == 'x4' ~ 1)) %>%
ggplot(aes(x = xax, y = cdf)) +
geom_step() +
geom_point(aes(x = 0, y = 0), size = 3, shape = 21, fill = 'white') +
geom_point(aes(x = 1, y = 0.5), size = 3, shape = 21, fill = 'white') +
geom_point(aes(x = 2, y = 3/5), size = 3, shape = 21, fill = 'white') +
geom_point(aes(x = 3, y = 4/5), size = 3, shape = 21, fill = 'white') +
geom_point(aes(x = 3.5, y = 9/10), size = 3, shape = 21, fill = 'white') +
geom_point(aes(x = 0, y = 0.5), size = 3, shape = 21, fill = 'black') +
geom_point(aes(x = 1, y = 3/5), size = 3, shape = 21, fill = 'black') +
geom_point(aes(x = 2, y = 4/5), size = 3, shape = 21, fill = 'black') +
geom_point(aes(x = 3, y = 9/10), size = 3, shape = 21, fill = 'black') +
geom_point(aes(x = 3.5, y = 1), size = 3, shape = 21, fill = 'black') +
labs(x = 'x', y = 'F(x)')
ggplot will be more powerful to use if you can put your data into a data frame and structure it so that the characteristics of your data can be mapped directly.
Here's a way to take your data and augment it with additional rows that represent the connecting points, by matching each x with the prior cdf value. I added a column, type, to keep track of which is which. I also arrange df so that geom_segment plots the points in the right order.
new_steps <-
tibble(x = c(0:3, 3.5, 4),
cdf = c(0, .5, .6, .8, .9, 1))
df <- new_steps %>%
mutate(type = "cdf") %>%
bind_rows(new_steps %>%
mutate(type = "prior",
cdf = lag(cdf))) %>%
drop_na() %>%
arrange(x, desc(type))
Then we can map the points' fill and the geom_segments' linetype to type.
ggplot(df) +
geom_point(aes(x, cdf, fill = type),
shape = 21) +
scale_fill_manual(values = c("black", "white")) +
geom_segment(aes(x = lag(x), y = lag(cdf),
xend = x, yend = cdf,
lty = type)) +
scale_linetype_manual(values = c("dashed", "solid"))
(1) No, there is not a built-in way to make the geom_step half-dashed. But if you post this as a separate question, perhaps someone will help create a new geom for this.
(2) The answer is to put the points you want plotted in a data frame, like anything else you might want to plot:
point_data = data.frame(x = rep(c(0, 1, 2, 3, 3.5), 2),
y = c(0, rep(c(.5, .6, .8, .9), 2), 1),
z = rep(c("a", "b"), each = 5))
# calling your gathered/mutated version of tibble_ex df
ggplot(df, aes(x = xax, y = cdf)) +
geom_step() +
geom_point(data = point_data, aes(x = x, y = y, fill = z), shape = 21) +
scale_fill_manual(values = c("white", "black"), guide = FALSE) +
labs(x = 'x', y = 'F(x)')
For the second part of your question, you can put all the coordinates in a separate data frame and call geom_point only once:
ddf <- data.frame(xax = rep(c(0:3, 3.5), 2),
cdf = c(0, .5, .6, .8, .9, .5, .6, .8, .9, 1),
col = rep(c("white", "black"), each = 5))
dev.new()
tibble_ex %>%
gather(x, xax, x0:x4) %>%
mutate(cdf = case_when(x == 'x0' ~ 0,
x == 'x1' ~ 1/2,
x == 'x2' ~ 3/5,
x == 'x3' ~ 4/5,
x == 'x35' ~ 9/10,
x == 'x4' ~ 1)) %>%
ggplot(aes(x = xax, y = cdf)) +
geom_step() +
geom_point(data = ddf, aes(fill = I(col)), size = 3, shape = 21) +
labs(x = 'x', y = 'F(x)')
I am trying to plot waterfall chart using ggplot2. When I am placing the data labels it is not putting in the right place.
Below is the code I am using
dataset <- data.frame(TotalHeadcount = c(-417, -12, 276, -276, 787, 14), Category = LETTERS[1:6])
dataset$SortedCategory <- factor(dataset$`Category`, levels = dataset$`Category`)
dataset$id <- seq_along(dataset$TotalHeadcount)
dataset$type <- ifelse(dataset$TotalHeadcount > 0, "in", "out")
dataset[dataset$SortedCategory %in% c("A", "F"), "type"] <- "net"
dataset$type <- factor(dataset$type, levels = c("out", "in", "net"))
dataset$end <- cumsum(dataset$`TotalHeadcount`)
dataset$end <- c(head(dataset$end, -1), 0)
dataset$start <- c(0, head(dataset$end, -1))
dataset$value <-dataset$`TotalHeadcount`
library(ggplot2)
strwr <- function(str) gsub(" ", "\n", str)
ggplot(dataset, aes(fill = type))+ geom_rect(aes(x = SortedCategory, xmin = id - 0.45, xmax = id + 0.45, ymin = end, ymax = start))+ scale_x_discrete("", breaks = levels(dataset$SortedCategory), labels = strwr(levels(dataset$SortedCategory)))+ theme_bw()+ theme(panel.border = element_blank(), panel.grid.major = element_blank(), axis.line = element_line(colour = "gray"))+guides(fill=FALSE)
And below is the output. I want the data label to be just at the beginning or at the end of the bar.
I am not very expert in R. Just trying to learn. Any help would be really appreciated.
I was following the below blog
https://learnr.wordpress.com/2010/05/10/ggplot2-waterfall-charts/
but somehow when I write the same code in geom_text it gives me an error. Could be a syntax related issue.
Here is an approach with ggplot.
First the data:
df1 <- data.frame(z = c(-417, -12, 276, -276, 787, 14),
b = LETTERS[1:6])
library(tidyverse)
Calculate the cumsum and the lag of the cumsum for geom_rect coords
df1 %>%
mutate(val = cumsum(z),
lag = c(0, lag(val)[-1]),
b1 = as.numeric(b)) -> df1
ggplot(df1)+
geom_rect(aes(xmin = b1 - 0.45,
xmax = b1 + 0.45, ymin = lag, ymax = val)) +
geom_text(aes(x = b1, y = val, label = val), #or `label = z`
vjust = ifelse(df1$val < df1$lag, -0.2, 1)) + #geom_text vjust depends on the direction of the value
scale_x_continuous(breaks = 1:6, labels = df1$b)
an easier way, but I think the labels position can not be changed at this moment but it is planned:
rect_text_labels_anchor (character) How should rect_text_labels be
positioned? In future releases, we might have support for north or
south anchors, or for directed positioning (negative down, positive
up) etc. For now, only centre is supported.
library(waterfalls)
df1 <- data.frame(z = c(-417, -12, 276, -276, 787, 14),
b = LETTERS[1:6])
you could also color it the same way in ggplot:
df1 %>%
mutate(val = cumsum(z),
lag = c(0, lag(val)[-1]),
b1 = as.numeric(b),
color = ifelse(val <lag, "down", "up")) -> df1
ggplot(df1)+
geom_rect(aes(xmin = b1 - 0.45,
xmax = b1 + 0.45, ymin = lag, ymax = val, fill = color)) +
geom_text(aes(x = b1, y = val, label = z),
vjust = ifelse(df1$val < df1$lag, -0.2, 1)) +
scale_x_continuous(breaks = 1:6, labels = df1$b)
EDIT: answers to the questions in comments.
Filled waterfall:
df1 <- data.frame(z = c(-417, -12, 276, -276, 787, 14),
b = LETTERS[1:6],
group = rep(c("AB", "CD", "EF"), each = 2))
df1 %>%
mutate(val = cumsum(z),
lag = c(0, lag(val)[-1]),
b1 = as.numeric(b),
g1 = as.numeric(group)) -> df1
ggplot(df1)+
geom_rect(aes(xmin = g1 - 0.45,
xmax = g1 + 0.45, ymin = lag, ymax = val, fill = b)) +
geom_text(aes(x = g1, y = val, label = z),
vjust = ifelse(df1$val < df1$lag, -0.2, 1)) +
scale_x_continuous(breaks = 1:3, labels = unique(df1$group))
To answer what went wrong with your geom_text code I would need to see it. Other then that your code works, but it over-complicates things. I advise you to learn a bit of tidyverse functions, data manipulation will be much cleaner then.
One more note, adding back-ticks:
dataset$`TotalHeadcount`
is not necessary when your column names do not contain special characters:
dataset$TotalHeadcount
EDIT2: to change to order on the x axis you would first change the levels of the grouping factor and then do the calculation and plotting:
df1 <- data.frame(z = c(-417, -12, 276, -276, 787, 14),
b = LETTERS[1:6],
group = rep(c("AB", "CD", "EF"), each = 2))
df1 %>%
mutate(group = factor(group, levels = c("AB", "EF", "CD"))) %>%
arrange(group) %>%
mutate(val = cumsum(z),
lag = c(0, lag(val)[-1]),
b1 = as.numeric(b),
g1 = as.numeric(group)) -> df1
ggplot(df1)+
geom_rect(aes(xmin = g1 - 0.45,
xmax = g1 + 0.45, ymin = lag, ymax = val, fill = b)) +
geom_text(aes(x = g1, y = val, label = z),
vjust = ifelse(df1$val < df1$lag, -0.2, 1)) +
scale_x_continuous(breaks = 1:3, labels = unique(df1$group))