Контролировать порядок точек в ggplot2 в R?

Предположим, я строю график плотного рассеяния в ggplot2 в R, где каждая точка может быть помечена другим цветом:

df <- data.frame(x=rnorm(500))
df$y = rnorm(500)*0.1 + df$x
df$label <- c("a")
df$label[50] <- "point"
df$size <- 2
ggplot(df) + geom_point(aes(x=x, y=y, color=label, size=size))

Когда я делаю это, точка рассеяния, обозначенная "точка" (зеленая), наносится поверх красных точек, которые имеют метку "а". Что управляет этим z-порядком в ggplot, т.е. что контролирует, какая точка поверх какой? Например, что, если бы я хотел, чтобы все точки "а" находились поверх всех точек, помеченных как "точка" (то есть они иногда частично или полностью скрывали бы эту точку)? Зависит ли это от буквенно-цифрового упорядочения меток? Я хотел бы найти решение, которое можно легко перевести на rpy2. Спасибо

4 ответа

Обновление 2016:

Эстетика заказа устарела, поэтому на данный момент самый простой подход - отсортировать data.frame так, чтобы зеленая точка находилась внизу и отображалась последней. Если вы не хотите изменять исходный файл data.frame, вы можете отсортировать его во время вызова ggplot - вот пример, который использует %>% а также arrange из пакета dplyr для сортировки на лету:

library(dplyr)
ggplot(df %>%
         arrange(label),
       aes(x = x, y = y, color = label, size = size)) +
  geom_point()

Оригинальный ответ 2015 года для версий ggplot2 < 2.0.0

В ggplot2 вы можете использовать эстетику порядка, чтобы указать порядок, в котором отображаются точки. Последние из них будут отображаться сверху. Чтобы применить это, вы можете создать переменную, содержащую порядок, в котором вы хотите рисовать точки.

Чтобы поставить зеленую точку сверху, нанося ее на график, за другими:

df$order <- ifelse(df$label=="a", 1, 2)
ggplot(df) + geom_point(aes(x=x, y=y, color=label, size=size, order=order))

Или сначала нарисуйте зеленую точку и похороните ее, нарисуйте точки в обратном порядке:

ggplot(df) + geom_point(aes(x=x, y=y, color=label, size=size, order=-order))

В этом простом примере вы можете пропустить создание новой переменной сортировки и просто принудительно label переменная к фактору, а затем числовой:

ggplot(df) +
  geom_point(aes(x=x, y=y, color=label, size=size, order=as.numeric(factor(df$label))))

ggplot2 будет создавать графики слой за слоем, и в каждом слое порядок построения графиков определяется geom тип. По умолчанию график строится в том порядке, в котором они отображаются в data,

Где это отличается, это отмечено. Например

geom_line

Подключите наблюдения, упорядоченные по значению х.

а также

geom_path

Подключите наблюдения в порядке данных


Есть также известные проблемы, касающиеся заказаfactorsи интересно отметить ответ автора пакета Хэдли

Отображение графика должно быть инвариантным к порядку фрейма данных - все остальное является ошибкой.


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


Создайте второй слой

Если вы хотите, чтобы определенные значения отображались над другими значениями, вы можете использовать subset Аргумент для создания второго слоя, который обязательно будет нарисован впоследствии. Вам нужно будет явно загрузить plyr пакет так .() буду работать.

set.seed(1234)
df <- data.frame(x=rnorm(500))
df$y = rnorm(500)*0.1 + df$x
df$label <- c("a")
df$label[50] <- "point"
df$size <- 2
library(plyr)
ggplot(df) + geom_point(aes(x = x, y = y, color = label, size = size)) +
  geom_point(aes(x = x, y = y, color = label, size = size), 
             subset = .(label == 'point'))

Обновить

В ggplot2_2.0.0, subset аргумент устарел. Используйте, например, base::subset выбрать соответствующие данные, указанные в data аргумент. И нет необходимости загружать plyr:

ggplot(df) +
  geom_point(aes(x = x, y = y, color = label,  size = size)) +
  geom_point(data = subset(df, label == 'point'),
             aes(x = x, y = y, color = label, size = size))

Или использовать alpha

Другим подходом, позволяющим избежать проблемы переполнения, было бы установить alpha (прозрачность) точек. Это не будет столь же эффективным, как явный подход второго уровня выше, однако, при разумном использовании scale_alpha_manual Вы должны быть в состоянии заставить что-то работать.

например

# set alpha = 1 (no transparency) for your point(s) of interest
# and a low value otherwise
ggplot(df) + geom_point(aes(x=x, y=y, color=label, size=size,alpha = label)) + 
  scale_alpha_manual(guide='none', values = list(a = 0.2, point = 1))

Основной вопрос здесь можно перефразировать так:

Как мне контролировать слои моего графика?

В пакете 'ggplot2' вы можете сделать это быстро, разделив каждый слой на отдельную команду. Мышление с точки зрения слоев требует немного практики, но, по сути, все сводится к тому, что вы хотите изобразить поверх других вещей. Вы строите от фона вверх.

Подготовка: Подготовьте данные образца. Этот шаг необходим только для этого примера, потому что у нас нет реальных данных для работы.

# Establish random seed to make data reproducible.
set.seed(1)

# Generate sample data.
df <- data.frame(x=rnorm(500))
df$y = rnorm(500)*0.1 + df$x

# Initialize 'label' and 'size' default values.
df$label <- "a"
df$size <- 2

# Label and size our "special" point.
df$label[50] <- "point"
df$size[50] <- 4

Вы можете заметить, что я добавил в пример другой размер, чтобы сделать разницу между слоями более понятной.

Шаг 1: Разделите ваши данные на слои. Всегда делайте это ПРЕЖДЕ, чем используете функцию "ggplot". Слишком много людей застревают, пытаясь манипулировать данными с помощью функций 'ggplot'. Здесь мы хотим создать два слоя: один с метками "a" и один с метками "point".

df_layer_1 <- df[df$label=="a",]
df_layer_2 <- df[df$label=="point",]

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

Шаг 2: нанесите данные на слои. Мы хотим сначала построить все данные "а", а затем построить все данные "точки".

ggplot() + 
    geom_point(
        data=df_layer_1,
        aes(x=x, y=y), 
        colour="orange", 
        size=df_layer_1$size) +
    geom_point(
        data=df_layer_2, 
        aes(x=x, y=y), 
        colour="blue", 
        size=df_layer_2$size)

демонстрационная диаграмма

Обратите внимание, что базовый слой графика ggplot() не имеет назначенных данных Это важно, потому что мы собираемся переопределить данные для каждого слоя. Тогда у нас есть два отдельных точечных геометрических слоя geom_point(...) которые используют свои собственные спецификации. Оси x и y будут общими, но мы будем использовать разные данные, цвета и размеры.

Важно переместить спецификации цвета и размера за пределы aes(...) функция, поэтому мы можем указать эти значения буквально. В противном случае функция 'ggplot' обычно назначает цвета и размеры в соответствии с уровнями, найденными в данных. Например, если у вас есть значения размера 2 и 5 в данных, он назначит размер по умолчанию для всех вхождений значения 2 и назначит некоторый больший размер для всех вхождений значения 5. Спецификация функции "aes" будет Не используйте значения 2 и 5 для размеров. То же самое касается цветов. У меня есть точные размеры и цвета, которые я хочу использовать, поэтому я перемещаю эти аргументы в саму функцию 'geom_plot'. Также в легенду будут включены любые спецификации в функции "aes", которые могут быть действительно бесполезными.

Последнее замечание: в этом примере вы можете достичь желаемого результата разными способами, но важно понять, как работают слои 'ggplot2', чтобы получить максимальную отдачу от ваших диаграмм 'ggplot'. Пока вы разделяете свои данные на разные слои, прежде чем вызывать функции ggplot, вы можете контролировать, как все будет отображаться на экране.

Он представлен в порядке строк в data.frame. Попробуй это:

df2 <- rbind(df[-50,],df[50,])
ggplot(df2) + geom_point(aes(x=x, y=y, color=label, size=size))

Как видите, зеленая точка рисуется последней, поскольку она представляет последнюю строку в data.frame.

Вот способ заказать data.frame, чтобы сначала была нарисована зеленая точка:

df2 <- df[order(-as.numeric(factor(df$label))),]
Другие вопросы по тегам