Search code examples
rggplot2colorsrasterr-raster

Extracting colors from .tif in R


I'm trying to modify the colors within my .tif. I've uploaded a file here.

Reading it in and quickly looking at it seems like all the information is there.

library(dplyr);library(ggplot2)
library(raster)
pic <- raster::brick(x="SUB_IMG_8020 (1)_A_36x36.tif")
pic
class      : RasterBrick 
dimensions : 619, 1060, 656140, 3  (nrow, ncol, ncell, nlayers)
resolution : 1, 1  (x, y)
extent     : 0, 1060, 0, 619  (xmin, xmax, ymin, ymax)
crs        : NA 
source     : SUB_IMG_8020 (1)_A_36x36.tif 
names      : SUB_IMG_8020_.1._A_36x36.1, SUB_IMG_8020_.1._A_36x36.2,     SUB_IMG_8020_.1._A_36x36.3 
min values :                          0,                          0,                          0 
max values :                        255,                        255,                        255 

plotRGB(pic)

example plot using plot plotRGB

So far so good. Now I want to manually change colors and hence, I transform the object to a data.framein order to use ggplot2. However, somewhere along the way I'm loosing information. Does anyone have an idea how to solve this?

test_spdf <- as(pic, "SpatialPixelsDataFrame")
#extract colors
test_df <- as.data.frame(test_spdf) %>% 
   mutate(cols = rgb(SUB_IMG_8020_.1._A_36x36.1,   
                SUB_IMG_8020_.1._A_36x36.2, 
                SUB_IMG_8020_.1._A_36x36.3, 
                maxColorValue = 255)) %>%
   dplyr::select(x, y, cols) %>% arrange(x) %>%
   tibble::rowid_to_column("nr")


ggplot(test_df, aes(x=x, y=y)) +  
  geom_raster(aes(fill=cols))+
  theme_void()+
  theme(legend.position="none")+
  coord_fixed()

enter image description here

This works out as expected. But when specifying scale_fill_manual I'm getting a weird looking plot which suggests that something went wrong when extracting the colors:

 ggplot(test_df, aes(x=x, y=y)) +  
  geom_raster(aes(fill=cols))+
  scale_fill_manual(values=c(test_df$cols))+
  theme_void()+
  theme(legend.position="none")+
  coord_fixed()

enter image description here

How can I correctly access the colors which somehow seem to be present (output of plotRGB). Thank you!


Solution

  • This is a good place to use scale_fill_identity() instead of scale_fill_manual. Otherwise, the fill colors will be assigned in a different order than what you intended.

    ggplot(test_df, aes(x=x, y=y)) +  
      geom_raster(aes(fill=cols))+
      theme_void()+
      theme(legend.position="none")+
      scale_fill_identity() +     # SWEET SWEET COLOR ASSIGNMENT MAGIC
      coord_fixed()
    

    The reason your scale_fill_manual approach didn't work is that ggplot is first determining the list of values assigned to the fill aesthetic, and creating groups in alphabetical order. So hex code "#290000" [in the JPEG we can see here] defines the first group of points that will receive a fill color, "#320500" the second, and so on. When you use scale_fill_manual, ggplot is taking the vector of colors you provide and assigning them in turn to each of those groups. Giving it the full list of colors in the original order of your data frame will result in scrambled colors, since they're in different order (and length) than what scale_fill_manual is expecting. If you wanted to use scale_fill_manual here, you could first get the (alphabetically sorted) list of colors, and then provide that as your list of fill values.

    library(dplyr)
    test_df %>% 
      arrange(cols) %>%        # sort alphabetically
      distinct(cols) %>%       # drop dupes
      pull(cols) -> col_list   # extract column as vector and save to col_list
    
    ggplot(test_df, aes(x=x, y=y)) +  
      geom_raster(aes(fill=cols))+
      theme_void()+
      theme(legend.position="none")+
      scale_fill_manual(values=c(col_list))+
      coord_fixed()