How to create a KML file using R - r

I have written a R script to get some map point data (Latitude and Longitude values). I am able to plot them in R and visualize them. But now I want to generate a KML file from this data and view using Google Earth. So that I can share it with colleagues and they can see it on Google Earth too.
What is the best method / package to do this ?

Check the writeOGR function in the rgdal package. Here is a simple example:
library("sp")
library("rgdal")
data(meuse)
coordinates(meuse) <- c("x", "y")
proj4string(meuse) <- CRS("+init=epsg:28992")
meuse_ll <- spTransform(meuse, CRS("+proj=longlat +datum=WGS84"))
writeOGR(meuse_ll["zinc"], "meuse.kml", layer="zinc", driver="KML")
The objects exported are SpatialPointsDataFrame, SpatialLinesDataFrame, or SpatialPolygonsDataFrame objects as defined in the sp package.
R> class(meuse)
[1] "SpatialPointsDataFrame"
attr(,"package")
[1] "sp"
For writing with the KML driver, note that the geometries should be in geographical coordinates with datum WGS84.

I think is worth mentioning the plotKML package as well.
Edit 2022-05-16: Seems that plotKML is no longer on CRAN, but you can use an older package version from the CRAN archive. See Installing a Package Removed from CRAN.
However, for easy sharing among colleagues I found interesting the mapview package based on leaflet package. One can save a map as HTML document with various options for a background map; no need of Google Earth and the HTML map will run on your browser.
Some examples:
library(sp)
library(rgdal)
library(raster)
library(plotKML)
library(mapview)
# A SpatialPointsDataFrame example
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <- CRS("+init=epsg:28992") # CRS Amersfoort (Netherlands)
# make a KML file from SpatialPointsDataFrame object
# will get a warning like "Reprojecting to +proj=longlat +datum=WGS84 ..."
# as it is expected to work with geographical coordinates with datum=WGS84,
# but seems that it takes care of the reprojecting.
plotKML::kml(meuse,
file.name = "meuse_cadium.kml",
points_names = meuse$cadmium,
colour = "#FF0000",
alpha = 0.6,
size = 1,
shape = "http://maps.google.com/mapfiles/kml/pal2/icon18.png")
# Or, an easy to make interactive map with mapView()
mapView(meuse)
# A RasterLayer example
data(meuse.grid)
gridded(meuse.grid) <- ~x+y
proj4string(meuse.grid) <- CRS("+init=epsg:28992")
dist_rst <- raster(meuse.grid["dist"])
# make a KML file from RasterLayer object
plotKML::kml(dist_rst,
file.name = "dist_rst.kml",
colour_scale = SAGA_pal[[1]])
# Or, easy to make interactive map with mapView() - display raster and add the points
mapView(dist_rst, legend=TRUE) + meuse
# However, note that for bigger raster datasets mapView() might reduce from resolution
More examples with plotKML here.
For mapview, an intro can be found here.

If you're willing to step outside R, there is a free program called DNRGarmin can take a comma separated file as a .txt and convert it to .kml for import into google earth.
You can find it here:
http://www.dnr.state.mn.us/mis/gis/tools/arcview/extensions/DNRGarmin/DNRGarmin.html
so in R:
my.geo.data <- all.my.data[ c("unique.id", "lats", "longs")]
write.csv( my.geo.data, file = "myGeoData.txt")
open DNRGarmin,
File -> Load From -> File -> myGeoData.txt Then,
File -> Save to -> File -> myGeoData.kml
#rcs's advice re: WGS84 applies for this answer too.
Good luck

If you/your collegues know QGIS, this is a very good way to display data in Google Earth. QGIS has the feature of showing Google Earth as a base map and then you can open your spatial data and it will be displayed on the base map. Of course it requires your data to be correctly projected as rcs says.
Here you need to export your points as a shape file using the maptools package and Spatial Points package:
library(maptools)
library(sp)
## define projection
myProjection <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
## your points in format dataframe
coordinates.df <- as.data.frame(MyCoordinates)
## the number of points you have as dataframe
number <- as.data.frame(NumberOfPoints)
## convert points to Spatial Points Dataframe
myPoints.spdf <- SpatialPointsDataFrame(coordinates.df, number, proj4string = CRS(myProjection))
## save shapefile
writeSpatialShape(myPoints.spdf, "MyPointsName")
Your points can now be opened in QGIS and be displayed in Google Earth. In QGIS your data can also easily be saved as kmz file if necessary.

Related

Corner position and centre of pixel in NetCDF data in R

I am having trouble trying to open NetCDF data in R. Basically, my main problem is about the centre of the pixel, which I think in my case is not the left-bottom corner but centre (or even right-upper corner, not sure). Take a look at this raster with a correctly projected administrative border:
----------------------------------------
I use this code:
To open the file:
wd <- ("~/Desktop/Regionalitzacio")
RCP85_TN_MAM<- nc_open(paste0(wd,"/rcp8.5_nc/MRE+ESTADISTICS-RCP85-sim1-TN-MAM-20212050.nc"))
To create the array:
RCP85_TN_MAM <- ncvar_get(RCP85_TN_MAM, "TMIN_rg")
Transforming it into raster and exporting it:
CRS <- CRS("+proj=longlat +ellps=GRS80 +no_defs")
r <- raster(t(RCP85_TN_MAM), xmn=min(lon), xmx=max(lon), ymn=min(lat), ymx=max(lat), crs=CRS) #ed50geografic
r <- flip(r, direction='y')
writeRaster(r, "RCP85_TN_MAM", "GTiff", overwrite=TRUE)
I made it once in ARCMAP because the software allows you to select wether your cordinates are in the bottom-left or anywhere else, but I didn't manage to find such an option in R.
Do you know if it's possible to give R where exactly your cordinates fit?
To open ncdf files with raster data in R, without having to worry about georeferencing, you can do
wd <- "."
setwd(wd)
library(terra)
RCP85_TN_MAM <- rast("/rcp8.5_nc/MRE+ESTADISTICS-RCP85-sim1-TN-MAM-20212050.nc")
Or
library(raster)
RCP85_TN_MAM <- brick("/rcp8.5_nc/MRE+ESTADISTICS-RCP85-sim1-TN-MAM-20212050.nc"))

Failing to assign projection to sp object SpatialPointsDataFrame

I have a SpatialPointsDataFrame called johnny, created from a vanilla dataframe by assigning coordinates. These coordinates are in coordinate system EPSG 4326 (the standard GPS geographic coordinate system), but johnny does not know that. So ,I am trying to assign EPSG 4326 to johnny, essentially as in this earlier question data projection in R using package SP . I, too, am using sp. My ultimate goal is to project johnny to projected_johnny. However, I can't seem to assign the existing projection correctly first. Who sees my mistake?
library(sp)
x <- seq(80,90,by=1)
y <- seq(40,50,by=1)
value <- seq(10,20,by=1)
johnny <- data.frame(cbind(x,y,value))
coordinates(johnny) <- ~x+y
class(johnny)
[1] "SpatialPointsDataFrame"
attr(,"package")
[1] "sp"
proj4string(johnny) <- CRS("+init=epsg:4326")
Error in if (is.na(get("has_proj_def.dat", envir = .RGDAL_CACHE))) { :
argument is of length zero
I have considered and rejected the following possible solutions after trying them out:
Adding library rdgal directly
using CRS("+proj=longlat +datum=WGS84") instead of CRS("+init=epsg:4326")
I am using R 3.6.0 and sp 1.3-1. The rgdal version loaded via sp is 1.5-15. Any ideas are welcome. This should be such a simple action...
I looked over your code and guessed what you are probably trying to accomplish. But the way you are going about things is more different than it needs to be. There is a simple way to accomplished this. By far, the easiest way to accomplish this is by using those tools found in the R, sf package. Know that the sf package is a newer package than the sp package. And the sf package provides easy to use tools for accomplishing these tasks.
The code below is somewhat different from your code. A two column matrix was used instead of your three column data frame.
The simple feature geometry points were created from the matrix. Then the simple feature column object was created from the geometry points. Then the plot was created.
Code:
# Create matrix
x <- seq(80,90,by=1)
y <- seq(40,50,by=1)
# value <- seq(10,20,by=1)
#johnny <- data.frame(cbind(x,y))
jm <- matrix(data = c(x,y), nrow = 11, ncol = 2)
# coordinates(johnny) <- ~x+y
# class(johnny)
# johnny
Create sf multipoint geometry:
jm.sfg <- st_multipoint(jm)
jm.sfg
Create sf column object:
jm.sfc <- st_sfc(jm.sfg, crs = 4326)
jm.sfc
Plot
plot(jm.sfc, axes = TRUE)
The plot can be viewed from link below.

Shapefiles do not overlay raster layer in R

I have hundreds of shapefiles without a coordinate reference system. My goal is the overlay the spatial polygons over the WorldClim raster layer. I used this approach before without any problems. However, this time the coordinates from my shapefiles are strange for me. Each coordinate for bounding box and coords within polygons is composed of 8 digit numbers without comma or dot to separate de decimals.
This is the bounding box from one of the shapes:
SHP bbox: xmin:-17367529, xmax:17367529, ymin:-5997367 and ymax:7052489
which are clearly different from the bounding box of the WorldClim raster layer.
WorldClim bbox: xmin=-180,xmax=180,ymin=-60 and ymax=90
When I tried to overlay the shapefile over the raster layer using plot command nothing happens.
plot(shapefile, add=T)
I understood that this is a projection problem. Then I tried to assign the same coordinate system of the WorldClim raster layer in the shapefile using the CRS function. However, the result remains the same (i.e. the shapefiles do not over the raster). In the sequence, I tried to use the spTransform function from the rgdal package to reproject the shapefile coordinates. However, because shapefile does not have any reference system the function does not work and I do not know how to reproject the shapefile in order to match with the raster layer. I've been researching for a few days about how to deal with this problem and I believe that the absence of a reference system is a key point to the problem. However, I'm failing to overcome this problem and I would like to know if someone could help how to deal with this situation.
You need to define the projection of shape files first using proj4string(meuse) or crs(shapefile)<-crs string then you can use spTransform:
library(rgdal)
data(meuse)
coordinates(meuse) <- c("x", "y")
Here you have the spatial data with x and y but you do not have the crs yet! So if you use spTransform it will fail.
summary(meuse) #proj4string : [NA] so below line fails!
meuse.utm <- spTransform(meuse, CRS("+proj=utm +zone=32 +datum=WGS84"))
# Error in spTransform(xSP, CRSobj, ...) :
# No transformation possible from NA reference system
To get around this, as mentioned above, you first need to define the projection as below:
proj4string(meuse) <- CRS(paste("+init=epsg:28992",
"+towgs84=565.237,50.0087,465.658,-0.406857,0.350733,-1.87035,4.0812"))
summary(meuse) #proj4string : epsg:28992... and then you may use spTransform
and then:
meuse.utm <- spTransform(meuse, CRS("+proj=utm +zone=32 +datum=WGS84"))

Plotting spatial data when two spatial objects have different CRS

I have a spatial polygon object and a spatial points object. The latter was created from xy latlong data vectors (called latitude and longitude, respectively) in a dataframe, while the former was simply read into R directly using rgdal. My code is as follows:
boros <- readOGR(dsn = ".", "nybb")
rats <- read.csv("nycrats_missing_latlong_removed_4.2.14.csv", header = TRUE)
coordinates(rats) <- ~longitude + latitude
At this point neither spatial object is projected. If I project these objects as follows:
proj4string(boros) <- CRS("+proj=lcc")
proj4string(rats) <- CRS("+proj=lcc")
Both objects are now projected, and both will successfully map with the plot() function as follows:
plot(boros)
plot(rats)
However when I try to plot them together:
plot(boros)
plot(rats, add = TRUE)
I get the first plot only, without the rats object superimposed over boros. However, and this is the big problem, I get NO error message, so I have been unable to determine where the disconnection is between these two spatial objects being able to speak to each other. Both commands run smoothly without error or warning, yet I am left with just the single plot. And when I check the projections of each object with proj4string() I get the same projection returned for each object.
I have now spent many, many hours over several days trying various ways of creating two spatial objects whose CRS and projections match such that they can be mapped together using plot(). Incidentally, one approach I took was to create a shapefile in ArcGIS for the rats object, which worked fine to create the file. But I am still left with the same inability of the two spatial objects to work together in R. I have tried many different projections for both objects, spTransform on both objects, nothing seems to work.
Any help would be most appreciated. I have also included a dropbox link with the 2 data files I have described above:
https://www.dropbox.com/sh/x0urdo6guprnw8y/tQdfzSZ384
So, as some of the comments point out, the problem is that your data and your maps have different projections.
It looks like your map comes from the NYC Department of City Planning. The shapefile is definitely not in WGS84 (longlat), but the CRS is not included in the file (which is very disappointing by the way...). Nevertheless, there is a metadata file which indicates that the shapefile is projected as EPSG 2263.
In order to make use of this in R we need a projection string. The idiomatic way to get this in R is:
library(rgdal)
EPSG <- make_EPSG()
NY <- with(EPSG,EPSG[grepl("New York",note) & code==2263,]$prj4)
NY
# [1] "+proj=lcc +lat_1=41.03333333333333 +lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 +x_0=300000.0000000001 +y_0=0 +datum=NAD83 +units=us-ft +no_defs"
Now we can either take your map and reproject that into WGS84, or take your data and reproject that into the map CRS.
setwd("< directory with all your files >")
data <- read.csv("nycrats_missing_latlong_removed_4.2.14.csv")
# First approach: reproject map into long-lat
wgs.84 <- "+proj=longlat +datum=WGS84"
map <- readOGR(dsn=".",layer="nybb",p4s=NY)
map.wgs84 <- spTransform(map,CRS(wgs.84))
map.wgs84.df <- fortify(map.wgs84)
library(ggplot2)
ggplot(map.wgs84.df, aes(x=long,y=lat,group=group))+
geom_path()+
geom_point(data=data, aes(x=longitude,y=latitude, group=NULL),
colour="red", alpha=0.2, size=1)+
ggtitle("Projection: WGS84 longlat")+
coord_fixed()
# Second approach: reproject data
map.df <- fortify(map)
rats <- SpatialPoints(data[,c("longitude","latitude")],proj4string=CRS(wgs.84))
rats <- spTransform(rats,CRS(NY))
rats.df <- data.frame(coordinates(rats))
ggplot(map.df, aes(x=long,y=lat,group=group))+
geom_path()+
geom_point(data=rats.df, aes(x=longitude,y=latitude, group=NULL),
colour="red", alpha=0.2, size=1)+
ggtitle("Projection: NAD83.2263")+
coord_fixed()
No rats in Central Park?

How to write new shapefiles from exisiting GPS coordinates in R?

I am a novice with R maps and I would like to graphically display plant species distributions as polygons on a map. I have a csv file of UTM coordinates. I am using the maps and maptools programs in R and I have been able to read in existing ESRI shapefiles. The discussion posts that I have seen all seem to deal with reading in existing shapefiles and editing them somewhat and "rewriting" them back out. Is there a simple way to convert my csv file into a shapefile for mapping purposes? Thank you for your help, Eric
You should have more info about your coordinate reference system. And I'm not sure about what you mean with 'polygon' : i think that .csv can only contain coordinates points.
Here is an exemple of workflow : create a simple data.frame; set coordinates ; write shapefile ; read shapefile back; and plot simple map. Hope it helps. Instead of creating a data.frame, you could juste import your .csv.
# Load libraries
library(sp)
library(rgdal)
# set CRS . For epsg code, see http://spatialreference.org/
projTest<-CRS("+init=epsg:28992")
# create a temp dir for shapefiles
trashMap<-tempdir()
# create dumb data:
occData<-data.frame(x=c(12,13,14,20),y=c(0,1,4,9),obs=c("a","b","c","d"))
# set x and y as coordinates
coordinates(occData)<-c('x','y')
# assign CRS
proj4string(occData)<-projTest
# write simple shapefile in trashMap dir
writeOGR(occData, trashMap, layer='testLayer', driver="ESRI Shapefile")
# get list of Layers
layers<-ogrListLayers(trashMap)
# read shapefile and selected layer
occData2<-readOGR(trashMap, layers)
# Modify data
occData2$newColumn<-c('no','stress','','dude')
occData2
# verify that is projected
is.projected(occData2)
# display projection type
proj4string(occData2)
# print maps before and after export in shapefile.
print(spplot(occData, auto.key=F, col.regions='black', scales=list(draw=T), pch=2, cex=1))
print(spplot(occData2, auto.key=F, col.regions='black', scales=list(draw=T), pch=2, cex=1))

Resources