2

I have a dataset containing longitude, latitude and a value column showing humidity, about 300 rows in length. Each point shows the humidity for a different location. I would like to plot all of them on a map and colour them according to their value (such as in gradient colours) and add a legend. It is a bit similar to the question here, but I can't get it to work. The code is basically there but only the colouring and displaying it properly in a legend does not really work. The points represent a line in Africa and the humidity values have been originally extracted from a raster dataset and they contain several digits. I created some sample data to illustrate where I am stuck.

library("maps")
library("raster")

# create sample data
lon <- seq(from=35.6, to=43.2, by=0.2)
lat <- seq(from=10.5, to=22.2, by=0.2)
humidity <- runif(59, min=9.6, max=13.5)
data <- data.frame(lon,lat, humidity)

colfunc<-colorRampPalette(c("dodgerblue2","khaki","orangered")) # create colours
map('world', xlim = c(20, 80), ylim = c(5, 30), lwd=0.5, col = "grey95", fill = T, interior = FALSE)
title("specific humidity along line")
map.axes()
points(data$lon, data$lat, cex=.5, pch=19, col=colfunc(100))
legend("topleft",title="q (g/kg)",legend=c(11,11.5,12,12.5,13),col =colfunc(100), pch=20)

The resulting plot looks like this: enter image description here Something is clearly wrong with the legend, I would like to have a few points shown in the legend with the corresponding colour and value or even use a nice colourbar. I am not sure why the colour in the legend is just blue. I also suspect that the line of points is not coloured according to their actual value and just displaying the whole colour gradient. Thanks for any suggestions! UPDATE with code from Alex:

n <- 10

colfunc<-colorRampPalette(c("dodgerblue2","khaki","orangered")) # create colours
mycol <- function(x, myrange, n=10) round( 1+(x-myrange[1])/diff(myrange) * (n-1))
map('world', xlim = c(20, 80), ylim = c(5, 30), lwd=0.5, col = "grey95", fill = T, interior = FALSE)
title("specific humidity along line")
map.axes()
points(data$lon, data$lat, cex=.5, pch=19, col=colfunc(n)[mycol(humidity, range(humidity), n)])
mylist <- c(10,11,11.5,12,12.5,13)
legend("topleft",title="q (g/kg)",legend=mylist,col = colfunc(n)[mycol(mylist,range(humidity), n)], pch=20)

That generates this plot: enter image description here Points are overlapping and it is hard to see the overall values of the points, is there any way to colour the points according to a defined range using the colourramp? Such as "red" for values 10 to 11, "green" for 11 to 12 and so on?

Dom Jack
  • 53
  • 3
  • 9
  • Your code should generate some example data. I do not want to download a file, and in the future it will be gone, making the Q and A much less useful. – Robert Hijmans Feb 09 '18 at 07:07
  • You are right, I just changed it accordingly and added sample data. Thanks! – Dom Jack Feb 09 '18 at 07:46

2 Answers2

5

You may have mixed up a few things. In you code, you are plotting points with a colour that is only a result of the order of the points (first point gets first colour in the list etc). The colour doesn't depend on the value.

Now in a colour gradient for humidity values in the full range 0:100 you will, frankly, not see any difference between values 11 and 13. You need a lot more contrast. So you should first do

mycol <- function(x, myrange, n=100) round( 1+(x-myrange[1])/diff(myrange) * (n-1))

now mycol(x, range(humidity), n) will return an integer that is 1 for the minimum value and n for the maximum.

n=100
points(data$lon, data$lat, cex=.5, pch=19, col=colfunc(n)[mycol(humidity, range(humidity), n)])

mylist <- c(11,11.5,12,12.5,13)
legend("topleft",title="q (g/kg)",legend=mylist,col = colfunc(n)[mycol(mylist,range(humidity), n)], pch=20)
Alex Deckmyn
  • 1,017
  • 6
  • 11
  • Many thanks for your help Alex. I tried using your code and it works perfectly! The humidity values do not represent relative humidity in range from 0 to 100 (%) but specific humidity, therefore I change n=100 to n=10, but I am unsure if that value makes sense, as the specific humidity values are in a range of about 10 to 13.2 g/kg? Unfortunately, the coloured points really cover each other, is there a way I could assign a specific colour to the range 10 to 11, 11 to 12 and so on? In that case the line would look smoother on the map. – Dom Jack Feb 12 '18 at 05:20
  • Any value of n makes as much sense as another, as it is just the number of different colours in your palette. For "pretty" intervals, you can use the same mycol function but set a different range e.g. c(10,14) with n=4. – Alex Deckmyn Feb 13 '18 at 01:09
1

you can seq the legend

library("maps")
library("raster")


n <- 4 # number in legend
# create sample data
lon <- seq(from=35.6, to=43.2, by=0.2)
lat <- seq(from=10.5, to=22.2, by=0.2)
humidity <- runif(39, min=9.6, max=20)
data <- data.frame(lon,lat[1:39], humidity)

    colfunc<-colorRampPalette(c("dodgerblue2","khaki","orangered")) # create colours
    map('world', xlim = c(20, 80), ylim = c(5, 30), lwd=0.5, col = "grey95", fill = T, interior = FALSE)
title("specific humidity along line")
map.axes()
points(data$lon, data$lat, cex=.5,pch=18, col=colfunc(nrow(data)))
legend("topleft",title="q (g/kg)",legend=round(seq(min(humidity),max(humidity),length.out = n),0),col =colfunc(n), pch=20) 
s.brunel
  • 1,003
  • 10
  • 24
  • Thanks a lot for your example code, it looks straightforward and works fine. However, as Alex pointed out, the colours do not represent the actual humidity values. – Dom Jack Feb 12 '18 at 05:00