Plot() and categorical maps: seems to be a bug.

27 views
Skip to first unread message

Steve Cumming

unread,
Apr 6, 2016, 11:46:01 AM4/6/16
to SpaDES Users
Here's something I am persistently having trouble with in Plot.

This code illustrates the creation of two maps, the first of which will have cell values in {0,1,2}

 sim$disturbanceMap<-raster(x,nrows=N, ncols=N,vals=0)
  setColors(sim$disturbanceMap) <- colorRampPalette(c("green","red"))(3)
  

while this map will have cell values in {0,1}

  sim$noCanGo<-raster(x,nrows=N, ncols=N,vals=0)
  setColors(sim$noCanGo) <- colorRampPalette(c("white","black"))(2)

Plot() however, produces either a solid green map, or a sold white map, respectively.

What is the appropriate way to define and plot maps having a small range in integer values?

Steve


Alex Chubaty

unread,
Apr 6, 2016, 12:14:10 PM4/6/16
to SpaDES Users
Steve, 

Can you please provide a minimal reproducible example?

Steve Cumming

unread,
Apr 6, 2016, 12:28:28 PM4/6/16
to SpaDES Users
OK:


N<-20
x<-raster::extent(c(0,N-1,0,N-1))
tstMap<-raster(x,nrows=N, ncols=N,vals=0)
setColors(tstMap) <- colorRampPalette(c("green","red"))(3)
tstMap[c(1,10,100)]<-1
tstMap[40:120]<-2
Plot(tstMap,new=TRUE)

Eliot McIntire

unread,
Apr 6, 2016, 12:32:23 PM4/6/16
to SpaDES Users
You haven't given it enough information... you are missing 2 things:
1. How many colors your want (the colorRampPalette interpolates, but so does setColors, so giving it on as an argument to colorRampPalette isn't enough 
2. What is your min and max on the legend. 

See bold:

N<-20
x<-raster::extent(c(0,N-1,0,N-1))
tstMap<-raster(x,nrows=N, ncols=N,vals=0)
setColors(tstMap, n=3) <- colorRampPalette(c("green","red"))(3)
tstMap[c(1,10,100)]<-1
tstMap[40:120]<-2
Plot(tstMap,new=TRUE, legendRange=0:2)

Eliot McIntire

unread,
Apr 6, 2016, 12:42:03 PM4/6/16
to SpaDES Users
You can actually remove function call to colorRampPalette, as this is what is done internally in setColors:
N<-20
x<-raster::extent(c(0,N-1,0,N-1)) 
tstMap<-raster(x,nrows=N, ncols=N,vals=0) 
setColors(tstMap, n=3) <- c("green","red")
tstMap[c(1,10,100)]<-1 
tstMap[40:120]<-2 
Plot(tstMap,new=TRUE, legendRange=0:2

Eliot

Steve Cumming

unread,
Apr 6, 2016, 1:57:20 PM4/6/16
to SpaDES Users
Thanks for this: I was working off ancient examples stolen from you, in which the colourRamp was used.

I would suggest that having to provide what is usually, in intention if not logically, the same information to setColors and to Plot 
is not ideal from a modularity perspective.

Can we define default behaviour for Plot that would use the parameter n provided to setColors and the range of values in the map to determine 
the legendRange?

Steve

Eliot McIntire

unread,
Apr 6, 2016, 3:21:29 PM4/6/16
to SpaDES Users
I agree with your point. I tried to do this in an earlier version of Plot, but I hit problems. 

As it turns out, there is no standard for the colorTable in rasters. I have been given rasters via .geoTiff, whose colortable (found inside a raster object with obj@legend@colortable) is much longer than the desired number of levels. The LandCoverClassification 2005 object is one such object. Its colorTable attribute is 255 long, but it only uses the first 40 colors. So, if we scale the legend to the length of the colorTable attribute, the legend would go from 1 to 255, not 1 to 40, which is the desired behaviour. 

(edit) I am currently looking at the LandCoverClassification 2005 object (can be downloaded to a temporary directory with this:

baseDir <- tempdir()
SpaDES::downloadModule("LccToBeaconsReclassify", baseDir)
SpaDES::downloadData("LccToBeaconsReclassify", baseDir) 
unzip(zipfile = file.path(baseDir, "LccToBeaconsReclassify", "data", "LandCoverOfCanada2005_V1_4.zip"),
      files = "LCC2005_V1_4a.tif",
      exdir = file.path(baseDir, "LccToBeaconsReclassify", "data"))
lcc05 <- raster(file.path(baseDir, "LccToBeaconsReclassify", "data", "LCC2005_V1_4a.tif"))
getColors(lcc05)
...
and it looks like #000000 is the trigger to "end" the legend. 

Is that universal? i.e., can we assume that a colortable is either the correct length (Steve's use case) or it the "first and last" colors are contained between the #000000 values of the colortable?


Steve Cumming

unread,
Apr 6, 2016, 3:25:23 PM4/6/16
to SpaDES Users
That's a very good question, re the coding for color tables

I have absolutely no idea. 

Some digging, or querying specialized fora might be in order, but I don't think it's a good use of your time at present.

sc

Alex Chubaty

unread,
Apr 6, 2016, 3:28:28 PM4/6/16
to SpaDES Users
The issue with your code is that you are setting the colours on a raster whose values are all zeros. Only after you have manually set the colours are you changing the values. Plot() uses the colours previously set by setColors() rather than forcing its own colours on the map.

Using you original code, but assigning colors after the values are set produces the expected result:

N <- 20
x
<-raster::extent(c(0, N-1, 0, N-1))
tstMap
<- raster(x, nrows = N, ncols = N, vals = 0)
tstMap
[c(1,10,100)] <- 1
tstMap
[40:120] <- 2
setColors
(tstMap) <- colorRampPalette(c("green", "red"))(3)
Plot(tstMap, new = TRUE)



Alex Chubaty

unread,
Apr 6, 2016, 3:30:14 PM4/6/16
to SpaDES Users
Note that this is only the case when you don't specify `n` in the `setColors()` call
Reply all
Reply to author
Forward
0 new messages