4

I would like to use the original colortable of a >>georeferenced raster image<< (tif-file) as coloured scale in a map plotted by ggplot/ggplot2.

Due to not finding an easier solution, I accessed the colortable-slot from the legend-attribute of the loaded raster image (object) raster1 like so:

raster1 <- raster(paste(workingDir, "/HUEK200_Durchlaessigkeit001_proj001.tif", sep="", collapse=""))
raster1.pts <- rasterToPoints(raster1)
raster1.df <- data.frame(raster1.pts)
colTab <- attr(raster1, "legend")@colortable

Ok, so far so good. Now I simply need to apply colortable as a colored scale to my existing plot:

(ggplot(data=raster1.df)
+ geom_tile(aes(x, y, fill=raster1.df[[3]]))
+ scale_fill_gradientn(values=1:length(colTab), colours=colTab, guide=FALSE)
+ coord_fixed(ratio=1)
)

Unfortunately, this does not work as expected. The resulting image does not show any colors beside white and the typical ggplot-grey which often appears when no custom values are defined. At the moment, I am a little clueless what is actually wrong here. I assumed that the underlying band values stored in raster1.df[[3]] are indices for the color table. This might be wrong. If it is wrong, then how are the band values connected with the colortable? And even if my assumption would be right: The parameters which I have given to scale_fill_gradientn() should still result in a more colorful plot, shouldn't they? I checked out what the unique values are:

sort(unique(raster1.df[[3]]))

This outputs:

 [1]  0  1  2  3  4  5  6  7  8  9 10 11 12

Apparently, not all of the 256 members of colortable are used which reminds me that the color does not always need to reflect the underlying band-data distribution (especially when including multiple bands).

I hope, my last thoughts didn't confuse you about the fact that the objective is quite straight forward.

Thank you for your help!

Florian R. Klein
  • 1,375
  • 2
  • 15
  • 32
  • Is the solution too obvious or too well hidden this time? :) – Florian R. Klein Oct 06 '13 at 08:06
  • Ok, now I know where the problem is situated: The `values`-parameter of the `scale_fill_gradientn`-function accepts only values between 0 and 1. I have to manually scale such a vector for all unique colors in `colortable`. I will post it as answer after finishing. However, there is still one problem remaining: The raster data values behind the raster tiles do not exactly reflext all used colors because the tif-image uses white as no value and black to outline areas. There must be a way to get the original color values for each raster pixel/tile. – Florian R. Klein Oct 06 '13 at 09:10
  • The discrepancy between the amount of colors and band-data values is more clear if a georeferenced image contains patterns instead of just simple color fills. Each unit could have lots of different colors, depending on its pattern and if it has a border, etcetera. – Florian R. Klein Oct 06 '13 at 09:29

1 Answers1

3

Ok, I have found an answer which might not apply to every georeferenced raster image out there, but maybe almost.

First, my assumption that the data values do bot exactly represent the color selection was wrong. There are 15 unique colors in the colortable of the spatial raster object. However, not all of them are used (14 and 15). Ok, now I know, I have to map my values to the corresponding colors ina way that scale_fill_gradientn understands. For this I am using my previous initial code snippet and define a new variable valTab which stores all unique data values of the given band:

raster1 <- raster(paste(workingDir, "/HUEK200_Durchlaessigkeit001_proj001.tif", sep="", collapse=""))
raster1.pts <- rasterToPoints(raster1)
raster1.df <- data.frame(raster1.pts)
raster1.img <- melt(raster1)
colTab <- attr(raster1, "legend")@colortable
names(colTab) <- 0:(length(colTab) - 1)
valTab <- sort(unique(raster1.df[[3]]))

Notice, how index names are defined for colTab - this will be important soon. With this, I am able to automatically relate all active colors with their respective value while plotting:

(ggplot(data=raster1.df)
+ geom_tile(aes(x, y, fill=raster1.df[[3]]))
+ scale_fill_gradientn(colours=colTab[as.character(valTab)])
+ coord_fixed(ratio=1)
)

Using valTab-members as references to the corresponding color-indices helps to always pick only the colors which are needed. I don't know if defining the values-paramter of scale_fill_gradientn() is necessary in some cases.

I am not sure if the raster images read by raster() always define their values starting from 0. If not, names(colTab) <- 0:(length(colTab) - 1) needs to be adjusted.

I hope, this helps somebody in the future. At least, I finally have a solution!

Florian R. Klein
  • 1,375
  • 2
  • 15
  • 32
  • You can access the colortable using function `colortable` from package `raster`. –  Oct 27 '15 at 04:57
  • @Florian R. Klein: I'm trying to reproduce this solution but I'm not really getting there. What are you achieving with `raster1.img <- melt(raster1)`? Are you using `melt()` of the package `reshape2`? And are you really trying to `melt` your rasterfile, I woud have expected using `melt(raster1.df)` – Ratnanil Oct 27 '15 at 09:55
  • Same question with slightly different data, the solution is here: http://stackoverflow.com/questions/33359284/r-plot-background-map-from-geotiff-with-ggplot2/33367160#33362471 – Ratnanil Oct 27 '15 at 11:57