Редактировать 2
Текущая версия ggplot2-пакета для разработки действительно решает проблему, упомянутую в моем вопросе ниже. Установите версию dev, используя
devtools::install_github("tidyverse/ggplot2")
редактировать
Кажется, что ошибочное поведение sec_axis
в ggplot2 3.1.0 является ошибкой. Это было признано разработчиками, и они работают над исправлением (см. Ветку на 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)
)
Это дает следующий сюжет:
Маркировка вторичной оси Y является правильной для логарифмической части оси (ниже 0,5), но неверной для линейной части оси.
Если я устанавливаю ggplot2 3.0.0 с помощью
require(devtools)
install_version("ggplot2", version = "3.0.0", repos = "http://cran.us.r-project.org")
и запустить тот же код, что и выше, я получаю следующий график, который я хочу:
Вопросы
- Есть ли способ исправить эту проблему в новейшей версии ggplot2 (3.1.0)? В идеале я хотел бы воздержаться от использования более старой версии ggplot2 (т.е. 3.0.0).
- Есть ли альтернативы
sec_axis
которые будут работать в этом случае?