0

I have a ggplot2 code which I used to apply frequently to my spatial dataframes:

borders <- sf::st_as_sf(maps::map("world", plot = FALSE, fill = TRUE))

xmin1 = range(Per_yr$Lon)[1]
xmax1 = range(Per_yr$Lon)[2]
ymin1 = range(Per_yr$Lat)[1]
ymax1 = range(Per_yr$Lat)[2]

DF <- ggplot(Per_yr) +
    geom_sf(data = borders, fill= "white")+
    geom_tile(aes(x=Lon, y=Lat, fill= as.character(Total)))+
    geom_sf(data = borders,fill = NA, colour = "dark green", size=0.2)+
    coord_sf(xlim = c(xmin1, xmax1), ylim = c(ymin1, ymax1))+
    scale_fill_manual(values = c("0" = "light grey", "1" = "#fcba03", "2"= "#e8940c", "3"="#DB6C05", "4"= "#e8550c", "5" = "#ad1320", "6" = "dark red",
    "7"= "#F87F65", "8"="#f772b0", "9"="#e02b73", "10" = "#611975", "11"="#8d49cc", "12" = "#b595e6",
    "13"= "#122da6", "14" = "blue", "15"="steel blue", "16" = "#609E90",  "17" =  "#0cb8e8", "18" = "#b7eb34", "19"="#90eb10",
    "20"= "#89dc69", "21"="#57c27e", "22" = "#b7c50e", "23"= "#799c11",  "24"= "#207852", "25"="#134d19"))+ 
    scale_x_longitude(ticks = 2) +
    scale_y_latitude(ticks = 2) 
  print(DF)

Here is a sample from my dataframe, Per_yr:

Lon Lat Total

24.0 35.3 13

24.0 35.4 8

24.0 35.5 3

24.0 37.7 5

24.0 37.8 5

24.0 38.0 7

24.0 38.1 8

The above code used to work fine, with the legend appearing in the exact same order I define the color assigned categories in scale_fill_manual. However, after I updated my R version to the new 4.3.1, and reinstalled tidyverse, ggplot started alphabeticising my legends.

From earlier stackoverflow questions, I tried different approaches to avert this, one of them below:

  xmin1 = range(Per_yr$Lon)[1]
  xmax1 = range(Per_yr$Lon)[2]
  ymin1 = range(Per_yr$Lat)[1]
  ymax1 = range(Per_yr$Lat)[2]

df <- data.frame(colorscale, names_colorscale)
  df$names_colorscale <- as.numeric(df$names_colorscale)
  legend_ord <- levels(with(df, reorder(colorscale, names_colorscale)))
  
DF <- ggplot(Per_yr) +
    geom_sf(data = borders, fill= "white")+
    geom_tile(aes(x=Lon, y=Lat, fill= as.character(Total)))+
    geom_sf(data = borders,fill = NA, colour = "dark green", size=0.2)+
    coord_sf(xlim = c(xmin1, xmax1), ylim = c(ymin1, ymax1))+
    scale_fill_manual(values = legend_ord)+
    scale_x_longitude(ticks = 2) +
    scale_y_latitude(ticks = 2)  
print(DF)

However I couldn't stop ggplot from alphabeticising.

Has anyone encountered a similar problem with a means to solve it?

P.S. Also after the update R Studio (running on Windows 11) keeps on showing my plots in an external pop-up window instead of the Plots pane on the lower right hand corner. If anyone of you know why it's happening (nothing in here is relevant, or works for me) and how I can fix it, I would greatly appreciate a way back to my old way of doing things :)

  • I'm 100% the issue is not related to updating R but might be related to a change in ggplot2. But in general the legend order is determined by the order of the variable mapped on `fill`. And as you convert to a character you get an alphabetical order. Instead try with `fill = factor(Total)` which as long as `Total` is numeric will preserve the numerical order. – stefan Sep 01 '23 at 05:52
  • Learn to change the ordering of the levels attribute of a factor. – IRTFM Sep 01 '23 at 06:44
  • Stefan, thank you, I indeed tried factoring (was one of my many different attempts to get it to work, but to no avail. @Sarah's suggestion below works for me though! Thanks all the same. – Bikem Ekberzade Sep 01 '23 at 12:37

1 Answers1

2

This is mentioned in the ggplot2 News:

"scale_manual() no longer displays extra legend keys, or changes their order, when a named values argument has more items than the data. To display all values on the legend instead, use scale_manual(values = vals, limits = names(vals)). (@teunbrand, @banfai, #4511, #4534)"

In line with this it works like this:

colour_scale <- c("0" = "light grey", "1" = "#fcba03", "2"= "#e8940c", "3"="#DB6C05", "4"= "#e8550c", "5" = "#ad1320", "6" = "dark red",
              "7"= "#F87F65", "8"="#f772b0", "9"="#e02b73", "10" = "#611975", "11"="#8d49cc", "12" = "#b595e6",
              "13"= "#122da6", "14" = "blue", "15"="steel blue", "16" = "#609E90",  "17" =  "#0cb8e8", "18" = "#b7eb34", "19"="#90eb10",
              "20"= "#89dc69", "21"="#57c27e", "22" = "#b7c50e", "23"= "#799c11",  "24"= "#207852", "25"="#134d19")

DF <- ggplot(Per_yr) +
  # geom_sf(data = borders, fill= "white")+
  geom_tile(aes(x=Lon, y=Lat, fill= as.character(Total)))+
  # geom_sf(data = borders,fill = NA, colour = "dark green", size=0.2)+
  coord_sf(xlim = c(xmin1, xmax1), ylim = c(ymin1, ymax1))+
  scale_fill_manual(values = colour_scale,
                    limits =  names(colour_scale))
  # scale_x_longitude(ticks = 2) +
  # scale_y_latitude(ticks = 2) 
print(DF)

As a side note when asking a question please make sure your question is minimal and reproducible, for example in your question the borders were not needed to get the question across so better not to include things as they required an extra package, and complicate things unnecessarily. In addition, the library for your scale functions (scale_x_longitude) was not stated, all libraries required to run your code should be called explicitly or people might just give up on answering.

Sarah
  • 3,022
  • 1
  • 19
  • 40
  • Thank you Sarah, this is indeed what I needed. What is still curious though is that my original code was working up until a few hours prior to this post, and it just stopped working after I undertook a mandatory update on R version, to make a package work.. Apologies on the long code, I'm new here, and still learning what is necessary and what is superfluous. – Bikem Ekberzade Sep 01 '23 at 12:34