Я пытаюсь воссоздать диаграмму, похожую на эту, используя ggplot2
, которая классифицирует историческую доходность (или спреды) по квартилям и представляет в виде гистограммы с накоплением.
У меня есть следующий набор данных и код. Проблема с моей диаграммой заключается в том, что я думаю, что geom_bar
суммирует все процентные значения в столбце Percent
в моем случае, а не отображает его в виде диапазона.
library(tidyverse)
data <- structure(list(date = structure(c(19307, 19310, 19311, 19312,
19313, 19314, 19317, 19318, 19319, 19321, 19307, 19310, 19311,
19312, 19313, 19314, 19317, 19318, 19319, 19321), class = "Date"),
Key = c("10 Year", "10 Year", "10 Year", "10 Year", "10 Year",
"10 Year", "10 Year", "10 Year", "10 Year", "10 Year", "30 Year",
"30 Year", "30 Year", "30 Year", "30 Year", "30 Year", "30 Year",
"30 Year", "30 Year", "30 Year"), Percent = c(3.813, 3.865,
3.799, 3.692, 3.775, 3.818, 3.825, 3.758, 3.706, 3.691, 4.058,
4.058, 3.982, 3.86, 3.89, 3.927, 3.905, 3.83, 3.739, 3.751
), Quartile = structure(c(3L, 4L, 2L, 1L, 2L, 3L, 4L, 2L,
1L, 1L, 4L, 4L, 3L, 2L, 2L, 3L, 2L, 1L, 1L, 1L), levels = c("1",
"2", "3", "4"), class = "factor")), class = c("grouped_df",
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -20L), groups = structure(list(
Key = c("10 Year", "30 Year"), .rows = structure(list(1:10,
11:20), ptype = integer(0), class = c("vctrs_list_of",
"vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -2L), .drop = TRUE))
data %>% {
ggplot(., aes(x = Key, y = Percent, fill = Quartile)) +
geom_bar(stat = 'identity', position = position_stack())
}
geom_boxplot
будет отображать его как диапазон, однако поле охватывает только межквартильный диапазон, а не полный минимальный и максимальный диапазон, как на диаграмме, которую я пытаюсь воссоздать. Кроме того, заполнить коробку с помощью Quartile
намного сложнее.
data %>% {
ggplot(., aes(x = Key, y = Percent)) +
geom_boxplot()
}
Любые идеи о том, как сделать это правильно?
Я думаю, вы можете попробовать использовать geom_rect, который принимает минимальное и максимальное значения как для y, так и для x. Мы можем получить значения ymin и ymax, сгруппировав данные по ключу и квартилю, создав минимальные и максимальные переменные, отсортировав по ключу и квартилю, а затем используя срез, чтобы взять только первую строку каждой группы. Нам также понадобится числовое значение x, чтобы это работало, поэтому мы делаем Key факторной переменной.
df <- data %>%
group_by(Key, Quartile) %>%
mutate(min = min(Percent), max = max(Percent)) %>%
arrange(Key, Quartile) %>%
slice(1) %>%
select(Key, Quartile, min, max) %>%
ungroup() %>%
mutate(Key = factor(Key))
Набор данных выглядит так.
Key Quartile min max
<fct> <fct> <dbl> <dbl>
1 10 Year 1 3.69 3.71
2 10 Year 2 3.76 3.80
3 10 Year 3 3.81 3.82
4 10 Year 4 3.82 3.86
5 30 Year 1 3.74 3.83
6 30 Year 2 3.86 3.90
7 30 Year 3 3.93 3.98
8 30 Year 4 4.06 4.06
Обратите внимание, что максимум одного квартиля не совпадает с минимумом следующего квартиля, поэтому это приведет к пробелам в графике. Кроме того, вы увидите, что 30-летний квартиль 4 имеет одинаковое значение для минимума и максимума, поэтому это не будет отображаться на графике. Отрегулируйте их соответствующим образом, если вам нужно, чтобы графики отображались непрерывно.
Поскольку мы превратили Key в фактор, если вы используете as.numeric() для Key, мы получим значения 1 и 2 в этом примере. Таким образом, мы корректируем ширину прямоугольника, добавляя и вычитая постоянное значение. Здесь я использовал 0,25. Мы используем scale_x_continuous для добавления меток, связанных с ключом.
ggplot(df) +
geom_rect(aes(xmin = (as.numeric(Key) -0.25), xmax = (as.numeric(Key) + 0.25), ymin = min, ymax = max, fill = Quartile)) +
scale_x_continuous(breaks = seq(from = min(as.numeric(df$Key)), to = max(as.numeric(df$Key))), labels = unique(df$Key)) +
theme_bw() +
theme(panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank())
Я надеюсь, что это приблизилось к тому, что вы ищете.
Вы можете обобщить свой набор данных, чтобы найти медиану и диапазон Percent
в пределах Key
и Quartile
, и передать их в geom_tile()
с сопоставлением Quartile
с fill
.
Обратите внимание, что 4-й квартиль для 30-летнего периода имеет диапазон 0. Вы можете убедиться, что он все еще отображается, также сопоставив Quartile
с color
. Это добавит границу к вашим плиткам, которая по-прежнему будет отображаться как горизонтальная линия, когда диапазон равен 0.
data <- data %>%
group_by(Key, Quartile) %>%
summarize(
yrange = max(Percent) - min(Percent),
Percent = median(Percent),
.groups = "drop"
)
ggplot(data) +
geom_tile(
aes(Key, Percent, width = .9, height = yrange, fill = Quartile, color = Quartile),
size = 1
) +
scale_fill_brewer(palette = "RdBu", aesthetics = c("fill", "color")) +
theme_classic() +
theme(legend.position = "bottom")
Хорошее решение. Но нельзя ли просто использовать
summarize()
вместоmutate() %>% arrange() %>% slice() %>% select()
?