2015-01-22 1 views
2

У меня есть цены со временем для разных типов продуктов. Я хочу визуализировать эволюцию разных цен в одном листе, поэтому я использую граненый ggplot. Вот моя игрушка пример:предотвратить второй aes(), чтобы переопределить диапазон осей (ylim, xlim) в ggplot2

df1 <- data.frame(time = rep(1:100, times = 5), 
        type = rep(c("A", "B", "C", "D", "E"), each = 100), 
        price = rnorm(n = 500, mean = 100)) 

gp <- ggplot(data = df1, aes(x = time, y = price)) 
# scales free because the price level of each product may be different 
gp <- gp + facet_wrap(~type, nrow = 3, ncol = 2, scales = "free") 
gp <- gp + geom_point() + geom_line() 
gp 

Это создает сюжет я хочу:

enter image description here

У меня также есть справочные цены для каждого вида продукции (в другом наборе данных), и я хочу указать эти цены на участке. Поэтому я использую geom_hline() следующим образом:

df2 <- data.frame(type = c("A", "B", "C", "D", "E"), 
        refprice = c(100, 105, 95, 50, 40)) 
gp <- gp + geom_hline(data = df2, aes(yintercept = refprice), facets = ~type) 

enter image description here

Это работает, но это может существенно изменить диапазон оси у, и я не хочу этого. Я хотел бы оставить ylim автоматически генерируемым первой частью, чтобы правильно визуализировать эволюцию цен независимо от ссылочной цены (нормально не видеть ссылочную цену, если она не относительно близка к фактической Цены).

Я знаю, что могу использовать scale_y_continuous(), coord_cartesian() или стенографию ylim() вручную установить пределы, как я хочу, но мне не нравится этот вариант, потому что либо требует жесткого кодирования ограничения или слишком много кодирования для расчета соответствующих лимитов. Поэтому я думал, что в ggplot должен быть более простой и элегантный способ избежать второго вызова для переопределения ylim и вместо этого использовать ylim, сгенерированные при первом вызове.

Я искал (я думаю, тщательно) для решения этой проблемы (SO, google, rseek), и все, что я нахожу, включает в себя решения, которые я только что сказал, что мне не нравится. Поэтому я решил опубликовать его здесь, чтобы узнать, знает ли кто-нибудь скрытую (или не настолько скрытую) функцию в ggplot2, чтобы сделать это проще и элегантнее. Большое спасибо.

+1

это использование ylim но, по крайней мере, кажется, чтобы соответствовать масштабам сгенерированные автоматически и не требует каких-либо дальнейших расчетов '+ ylim (мин (df1 $ цена), максимальная (df1 $ цена)) ' – beetroot

+0

Thx. Это решение не работает для меня жестко, потому что каждый сюжет (фасет) может иметь очень разные уровни цен (поэтому мне нужны шкалы = «свободные», чтобы допускать разные диапазоны по осям каждого графика) и 'ylim (min (df1 $ price), max (df1 $ price)) 'накладывает общий диапазон на всю ось y. –

ответ

1
yrange <- sapply(ggplot_build(gp)$panel$ranges, function(x) x$y.range) 
#order df2 correctly (the same order as the panels) if it isn't 

gp + geom_hline(data = df2[df2$refprice >= yrange[1,] & df2$refprice <= yrange[2,],], 
       aes(yintercept = refprice)) 

resulting plot

+0

Спасибо. Умный !, чтобы отображать только те наблюдения в пределах требуемого диапазона. Хотя он работает в том смысле, что он производит результат, который я ищу, это решение попадает в группу решений, которые мне не нравятся в этом случае (потому что это связано с большим количеством кодировок - много строк -). Возможно, я слишком упростил свой пример с игрушкой, и в этом примере вам не нужно включать много строк кода, но в моем реальном приложении у меня есть другие горизонтальные линии, цвет которых зависит от справочной цены, поэтому я не могу просто отбросьте эти наблюдения за пределами соответствующего диапазона. –

+0

@HernandoCasas Я изменил его, чтобы работать со «свободными» шкалами. – Roland

+1

Вы не можете иметь свой торт и съесть его. Сложные цели требуют некоторого кодирования. – Roland

Смежные вопросы