Making a Choropleth in R without using a gradient - r

I'm pretty new to R and I am trying to map the distribution of an ant species in Argentina using the adm1 (or state) divisions.
I have downloaded data from the GADM website and I have a csv file that I've created that contains info saying whether the species is present or absent in each adm1.
Even though I don't have a gradient can I still make a choropleth? If not, what other types of maps could I use?
I've looked at several sites including Infomaps using R, How to make choropleths in R, and the Choropleth Map Challenge, which have been really helpful but they all have numeric data and I'm using a present(1) or absent(0) column. The different packages I've tried are sp(with RColorBrewer), ggplot2, rgeos, and maptools.
Here is the code I have so far:
library(sp)
library(RColorBrewer)
write.csv(atr, "atr_data.csv")
atr_data<-read.csv("atr_data.csv", header=TRUE)
spcode country_code adm1_code newcol
1 atr VEN VE.AR 0
2 atr PRY PY.CE 0
3 atr PAN PA.CL 0
4 atr PAN PA.CL 0
5 atr PAN PA.PN 0
6 atr PAN PA.PN 0
I'm in the process of making a column with the full adm1 names instead of the codes so that it will match up with the GADM file (so I haven't written the code to merge the data yet).
#to retrieve map for Argentina ARG
con <- url("http://gadm.org/data/rda/ARG_adm1.RData")
print(load(con))
close(con)
#to generate random colors on map
col = rainbow(length(levels(gadm$NAME_1)))
spplot(gadm, "NAME_1", col.regions=col, main="ARG Regions", colorkey = FALSE, lwd=.4,col="white")
#this piece of code is a mess
col_no <- as.factor(as.numeric(atr_data$newcol[order],
c(0,1)))
levels(col_no)<- c("0", "1")
gadm$col_no <- col_no
myPalette<-brewer.pal(3, "Purples")
spplot(gadm, "col_no", col=grey(.9),
col.regions=myPalette,
main="Distribution of Atratus in Argentina")
Any help would be greatly appreciated, thanks!

There's a couple of minor issues that come up in the example you've provided.
First, the data slot for spatial polygon dataframes can be accessed with gadm#data$col_no instead of gadm$col_no. Once you've finished filling out your presence/absence table, either by accessing the slot directly, or using spCbind in the maptools package allows you to add the presence/absence data to the spatial polygon data frame.
Second, if you have only 2 levels in your col_no factor, you will have to subset MyPalette to 2 colours since the Brewer palette will only work with a minimum of 3 levels.
library(sp)
library(RColorBrewer)
con <- url("http://gadm.org/data/rda/ARG_adm1.RData")
print(load(con))
close(con)
# Randomly assigning presence/absence data for display purposes only
gadm#data$col_no <- as.factor(rbinom(n = 24, size = 1, prob = 0.5))
myPalette <- brewer.pal(3, "Purples")
# col.regions is limited to 2 colors below with the middle color dropped.
spplot(gadm, zcol = "col_no", colorkey = TRUE, col.regions = myPalette[-2],
main="Distribution of Atratus in Argentina")

Related

Mapping my data to a Zip Code area map in R

My data is like this:
ZIPcode Cases longi lati
43613 1 -83.604452 41.704307
44140 1 -81.92148 41.48982
46052 1 -86.470531 40.051603
48009 22 -83.213883 42.544619
48017 6 -83.151815 42.535396
48021 7 -82.946167 42.463894
48025 19 -83.265758 42.523195
I want to get a map similar to this (if you can see it) in R. The outline should be zipcodes and the shading should be according to number of cases, darker as cases increase.
I'm very new to R. Tried a lot of code I found online but can't get what I want. Any help is appreciated. Can this be done in base SAS ?
Thank you!
enter image description here
Definetly you can do it in R, I put together a reprex (reproducible example) for you. Key points:
You need to load into R a .shp file (or .geojson, .gpkg, etc.). That is an actual file with the outline of your map. For ZIPCODES I found a R package, tigris, that does that for you, if not you'll need to load it by yourself.
For handling mapping objects (load, transform, .etc), sf package is your best friend.
For plotting, in this example I used cartography, but you can use several different package, as ggplot2 or tmap.
Last line is that, given your data (and if I didn't get the ZIPCODEs wrong), a map as the one you shown (choropleth map) maybe is not the best options. Have a look here to see other alternatives.
library(sf) #Overall handling of sf objects
library(cartography) #Plotting maps package
#1. Create your data
yourdata <- data.frame(ZCTA5CE10=c("43613", "44140", "46052",
"48009","48017", "48021","48025"),
Cases=c(1,1,1,22,6,7,19)
)
#2. Download a shapefile (shp,gpkg,geojson...)
library(tigris) #For downloading the zipcode map
options(tigris_use_cache = TRUE)
geo <- st_as_sf(zctas(cb = TRUE, starts_with = yourdata$ZCTA5CE10))
#Overall shape of USA states
states <- st_as_sf(states(cb=TRUE))
#For plotting, all the maps should have the same crs
states=st_transform(states,st_crs(geo))
#3. Now Merge your data
yourdata.sf=merge(geo,yourdata)
#4. Plotting
par(mar=c(1,1,1,1))
ghostLayer(yourdata.sf)
plot(st_geometry(states), add=TRUE)
choroLayer(yourdata.sf,
var="Cases",
add=TRUE,
border = NA,
legend.pos = "right",
legend.frame = TRUE)
layoutLayer(title = "Cases by ZIPCODE",
theme = "blue.pal",
scale = FALSE,
sources = "Source; your question on SO",
author = "by dieghernan, 2020"
)
Created on 2020-02-27 by the reprex package (v0.3.0)

Colorize the map of Russia depending on the variable in R

I have a map of Russia with regional subdivision
library(raster)
data <- getData('GADM', country='RUS', level=1)
http://www.gks.ru/bgd/regl/B16_14p/IssWWW.exe/Stg/d01/08-01.doc
The link is to a Word.doc with data (table) on crime rates for Russian regions. I can extract this data and use it in R. I want to take 2015 year and colorize regions on the map depending on the crime rate (also add a legend). How can I do this? The problem is that names of regions are sometimes different in the shape file (NL_NAME_1) and in the data from www.gks.ru.
I also have this code for graph that I need, except that here we have meaningless colors:
library(sp)
library(RColorBrewer)
data$region <- as.factor(iconv(as.character(data$NAME_1)))
spplot(data, "region", xlim=c(15,190), ylim=c(40,83),
col.regions=colorRampPalette(brewer.pal(12, "Set3"))(85), col = "white")
If I understand your question properly, you just need to add your data to the spatial object for making colors meaningful.
Note, please, that the data is a reserved word in R. So, it's better to modify a little your variable name:
geo_data <- getData('GADM', country = 'RUS', level = 1)
Let's emulate some data to demonstrate a visualization strategy:
set.seed(23)
geo_data#data["data_to_plot"] <- sample(1:100, length(geo_data#data$NAME_1))
Using a default GADM projection would cut the most eastern part of the country. A simple transformation helps to fit the whole area to a plot:
# fit Russian area inside the plot
geo_data_trsf <- spTransform(geo_data, CRS("+proj=longlat +lon_wrap=180"))
Draw the map selecting data_to_plot instead of region:
max_data_val <- max(geo_data_trsf#data$data_to_plot)
spplot(geo_data_trsf, zcol = "data_to_plot",
col.regions = colorRampPalette(brewer.pal(12, "Set3"))(max_data_val),
col = "white")
The plot limits are adjusted automatically for the transformed spatial data geo_data_trsf, making possible to omit xlim and ylim.
As for the problem with the names, I can't provide any ready-to-use solution. Obviously, the regions' names of NL_NAME_1 need some additional treatment to use them as labels. I think, it would be better to use NAME_1 as an identifier in your code to ensure that it'll be no troubles with encoding. The NL_NAME_1 column is perfectly suitable to set the correspondence between your Word-data and the data inside the spatial object geo_data.

Gradient colours in ggplot (relatively simple)

I have a dataframe which I have constructed by interpolating a series of origin destination points (they relate to a cycle share scheme that used to run in Seattle).
I've called the dataframe interpolated_flows:
line_id long lat seg_num count
1 1 -122.3170 47.61855 1 155
2 1 -122.3170 47.61911 2 155
3 1 -122.3170 47.61967 3 155
4 1 -122.3170 47.62023 4 155
5 1 -122.3169 47.62079 5 155
6 1 -122.3169 47.62135 6 155
What I would like to do (and I think is relatively simple if you know ggplot) is to plot these flows (lines) with the width of a line determined by the count and the gradient determined by the seg_num.
This is my attempt so far:
#Create variables to store relevant data for simplicity of code
X <- interpolated_flows$long
Y <- interpolated_flows$lat
sgn <- interpolated_flows$seg_num
ct <- interpolated_flows$count
#Create a map from flow data and include the bounded box as a base
g <- ggplot(interpolated_flows,aes(x=X, y=Y),group=interpolated_flows$line_id,color=sgn)
map <- ggmap(seattle_map,base_layer = g)
map <- map + geom_path(size=as.numeric(ct)/100,alpha=0.4)+
scale_alpha_continuous(range = c(0.03, 0.3))+coord_fixed(ratio=1.3)+
scale_colour_gradient(high="red",low="blue")
png(filename='Seattle_flows_gradient.png')
print(map)
dev.off()
And I end up with the image attached. I have spent a long time playing around with various parameters in the plotting part of the code but without success so would really appreciate if someone could point me in the right direction.
Edit:
base <- ggplot(interpolated_flows,aes(x=X, y=Y))
map <- ggmap(seattle_map,base_layer = g)
map <- map+geom_path(aes(color=seg_num,size=as.numeric(count)))+
scale_size_continuous(name="Journey Count",range=c(0.05,0.4))+
scale_color_gradient(name="Journey Path",high="white",low="blue",breaks=c(1,10), labels=c('Origin','Destination'))+
coord_fixed(ratio=1.3)+scale_x_continuous("", breaks=NULL)+
scale_y_continuous("", breaks=NULL)
png(filename='Seattle_flows_gradient.png')
print(map)
dev.off()
This is the plot I have now got to which looks like this. I have only two questions - 1) does anyone know a way to improve the resolution of the background map? I tried changing the zoom parameter in the get_map function but it didn't seem to help. 2) The lines I have plotted seem very 'white' heavy. It doesn't look to me like the gradient is evenly distributed. Anyone have any ideas why this would be and how to fix?
See if this suits you. I have create a new dataset so as to see diffencies. Once the data.frame is created you can use it as your first ggplot argument and reference columns by their names as Mako212 say.
long<-seq(-122,-123,length.out = 6)
lat<-seq(47,48,length.out = 6)
seg_num<-seq(1,6,1)
count<-seq(155,165,length.out = 6)
interpolated_flows<-data.frame(long,lat,seg_num,count,stringsAsFactors = false)
base_plot<-ggplot(interpolated_flows,aes(x=long, y=lat))
base_plot+
geom_path(aes(color=seg_num,size=as.numeric(count/100),alpha=lat))+
#notice that size, color and alpha are into aethetic
scale_size_continuous(name="Count")+
scale_alpha_continuous(name="Latitude",range = c(0.03, 0.3))+ #you won't need it if you don't want variable transparency
#just put the desired value into the aethteic
scale_color_gradient(name="Seg_num",high="red",low="blue")+
coord_fixed(ratio=1.3)
Hope it helps

Using a raster attribute from a multi-attribute raster for colour levels in a plot in R

I have a raster object with a large number of attributes, and I would like to plot the spatial data in R and colour code it by a certain attribute. I have not been able to work out how to use the information of a particular attribute to achieve this. So far I have successfully extracted the attribute of choice using factorValues(), but I cannot determine how to now incorporate this information into the plot() function. I tried using the ratify() and level() functions mentioned in the raster package documentation, but I don’t understand how the simplified online examples can be adapted for a raster with multiple attributes.
Any advice on how to achieve this would be greatly appreciated.
# read in shapefile
shp = readOGR(".", "grid")
#convert to raster
r = raster(extent(shp))
res(r) = c(1,0.5)
ra = rasterize(shp, r)
#crop raster to desired extent
rcrop = crop(ra, extent(-12, 2, 29, 51))
# extract attribute value of interest
f = factorValues(rcrop, 1:420, layer=1, att=17, append.names=FALSE)
# here there are 420 cells in the raster and I am interested in plotting values of attribute 17 of the raster (this is currently a numeric attribute, not a factor)
#extra code to set attribute as the level to use for plotting colours???
rcrop = ratify(rcrop)
rat = levels(rcrop)[[1]] #this just extras row IDs..not what I want
#…
### plot: I want to plot the grid using 7 colours (I would ideally like to specify the breaks myself)
require(RColorBrewer)
cols = brewer.pal(7,"YlGnBu")
#set breaks
brks = seq(min(minValue(rcrop)),max(maxValue(rcrop),7))
#plot
plot(rcrop, breaks=brks, col=cols, axis.arg=arg)
The following is pretty hacky (and may perform poorly for large rasters), but I'm not sure if there's a way to link col.regions to a specified attribute.
rasterVis::levelplot does a nice job of labelling colour ramps corresponding to factor rasters, and while it provides an att argument allowing you to specify which attribute you're interested in, this seems to only modify the labelling of the ramp. Raster cell values control how the colour ramp is mapped to the raster, so it seems to me that we need to modify the cell values themselves. Maybe #OscarPerpiñán will chime in here to prove me wrong :)
We can create a simple function to substitute the original cell values with whichever attribute we want:
switch_att <- function(r, att) {
r[] <- levels(r)[[1]][values(r), att]
r
}
Let's download and import a small example polygon dataset from Natural Earth:
library(rasterVis)
library(rgdal)
require(RColorBrewer)
download.file(file.path('http://www.naturalearthdata.com',
'http//www.naturalearthdata.com/download/110m/cultural',
'ne_110m_admin_0_countries.zip'),
f <- tempfile())
unzip(f, exdir=tempdir())
shp <- readOGR(tempdir(), 'ne_110m_admin_0_countries')
rasterize the vector data:
r <- rasterize(shp, raster(raster(extent(shp), res=c(1, 1))))
And create some plots with levelplot:
levelplot(switch_att(r, 'continent'), col.regions=brewer.pal(8, 'Set2')) +
layer(sp.polygons(shp, lwd=0.5))
levelplot(switch_att(r, 'economy'), par.settings=BuRdTheme) +
layer(sp.polygons(shp, lwd=0.5))
EDIT
With Oscar's update to rasterVis, the switch_att hack above is no longer necessary.
devtools::install_github('oscarperpinan/rastervis')
levelplot(r, att='continent', col.regions=brewer.pal(8, 'Set2')) +
layer(sp.polygons(shp, lwd=0.5))
will produce the same figure as the first one above.

Drawing line on ggmap plot between two countries using long/lat

I am a total newbie to R and I would like to draw a line (possibly weighted, e.g., by the number of trips made) between two countries. Currently, I use longitude and latitude for each capital to draw a line, but I would like to do it using the package ggmap. I was looking around, but did not find any solution so far. I would appreciate a quick help.
require(ggmap)
require (rworldmap)
all_content = readLines("ext_lt_intratrd_1_Data.csv")
skip_second = all_content[-2]
dat = read.csv(textConnection(skip_second), header = TRUE, stringsAsFactors =F)
dat[5,2]<- c("Germany") # using a data where the first line is
header, but second line must be skipped as it is EU 27
and not a single country
europe <- read.csv("eulonglat.csv", header = TRUE) # using world capitals to
generate points
myfulldata <- merge(dat, europe)
map <- get_map(location = 'Europe', zoom = 4)
mapPoints <- ggmap(map) + geom_point(aes(x = UNc_longitude, y = UNc_latitude, size
= log(myfulldata$Value)), data = myfulldata, col = "red", alpha= 0.5) # this can
be plotted
# i would continue with drawing line and i searched for references
# i found arrows(42.66,23.34,50.82,4.47) - which did not work
# i tried to look for a reference work more, but could not find
# instead i found it using with the package rworldmap the following
lines(c(4.47, 23.32), c(50.82, 42.66))
# this does not work on ggmap

Resources