пользовательская легенда ggplot с использованием R - PullRequest
1 голос
/ 04 августа 2020

Я хотел бы вручную настроить легенду в моем сюжете, который я создаю с помощью ggplot, а также добавить два новых элемента в легенду. Сейчас легенда отображается как заголовок легенды - фактор (CruiseID), за которым следует красный кружок с текстом 201905, а затем синий кружок с текстом 201906, хотя в коде есть код scale_fill_manual. Я не хотел бы иметь заголовок легенды, за которым следовали красный кружок и текст 2019 MAB Leg 1, синий круг и текст 2019 MAB Leg 2, серое поле и текст Survey Domain белое поле с черным контуром и текстовой областью доступа

пример данных

data<-data.frame(CruiseID=c(rep(201905,5),rep(201906,5)),
                 beglat=c(36.66,36.66,37.07,37.01,37.03,37.033,37.08,37.09,37.07,37.077),
                 beglong=c(-74.75,-74.75,-74.73,
                  -74.731,-74.90,-74.90,-74.88,-74.88,
                  -74.72,-74.72))


ggplot() +
  geom_point(data = data, aes(x = beglong, y = beglat,colour=factor(CruiseID))) +
  scale_colour_manual(values = c("red", "blue"),drop=T)+
  xlim(-76,-71)+
  ylim(36,42)+
  ggtitle("2019 MAB Survey Stations") +
  labs(x = "Longitude", y = "Latitude") +
  scale_fill_manual(values = c("red", "blue","gray87","black"),
                    labels = c('Leg 1', 'MAB Leg 2','Survey Domain','Access Area'))+
  theme_bw()+
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.title=element_text(size=14),
        text=element_text(size=12),
        axis.text.x=element_text(colour="black", size = 12),
        axis.text.y=element_text(colour="black", size = 12),
        legend.justification=c(.5,.5), 
        legend.background = element_rect(fill = "white", color = NA),
        legend.position=c(0.8, 0.3),legend.box="vertical", 
        legend.margin=margin())

Ответы [ 2 ]

2 голосов
/ 04 августа 2020

Вот решение, которое использует ggnewscale::new_scale_color для создания двух шкал для цвета, одну для точек, а другую для прямоугольников. Кроме того, я создал дополнительный data.frame с именем df для построения двух прямоугольников с использованием geom_rect и создания легенды для блоков.

library(ggplot2)
library(ggnewscale)

# Create another data frame to plot the rectangles and its legend
df <- data.frame (xmin = c(0,0),
            xmax = c(0,0),
            ymin = c(0,0),
            ymax = c(0,0),
            fill = c("A","B"))

ggplot() +
  geom_point(data = data, aes(x = beglong, 
                              y = beglat, 
                              colour=factor(CruiseID))) +
  # Move the color scale for the points before setting a new scale color
  scale_color_manual(values = c("red", "blue"),
                      labels = c('2019 MAB Leg 1', '2019 MAB Leg 2'))+
  # Set new scale color
  new_scale_color() +
  # plot rectangles in 0,0; where they will not appear in the plot's area
  geom_rect(data = df,aes(xmin = xmin,
                          xmax = xmax,
                          ymin = ymin,
                          ymax = ymax,
                          fill = fill,
                          col = fill)) +
  # Manually set color for the boxes
  scale_color_manual(values = c("white","black"),
                     labels = c('Survey Domain', 'Access Area')) +
  # Manually set fill for the boxes, use same labels as color so the box legends are combined
  scale_fill_manual(values = c("gray87","white"),
                    labels = c('Survey Domain', 'Access Area'))+
  xlim(-76,-71)+
  ylim(36,42)+
  ggtitle("2019 MAB Survey Stations") +
  labs(x = "Longitude", y = "Latitude") +
  theme_bw()+
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.title=element_text(size=14),
        text=element_text(size=12),
        axis.text.x=element_text(colour="black", size = 12),
        axis.text.y=element_text(colour="black", size = 12),
        legend.justification=c(.5,.5),
        # Remove legend title
        legend.title = element_blank(),
        legend.background = element_rect(fill = "white", color = NA),
        legend.position=c(0.8, 0.3),legend.box="vertical", 
        legend.margin=margin())

желаемый сюжет

0 голосов
/ 05 августа 2020

Впереди, комментарий @RuiBarradas по поводу scale_fill_manual является правильным и ошибочным из вашего кода. Я полагаю, вы включили его, надеясь добавить свои области (опрос и доступ) позже. Возможно, вы думали, что это может повлиять на вашу цветовую легенду (или просто запутали их). Тем не менее, его точка зрения верна: scale_fill_manual здесь ничего не делает, если вы действительно не используете fill= как aes theti c где-нибудь на графике. Все наименования и тому подобное должны быть выполнены в scale_color_manual для ваших точек.

Кроме того, у вас есть два варианта для установки ваших меток. Я считаю, что вы можете использовать labels= в своих масштабных вызовах для их установки, и это может быть именованный вектор c("201905" = "MAB Leg 1", ...). Или вы можете использовать метки изначально в эстетике c (как я делаю ниже). Они оба работают, но для первого требуется немного больше управления данными без ggplot.

Я предлагаю немного другую организацию данных.

  • Поскольку вы не хотите показывает числа 201905 (et c), но вы хотите назначить им метки и цвета, я создам фрейм labels, который сопоставляет их вместе, а затем я merge их.

  • Поскольку у вас есть scale_fill_manual, но не назначена fill= эстетика, я создам фальшивый areas фрейм, который содержит ваши два типа области. Я назначу им произвольные значения CruiseID, чтобы мы могли использовать фрейм labels для их идентификации (а также их заливки).

labels <- data.frame(
  CruiseID = c(201905, 201906, -1, -2),
  # 'factor' to preserve the order
  label    = factor(c("MAB Leg 1", "MAB Leg 2", "Survey Domain", "Access Area")),
  color    = c("red", "blue", "#00000000", "black"),
  fill     = c("#00000000", "#00000000", "gray", "white")
)
areas <- data.frame(
  label = c(-1, -2),
  beglat = NA_real_, beglong = NA_real_)

Затем Значение values= функций scale_*_manual может работать с именованным вектором. Я повторно использую labels для этого, используя небольшой трюк, чтобы превратить два столбца в именованный вектор:

labels
#   CruiseID         label     color      fill
# 1   201905     MAB Leg 1       red #00000000
# 2   201906     MAB Leg 2      blue #00000000
# 3       -1 Survey Domain #00000000      gray
# 4       -2   Access Area     black     white
setNames(labels$color, labels$label)
#     MAB Leg 1     MAB Leg 2 Survey Domain   Access Area 
#         "red"        "blue"   "#00000000"       "black" 

Для удаления заголовков легенд просто добавьте name=NULL к применимым scale_ звонки.

Код:

ggplot() +
  geom_point(                                     # UPDATED
    data = merge(data, labels, by = "CruiseID", all.x = TRUE),
    aes(x = beglong, y = beglat, colour = label)) +
  scale_colour_manual(                            # UPDATED
    name = NULL,
    values = setNames(labels$color, labels$label),
    drop = TRUE) +
  geom_polygon(                                   # NEW, placeholder
    data = merge(areas, labels, by = "CruiseID", all.x = TRUE),
    aes(x = beglong, y = beglat, fill = label),
    na.rm = TRUE) +
  scale_fill_manual(                              # UPDATED
    name = NULL,
    values = setNames(labels$fill, labels$label),
    drop = TRUE) +
  xlim(-76,-71) +
  ylim(36,42) +
  ggtitle("2019 MAB Survey Stations") +
  labs(x = "Longitude", y = "Latitude") +
  theme_bw() +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    plot.title=element_text(size=14),
    text=element_text(size=12),
    axis.text.x=element_text(colour="black", size = 12),
    axis.text.y=element_text(colour="black", size = 12),
    legend.justification=c(.5,.5), 
    legend.background = element_rect(fill = "white", color = NA),
    legend.position=c(0.8, 0.3),legend.box="vertical", 
    legend.margin=margin(),
    legend.key = element_rect(colour = "black")   # NEW
  )

updated ggplot2 with boxed legends

Finally, without editing the grob (graphic object) and/or graphic-table manually, I don't think there's a way to box in the colors of one legend and not the other: the theme option legend.key allows us to box them in, but it applies to all legends. If you don't mind the boxes around the dots, you're good. If you can't have them, then you can remove the legend.key= option and change your "Access Area" from white to something different than the background color, so that it is visible.

labels <- data.frame(
  CruiseID = c(201905, 201906, -1, -2),
  # 'factor' to preserve the order
  label    = factor(c("MAB Leg 1", "MAB Leg 2", "Survey Domain", "Access Area")),
  color    = c("red", "blue", "#00000000", "black"),
  fill     = c("#00000000", "#00000000", "gray", "gray90")
)

ggplot() +
  geom_point(                                     # UPDATED
    data = merge(data, labels, by = "CruiseID", all.x = TRUE),
    aes(x = beglong, y = beglat, colour = label)) +
  scale_colour_manual(                            # UPDATED
    name = NULL,
    values = setNames(labels$color, labels$label),
    drop = TRUE) +
  geom_polygon(                                   # NEW, placeholder
    data = merge(areas, labels, by = "CruiseID", all.x = TRUE),
    aes(x = beglong, y = beglat, fill = label),
    na.rm = TRUE) +
  scale_fill_manual(                              # UPDATED
    name = NULL,
    values = setNames(labels$fill, labels$label),
    drop = TRUE) +
  xlim(-76,-71) +
  ylim(36,42) +
  ggtitle("2019 MAB Survey Stations") +
  labs(x = "Longitude", y = "Latitude") +
  theme_bw() +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    plot.title=element_text(size=14),
    text=element_text(size=12),
    axis.text.x=element_text(colour="black", size = 12),
    axis.text.y=element_text(colour="black", size = 12),
    legend.justification=c(.5,.5), 
    legend.background = element_rect(fill = "white", color = NA),
    legend.position=c(0.8, 0.3),legend.box="vertical", 
    legend.margin=margin()
  )

обновлен ggplot2, легенда без рамки

...