Добавление легенды вручную на график R / ggplot2 без вмешательства в график - PullRequest
0 голосов
/ 28 марта 2020

Вопрос: Можно ли добавить к сюжету легенду, которая не имеет ничего общего с самим сюжетом и - что крайне важно - не будет мешать цветам на сюжете?

Объяснение

У меня есть вся необходимая информация для легенды. В частности, у меня есть шестнадцатеричные коды цветов и ярлыки. Мне все равно, какие фигуры показаны (линии, точки, в зависимости от того, что проще).

Я надеялся, что это поможет (это очень упрощенный минимальный рабочий пример):

the_colors <- c("#e6194b", "#3cb44b", "#ffe119", "#0082c8", "#f58231", "#911eb4", "#46f0f0", "#f032e6", 
                "#d2f53c", "#fabebe", "#008080", "#e6beff", "#aa6e28", "#fffac8", "#800000", "#aaffc3", 
                "#808000", "#ffd8b1", "#000080", "#808080", "#ffffff", "#000000")
the_labels <- c("01", "02", "03", "04", "05", "06", "07", "08", "09", "10")

the_df <- data.frame("col1"=c(1, 2, 2, 1), "col2"=c(2, 2, 1, 1), "col3"=c(1, 2, 3, 4))

the_plot <- ggplot() + geom_point(data=the_df, aes(x=col1, y=col2), color=the_colors[[4]])

the_plot <- the_plot +
  scale_color_manual("Line.Color", values=the_colors[1:length(the_labels)],
                      labels=the_labels)

К сожалению, он даже не покажет легенду.

Играя по правилам и включая аргумент color внутри элемента aesthetics, я могу заставить его показать легенду.

the_plot <- ggplot() + geom_point(data=the_df, aes(x=col1, y=col2, color=the_colors[[4]]))

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

На других языках это невероятно просто. В R / ggplot2 это кажется невероятно сложным.

Причина, по которой я хочу это сделать: Мне нужна легенда, которая не влияет на цвета в моем сюжете. Это иногда очень неудобно. Нет также более глубокой причины, по которой легенда должна связываться с цветами на графике, просто она реализована в R / ggplot2.

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

Другие вопросы: Были и другие вопросы, задающие то же самое предмет. Вместо этого в ответах предлагались обходные пути для решения конкретной проблемы ОП (обычно путем применения melt() или около того) без предоставления решения поставленного вопроса (как добавить легенду вручную, не вмешиваясь в сюжет). Например, здесь и здесь . Это не то, что меня интересует. Я хотел бы знать, могу ли я добавить произвольную легенду к произвольному сюжету и, если да, то как.

Программное обеспечение: R 3.6. 3, ggplot2 3.2.1

Редактировать (30 марта 2020 г.):

Решение: Как описано в ответе @ Tjebo ниже, легенда о том, что является достаточно независимым от графика и определяет дополнительные ряды данных, не показанные на графике, могут быть созданы с помощью scale_color_identity. С помощью опции # 1 в ответе @Tjebo я мог решить свою непосредственную проблему:

the_colors <- sort(c("#e6194b", "#3cb44b", "#ffe119", "#0082c8", "#f58231", "#911eb4", "#46f0f0", "#f032e6", 
            "#d2f53c", "#fabebe", "#008080", "#e6beff", "#aa6e28", "#fffac8", "#800000", "#aaffc3", 
            "#808000", "#ffd8b1", "#000080", "#808080"))

color_df <- data.frame(the_colors=the_colors[1:length(the_labels)], the_labels=the_labels)

the_df <- data.frame("col1"=c(1, 2, 2, 1), "col2"=c(2, 2, 1, 1), "col3"=c(1, 2, 3, 4))

the_plot <- ggplot() + 
    geom_point(data = color_df, aes(x = the_df$col1[[1]], y = the_df$col2[[1]], color = the_colors)) +
    scale_color_identity(guide = 'legend', labels = color_df$the_labels) 

the_plot <- the_plot +
  geom_point(data=the_df, aes(x=col1, y=col2), color=the_colors[[4]]) 

print(the_plot)

Объяснение решения: В более общем смысле, как объясняет Tjebo, он отделяет сюжет от легенда. Легенда еще нуждается в сюжете. Сначала он строится следующим образом:

the_plot <- ggplot() + 
  geom_point(data = color_df, aes(x = the_df$col1[[1]], y = the_df$col2[[1]], color = the_colors)) +
  scale_color_identity(guide = 'legend', labels = color_df$the_labels)

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

the_plot <- the_plot + 
  geom_point(data=the_df, aes(x=col1, y=col2), color=the_colors[[4]])

Он также гибок в том, что можно добавлять дополнительные ряды данных в любом из цветов, которые предварительно определены в переменной the_colors:

the_plot <- the_plot +
  geom_point(data=the_df, aes(x=col1, y=col3), color=the_colors[[6]]) 

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

Редактировать 2 (30 марта 2020 г.), Дополнительное примечание: При таком решении легенда сортирует цвета по их шестнадцатеричным кодам. Я не могу понять, почему он это делает, но это так. Таким образом, чтобы цвета в легенде соответствовали предполагаемым цветам, вектор шестнадцатеричных кодов должен быть отсортирован заранее (как это сделано в приведенном выше коде).

Неожиданное поведение, подобное этому, не будет проблемой при обычном использовании R и ggplot2 (когда вы разрешаете ggplot2 делать легенду за вас и строго ограничиваетесь тем, какие конструкции предназначены для использования). Это решение по сути является хакерским указанием на то, как легенда будет использоваться в ggplot2 (к сожалению, довольно ограниченно). Таким образом, возможно, что этот взлом будет сломан в будущих версиях ggplot или R.

1 Ответ

1 голос
/ 28 марта 2020

Может быть, это то, что вы хотите ... График 1 определенно не является умным и ggplot-y способом построения графиков (по сути, вы не визуализируете измерения ваших данных). Ниже другой вариант (график 2) ...

Ниже - создание нового фрейма данных и графика с помощью scale_color_identity. Используйте точку данных вашего второго графика, которая идет вторым и перекрывает первый график, поэтому точка исчезает.

library(tidyverse)
the_colors <- c("#e6194b", "#3cb44b", "#ffe119", "#0082c8", "#f58231", "#911eb4", "#46f0f0", "#f032e6", 
                "#d2f53c", "#fabebe", "#008080", "#e6beff", "#aa6e28", "#fffac8", "#800000", "#aaffc3", 
                "#808000", "#ffd8b1", "#000080", "#808080", "#ffffff", "#000000")

color_df <- data.frame(the_colors, the_labels = seq_along(the_colors))

the_df <- data.frame("col1"=c(1, 2, 2, 1), "col2"=c(2, 2, 1, 1), "col3"=c(1, 2, 3, 4))

#the_plot <- 
  ggplot() + 
    geom_point(data = color_df, aes(x = the_df$col1[[1]], y = the_df$col2[[1]], color = the_colors)) +
    scale_color_identity(guide = 'legend', labels = color_df$the_labels) +
    geom_point(data=the_df, aes(x=col1, y=col2), color=the_colors[[4]]) 

более ggplot-y way

Теперь последний сюжет действительно своеобразен, потому что, как вы говорите, «цвета не имеют ничего общего с сюжетом» [с данными], поэтому показывать их абсолютно бессмысленно. На самом деле вы хотите визуализировать измерения ваших данных.

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

Сначала создайте именованный вектор, чтобы вы могли передать его в качестве аргумента values в scale_color. Имена должны быть значениями вашего столбца, которые будут представлены цветом, в данном случае col3.

names(the_colors) <- str_pad(seq_along(the_colors), width = 2, pad = '0')

the_df <- data.frame("col1"=c(1, 2, 2, 1), "col2"=c(2, 2, 1, 1), "col3"=str_pad(c(1, 2, 3, 4), width = 2,pad='0'))

ggplot() + 
  geom_point(data=the_df, aes(x=col1, y=col2, color = col3))  +
  scale_color_manual(limits = names(the_colors), values = the_colors)

Создано в 2020-03-28 пакетом Представить (v0.3.0)

...