Редактировать 2
Текущая версия ggplot2-пакета для разработки действительно решает проблему, упомянутую в моем вопросе ниже. Установите версию dev, используя
devtools::install_github("tidyverse/ggplot2")
Редактировать
Кажется, что некорректное поведение sec_axis
в ggplot2 3.1.0 является ошибкой. Это было признано разработчиками, и они работают над исправлением (см. thread на GitHub).
Цель
У меня есть график, где ось Y колеблется от 0 до 1. Я хотел бы добавить вторичную ось Y, которая варьируется от 0 до 0,5 (так что ровно половина значений первичной оси Y). Пока проблем нет.
Что усложняет дело, так это то, что у меня есть пользовательское преобразование для оси Y, где часть оси Y отображается линейно, а остальные - логарифмически (см. Пример кода ниже). Для справки см. этот пост или этот пост .
Проблема
Это прекрасно работает при использовании ggplot2 версии 3.0.0, но больше не работает при использовании новейшей версии (3.1.0). Смотрите пример ниже. Я не знаю, как это исправить в последней версии.
Из журнала изменений :
sec_axis () и dup_axis () теперь возвращают соответствующие разрывы для
вторичная ось применительно к логарифмически преобразованным шкалам
Эта новая функциональность нарушается в случае смешанно-преобразованных осей Y.
Воспроизводимый пример
Вот пример использования самой последней версии (3.1.0) ggplot2:
library(ggplot2)
library(scales)
#-------------------------------------------------------------------------------------------------------
# Custom y-axis
#-------------------------------------------------------------------------------------------------------
magnify_trans_log <- function(interval_low = 0.05, interval_high = 1, reducer = 0.05, reducer2 = 8) {
trans <- Vectorize(function(x, i_low = interval_low, i_high = interval_high, r = reducer, r2 = reducer2) {
if(is.na(x) || (x >= i_low & x <= i_high)) {
x
} else if(x < i_low & !is.na(x)) {
(log10(x / r)/r2 + i_low)
} else {
log10((x - i_high) / r + i_high)/r2
}
})
inv <- Vectorize(function(x, i_low = interval_low, i_high = interval_high, r = reducer, r2 = reducer2) {
if(is.na(x) || (x >= i_low & x <= i_high)) {
x
} else if(x < i_low & !is.na(x)) {
10^(-(i_low - x)*r2)*r
} else {
i_high + 10^(x*r2)*r - i_high*r
}
})
trans_new(name = 'customlog', transform = trans, inverse = inv, domain = c(1e-16, Inf))
}
#-------------------------------------------------------------------------------------------------------
# Create data
#-------------------------------------------------------------------------------------------------------
x <- seq(-1, 1, length.out = 1000)
y <- c(x[x<0] + 1, -x[x>0] + 1)
dat <- data.frame(
x = x
, y = y
)
#-------------------------------------------------------------------------------------------------------
# Plot using ggplot2
#-------------------------------------------------------------------------------------------------------
theme_set(theme_bw())
ggplot(dat, aes(x = x, y = y)) +
geom_line(size = 1) +
scale_y_continuous(
, trans = magnify_trans_log(interval_low = 0.5, interval_high = 1, reducer = 0.5, reducer2 = 8)
, breaks = c(0.001, 0.01, 0.1, 0.5, 0.6, 0.7, 0.8, 0.9, 1)
, sec.axis = sec_axis(
trans = ~.*(1/2)
, breaks = c(0.001, 0.01, 0.1, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5)
)
) + theme(
axis.text.y=element_text(colour = "black", size=15)
)
Это дает следующий сюжет:
![ggplot_new](https://i.stack.imgur.com/lEi0p.png)
Маркировка вторичной оси Y является правильной для логарифмической части оси (ниже 0,5), но неправильной для линейной части оси.
Если я установлю ggplot2 3.0.0, используя
require(devtools)
install_version("ggplot2", version = "3.0.0", repos = "http://cran.us.r-project.org")
и запустить тот же код, что и выше, я получаю следующий график, который я хочу:
![ggplot_old](https://i.stack.imgur.com/vgjw9.png)
Вопросы
- Есть ли способ исправить эту проблему в новейшей версии ggplot2 (3.1.0)? В идеале я хотел бы воздержаться от использования более старой версии ggplot2 (т.е. 3.0.0).
- Есть ли альтернативы
sec_axis
, которые бы работали в этом случае?