2016-01-06 2 views
17

Как вы регулируете асимметричное расширение пределов в ggplot? Например,Асимметричное расширение пределов [ggplot2 2.0]

library(ggplot2) 

ggplot(mtcars) + 
    geom_bar(aes(x = cyl), width = 1) 

enter image description here

Я хотел бы в нижней части брусков заподлицо с нижней части фона панели, но будет по-прежнему, как пространство в верхней части. Я могу добиться этого с пустой аннотацией:

ggplot(mtcars) + 
    geom_bar(aes(x = cyl), width = 1) + 
    annotate("blank", x = 4, y = 16) + 
    scale_y_continuous(expand = c(0.0,0)) 

enter image description here

В предыдущих версиях ggplot, однако, я мог бы использовать the solution provided by Rosen Matev:

library("scales") 
scale_dimension.custom_expand <- function(scale, expand = ggplot2:::scale_expand(scale)) { 
    expand_range(ggplot2:::scale_limits(scale), expand[[1]], expand[[2]]) 
} 

scale_y_continuous <- function(...) { 
    s <- ggplot2::scale_y_continuous(...) 
    class(s) <- c('custom_expand', class(s)) 
    s 
} 

, а затем использовать scale_y_continuous(expand = list(c(0,0.1), c(0,0))), который бы добавить последовательно дополнение к вершине диаграммы. В текущей версии, однако, я получаю сообщение об ошибке

ggplot(mtcars) + 
    geom_bar(aes(x = cyl), width = 1) + 
    scale_y_continuous(expand = list(c(0,0.1), c(0,0))) 

# Error in diff(range) * mul : non-numeric argument to binary operator 

Есть ли эффективное решение для ggplot2 2.0?

Решение должно включать в себя возможность гибкой работы с фасетками и free_xy вариантов масштаба. Например,

ggplot(mtcars) + 
    geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
    facet_grid(vs ~ ., scales = "free_y") 

enter image description here

Раствор должен давать что-то вроде:

ggplot(mtcars) + 
    geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
    facet_grid(vs ~ ., scales = "free_y") + 
    scale_y_continuous(expand = c(0,0)) + 
    geom_blank(data = data.frame(cyl = c(5,5), y = c(12, 16), vs = c(1,0)), aes(x = cyl, y = y)) 

enter image description here

+1

Для обеспечения максимальной гибкости, я бы предложил сделать пример в ваших аспектах использования вопрос. Для незапланированного графика можно агрегировать свои данные и использовать 'ylim = c (0, 1.1 * max (aggregated_data $ y_variable))' - хотя и не так хорошо, как модифицированное решение расширения. С граненой графикой решение 'ylim' не будет работать хорошо, поэтому решение' expand' * необходимо *. – Gregor

+0

В незавершенном случае вы не могли использовать 'coord_cartesian', чтобы получить нужный эффект? Например: 'coord_cartesian (ylim = c (0, max (таблица (mtcars $ cyl)) + 2), xlim = c (min (mtcars $ cyl) -0.75, max (mtcars $ cyl) +0.75), expand = FALSE) '. До версии 2.0 нет необходимости устанавливать 'xlim', но (насколько я могу сказать) теперь, когда по умолчанию используется' expand = TRUE', вам нужно явно установить оба ограничения, если вы хотите сохранить заполнение на ось х. – eipi10

+0

@ eipi10 делает мой пункт. В безграничном случае вы можете найти обходные пути довольно легко. Ответ * Меня интересует (и я думаю, что Хью тоже) - это тот, который работает как с фасетками, так и без них. – Gregor

ответ

4

С ggplot2 2.2.1, теперь мы можем использовать expand_scale достижению цели Op в

Edit: вы на самом деле нужно разрабатываемую версию ggplot2 2.2.1.9000. Запуск
devtools::install_github("tidyverse/ggplot2") для установки.

library(ggplot2) 

    ggplot(mtcars) + 
     geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
     facet_grid(vs ~ ., scales = "free_y") + 
     scale_y_continuous(expand = expand_scale(mult = c(0, .2))) 

enter image description here

2

я использовал решение Розен Matev часто, и был разочарован, когда он порвал с ggplot версии 2,0. Я предлагаю решение, хотя и не столь изящное, как Rosen's, но будет работать на участках без фасетов, facet_wrap и facet_grid, а также в одностороннем и двухстороннем порядке facet_grid. Однако он не будет работать с более сложными сетками фасетов и не будет работать с coord_flip. Существуют две функции: одна для асимметричного расширения вдоль оси y и одна для разложения вдоль оси x. Функции выполняют мультипликативные и аддитивные разложения.

Функции собирают информацию из графика, вычисляют новые пределы для оси y (или x), затем используют geom_blank для построения новых графиков с требуемыми коэффициентами расширения.

Во-первых, функция для выполнения асимметричного расширения вдоль оси y.

# Function takes two parameters 
# 'p' is the plot 
# 'expand' is a list of two vectors: 
#  First vector contains the multiplicative factors; 
#  Second vector contains the additive parts. 
#  First element in each vector refers to the lower boundary; 
#  Second element refers to the upper boundary. 

asymmY = function(p, expand = list(mult = c(0, .2), add = c(0, 0))) { 

    np = p + coord_cartesian(expand = FALSE) # No expand 
    gb <- ggplot_build(np) 

    limits <- sapply(gb$panel$ranges, "[[", "y.range") 
    range = apply(limits, 2, function(x) max(x) - min(x)) 
    rangeU = range*expand[[1]][2] 
    rangeL = range*expand[[1]][1] 
    limits <- limits + rbind(-rangeL, rangeU) # Multiplicative expand 

    limits[1,] = limits[1,] - expand[[2]][1] # Additive expand 
    limits[2,] = limits[2,] + expand[[2]][2] 

    limits = as.vector(limits) 

    df = facet_type(np, gb, "y", limits) # df with new limits - depends on facet type 

    np = np + geom_blank(data = df, inherit.aes = FALSE, aes(x = Inf, y = y)) # new plot 

    # But the x axis expansions were set to false. Put back the default expand 
    gb <- ggplot_build(np) 

if(any(grepl("Discrete", class(gb$panel$x_scale[[1]])))) { 
    limits <- sapply(gb$panel$ranges, "[[", "x.range") 
    limits[1,] = ceiling(limits[1,]) - .6 
    limits[2,] = trunc(limits[2,]) + .6 
    limits = as.vector(limits) 
} else { 
    limits <- sapply(gb$panel$ranges, "[[", "x.range") 
    range = apply(limits, 2, function(x) max(x) - min(x)) 
    rangeU = range*.05 
    rangeL = range*.05 
    limits <- limits + rbind(-rangeL, rangeU) 
    limits = as.vector(limits) 
} 

    df = facet_type(np, gb, "x", limits) 

    np + geom_blank(data = df, inherit.aes = FALSE, aes(x = x, y = Inf)) 
} 

# Function to determine type of facetting 
# and to get data frame of new limits. 
facet_type = function(np, gb, axis, limits) { 
    if(class(np$facet)[1] == "null") { 
     setNames(data.frame(y = limits), axis) 
    } else 
    if(class(np$facet)[1] == "wrap") { 
     facetvar <- as.character(np$facet$facets) 
     facetlev <- gb$panel$layout[[facetvar]] 
     setNames(data.frame(rep(facetlev, each = 2), limits), c(facetvar, axis)) 
    } else { 
     facetvar <- as.character(np$facet$cols) 
     if(length(facetvar) == 0) facetvar <- as.character(np$facet$rows) 
     facetlev <- gb$panel$layout[[facetvar]] 
     setNames(data.frame(rep(facetlev, each = 2), limits), c(facetvar, axis)) 
    } 
} 

Попробуйте использовать некоторые граничные сетки и фасетные сетки.

# Try asymmetric expand along y-axis 
library(ggplot2) 

p1 <- ggplot(mtcars) + 
    geom_bar(aes(x = factor(cyl))) + 
    facet_grid(am ~ vs , scales = "free_y") 

p2 <- ggplot(mtcars) + 
    geom_bar(aes(x = factor(cyl), fill = factor(vs)), width = .5) + 
    facet_grid(vs ~ ., scales = "free_y") 

p3 <- ggplot(mtcars) + 
    geom_bar(aes(x = factor(cyl), fill = factor(vs)), width = .5) + 
    facet_grid(. ~ vs) 

p4 <- ggplot(mtcars) + 
    geom_bar(aes(x = factor(cyl), fill = factor(vs)), width = .5) + 
    facet_wrap(~vs, scales = "free_y") 

asymmY(p1, list(c(0, 0.1), c(0, 0))) 
asymmY(p2, list(c(0, 0.1), c(0, 0))) 
asymmY(p3, list(c(0, 0.1), c(0, 0))) 
asymmY(p4, list(c(0, 0.1), c(0, 0))) 

Во-вторых, функция для выполнения асимметричного расширения вдоль оси х.

asymmX = function(p, expand = list(mult = c(0, .2), add = c(0, 0))) { 

    np = p + coord_cartesian(expand = FALSE) # No expand 
    gb <- ggplot_build(np) 

    limits <- sapply(gb$panel$ranges, "[[", "x.range") 
    range = apply(limits, 2, function(x) max(x) - min(x)) 
    rangeU = range*expand[[1]][2] 
    rangeL = range*expand[[1]][1] 
    limits <- limits + rbind(-rangeL, rangeU) # Mult expand 

    limits[1,] = limits[1,] - expand[[2]][1] 
    limits[2,] = limits[2,] + expand[[2]][2] # Add expand 

    limits = as.vector(limits) 

    df = facet_type(np, gb, "x", limits) # df with new limits - depends on facet type 

    np = np + geom_blank(data = df, inherit.aes = FALSE, aes(x = x, y = Inf)) # new plot 

    # But the y axis expansions were set to false. Put back the default expand 
    gb <- ggplot_build(np) 

if(any(grepl("Discrete", class(gb$panel$y_scale[[1]])))) { 
    limits <- sapply(gb$panel$ranges, "[[", "y.range") 
    limits[1,] = ceiling(limits[1,]) - .6 
    limits[2,] = trunc(limits[2,]) + .6 
    limits = as.vector(limits) 
} else { 
    limits <- sapply(gb$panel$ranges, "[[", "y.range") 
    range = apply(limits, 2, function(x) max(x) - min(x)) 
    rangeU = range*.05 
    rangeL = range*.05 
    limits <- limits + rbind(-rangeL, rangeU) 
    limits = as.vector(limits) 
} 

    df = facet_type(np, gb, "y", limits) 

    np + geom_blank(data = df, inherit.aes = FALSE, aes(x = Inf, y = y)) 
} 

Попробуйте.

# Try asymmetric expand along x-axis 
df = data.frame(x = c(20, 15, 25, 23, 12, 14), 
       y = rep(c("a", "b", "c"), 2), 
       z = rep(c("aaa", "bbb"), each = 3), 
       w = rep(c("ccc", "ddd", "eee"), each = 2)) 

p1 = ggplot(df[,-4]) + geom_point(aes(x, y)) + 
    geom_segment(aes(x = 0, xend = x, y = y, yend = y)) + 
    geom_text(aes(x = x, y = y, label = x), hjust = -1) + 
    facet_grid(. ~ z, scales = "free_x") 

p2 = ggplot(df[, -4]) + geom_point(aes(x, y)) + 
    geom_segment(aes(x = 0, xend = x, y = y, yend = y)) + 
    geom_text(aes(x = x, y = y, label = x), hjust = -1) + 
    facet_grid(z ~ .) 

p3 = ggplot(df) + geom_point(aes(x, y)) + 
    geom_segment(aes(x = 0, xend = x, y = y, yend = y)) + 
    geom_text(aes(x = x, y = y, label = x), hjust = -1) + 
    facet_grid(w ~ z) 

p4 = ggplot(df[,-4]) + geom_point(aes(x, y)) + 
    geom_segment(aes(x = 0, xend = x, y = y, yend = y)) + 
    geom_text(aes(x = x, y = y, label = x), hjust = -1) + 
    facet_wrap(~ z) 

asymmX(p1, list(c(0, .15), c(0, 0))) 
asymmX(p2, list(c(0, 0), c(0, 5))) 
asymmX(p3, list(c(0, .2), c(0, 0))) 
asymmX(p4, list(c(0, 0), c(9, 5))) 
5

Я теперь пытался добавить код для этого ggplot2; см. issue #1669 и corresponding pull request. Если это принято, синтаксис аргумента expand будет изменен с c(m, a) на c(m_lower, a_lower, m_uppper, a_upper), для указания отдельных значений расширения для нижнего и верхнего пределов диапазона. (Старый синтаксис будет по-прежнему продолжают работать, хотя, как первые два элемента будут повторно использоваться, если элементы три и/или четыре отсутствуют.)

С помощью этого нового синтаксиса, вы можете использовать

ggplot(mtcars) + 
    geom_bar(aes(x = cyl), width = 1) + 
    scale_y_continuous(expand = c(0, 0, 0.05, 0)) 

результат выглядит следующим образом:

Simple bar chart

Он также работает с facetting:

ggplot(mtcars) + 
    geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
    facet_grid(vs ~ ., scales = "free_y") + 
    scale_y_continuous(expand = c(0, 0, 0.05, 0)) 

Bar chart with facetting

+2

Что случилось с реализацией? – Ferroao

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