From 7d893b23ca959a7cc3ce2d185284ab9e66cb6517 Mon Sep 17 00:00:00 2001 From: gistin Date: Sat, 9 Jul 2022 17:39:29 +0100 Subject: [PATCH] aoo and eoo analysis and polygons added --- R/analysis.R | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++ R/app.R | 87 ++++++++-------- R/projWiz.R | 217 +++++++++++++++++++++++++++++++++++++++ README.md | 2 +- app.R | 2 - 5 files changed, 545 insertions(+), 48 deletions(-) create mode 100644 R/analysis.R create mode 100644 R/projWiz.R diff --git a/R/analysis.R b/R/analysis.R new file mode 100644 index 0000000..108b471 --- /dev/null +++ b/R/analysis.R @@ -0,0 +1,285 @@ +#Contains the functions for analysis +#mostly ripped from rCAT2 + + + + +########################################################### +#calculates the EOO area +########################################################### +#' @title Extent of Occurrence (EOO) Area +#' @description +#' Calculates the Extent of Occurrence in km2 or returns a simple feature polygon from a set of points (x,y) +#' @author Justin Moat. J.Moat@kew.org +#' @param thepoints dataframe of points in metres i.e. c(x,y) +#' +#' @return float_value area of EOO polygon and sf polygon in geographic project +#' @note area returned is in x,y units, but negative as polygon is constructed anticlockwise +#' @examples +#' x <- runif (20,0,10) +#' y <- runif (20,0,10) +#' df <- data.frame(x,y) +#' eoo (df) +#' ####### +#' spoly <- eoo (df,TRUE) +#' plot(spoly) +#' @seealso \code{\link{ratingEoo}} for EOO Ratings +#' @export +#' @importFrom grDevices chull +#' @importFrom pracma polyarea +#' @import sf +#' @references +#' Bachman, S., Moat, J., Hill, A.W., de Torre, J., Scott, B., 2011. Supporting Red List threat assessments with GeoCAT: geospatial conservation assessment tool. Zookeys 126, 117–26. doi:10.3897/zookeys.150.2109 +#' +#' Joppa, L.N., Butchart, S.H.M., Hoffmann, M., Bachman, S.P., Akçakaya, H.R., Moat, J.F., Böhm, M., Holland, R.A., Newton, A., Polidoro, B., Hughes, A., 2016. Impact of alternative metrics on estimates of extent of occurrence for extinction risk assessment. Conserv. Biol. 30, 362–370. doi:10.1111/cobi.12591 +library(pracma) +library (sf) + +eoosh <- function(points) { + if (! "X" %in% colnames(points) | ! "Y" %in% colnames(points)) { + stop("Point coordinates must be supplied in columns named 'X' and 'Y'.") + } + + hull_idx <- chull(points) + hull <- points[hull_idx,] + + area <- polyarea(x=hull$X, y=hull$Y) + # hull is constructed backwards, so area is negative and in m^2 + area <- -1 * area / 1e6 + + #JMJMJM WORKING + p1 <- matrix(c(hull$X,hull$Y),ncol=2) + #close it + p1 <- rbind(p1,c(hull[1,]$X,hull[1,]$Y)) + p1 <- st_polygon(list(p1)) + #set projection + p1 <- st_sfc(p1, crs = attr(points,'crs')) + #to geographic + p1 <- st_transform(p1,4326) + + list(area = area,polysf = p1) + + #JMJMJM +} + + +########################################################### +#calculates the initial AOO, with simple grid 0,0 # +########################################################### +#' calculates a very simple AOO area from a set of points +#' @title Area of Occupancy (AOO), grid orgin 0,0 +#' @description +#' Calculates the number area the of occupied cells for (Area of Occupancy AOO) from a set of points (x,y), projected into metres, with origin 0,0. +#' Please cite: Moat, J., Bachman, S. P., Field, R., & Boyd, D. S. (2018). Refining area of occupancy to address the modifiable areal unit problem in ecology and conservation. Conservation biology, 32(6), 1278-1289. if using this algorithm: +#' @author Justin Moat. J.Moat@kew.org +#' @param thepoints set of points in metres i.e. c(x,y) +#' @param cellsize size of cell (length) in metres +#' @param returnV, switches to return different sets of results: \cr +#' S = Simple, returns just the AOO area in km2, (DEFAULT) \cr +#' E = Expended simple, returns the solution for the AOO as list of (area,number of cells, rotation (0 degrees), shift in x direction(0), shift in y direction(0)). This is used so as be compatiable with other AOO calculations. \cr +#' SF = returns a polygon simple feature for mapping and plotting in ggplot/plot or export to GIS format. +#' @return as returnV, default is area in km2 +#' @examples +#'library(ggplot2) +#'#Build and project some points +#'thepoints <- ptsSquare(19,0.1) +#'names(thepoints) <- c("lat","long") +#'thepoints <- simProjWiz(thepoints) +#'attr(thepoints,'crs') +#'cellsize = 2000 +#' +#'#return area in km2 +#'aoo (thepoints,cellsize) +#'#return list of parameters +#'aoo (thepoints,cellsize,returnV="E") +#'#return polygon for plotting +#'gridpoly <- aoo(thepoints,cellsize,returnV="SF") +#'ggplot(data=gridpoly) +#' + geom_sf(color="black",fill="red") +#' + geom_point(data=thepoints,aes(X,Y)) +#' @seealso \code{\link{ratingAoo}} for AOO Ratings from IUCN categories +#' @export +#' @references +#' Moat, J., Bachman, S. P., Field, R., & Boyd, D. S. (2018). Refining area of occupancy to address the modifiable areal unit problem in ecology and conservation. Conservation biology, 32(6), 1278-1289. +#' +#' Bachman, S., Moat, J., Hill, A.W., de Torre, J., Scott, B., (2011). Supporting Red List threat assessments with GeoCAT: geospatial conservation assessment tool. Zookeys 126, 117–26. doi:10.3897/zookeys.150.2109 + +aoosh <- function(thepoints, cellsize=2000, returnV="S"){ + bottomleftpoints <- unique(floor(thepoints/cellsize)) + + cellp <- data.frame( + x=(bottomleftpoints$X * cellsize), + y=(bottomleftpoints$Y * cellsize) + ) + + # if (returnV == "E") { + # return(list( + # area=nrow(cellp) * (cellsize^2)/1000000, + # nocells=nrow(cellp), + # rotation=0, + # xshift=0, + # yshift=0 + # )) + # } + + area <- (nrow(cellp) * (cellsize^2)/1000000) + p1 <- buildCells(cellp, cellsize, 0, 0, 0, attr(thepoints,'crs')) + p1 <- st_transform(p1,4326) + #print("AOO") + return (list(area = area, polysf=p1)) + # if (returnV == "SF") { + # buildCells(cellp, cellsize, 0, 0, 0, attr(thepoints,'crs')) + # } else { + # return(nrow(cellp) * (cellsize^2)/1000000) + # } +} + + +###############building blocks for polygon production###### +########################################################### +#builds polygons from points and rotation, shift in X and y +#returns polygons for ggplot2 and mapping +########################################################### +#' @title Build simple feature polygons from point data, rotation and shift in x and y direction +#' @description +#' Builds cell polygons (as simple features) from points and rotation, shift in X and y returns polygons for ggplot2 and mapping. +#' Generally used to plot data from AOO calculations. +#' @author Justin Moat. J.Moat@kew.org +#' @param thepoints set of points in metres i.e. c(x,y) +#' @param cellsize size of cell (length) in metres +#' @param rot rotation of the grid in radian +#' @param shiftx shift in the x direction in metres +#' @param shifty shift in the y direction in metres +#' @return Simple Feature of polygons +#' @examples +#'#Build and project some points +#'thepoints <- ptsSquare(19,0.1) +#'names(thepoints) <- c("lat","long") +#'thepoints <- simProjWiz(thepoints) +#'#Check projection information is attributed +#'attr(thepoints,'crs') +#'cellsize = 2000 +#'all <- aooFixedRotation(thepoints,cellsize,1296,"ALL") +#'worstgrid <- all[which.max(all$nofcells),] +#'worstpoly <- buildCellPolys_rxy(thepoints,cellsize,worstgrid$rotation,worstgrid$xshift,worstgrid$yshift) +#'ggplot(data=worstpoly) +#' + geom_sf(color="black",fill="red") +#' + geom_point(data=thepoints,aes(X,Y)) +#' +#' @export +#' @references +#' Moat, J., Bachman, S. P., Field, R., & Boyd, D. S. (2018). Refining area of occupancy to address the modifiable areal unit problem in ecology and conservation. Conservation biology, 32(6), 1278-1289. + +buildCellPolys_rxy<- function(thepoints,cellsize,rot,shiftx,shifty){ + #shift first + testps <- cbind(thepoints$X - shiftx,thepoints$Y - shifty) + #then rotate + rpoints <- rotateP(testps,rot) + testcps <- unique(floor(rpoints/cellsize))*cellsize + colnames(testcps)<-c("x","y") + buildCells(testcps,cellsize,-rot,shiftx,shifty,attr(thepoints,'crs')) + +} + + + + + +########################################################### +#Rotates a set of points # +########################################################### +#Note angle in radians and only needed between 0 and 2pi for 360's +#but if using with shift you really only need 0 and pi/2 +#' @title Rotates a set of points +#' @description +#' Rotates a set of point by an angle in radians. Used as part of the AOO rotation calculations. +#' +#' @author Justin Moat. J.Moat@kew.org +#' @param thepoints set of points in metres i.e. c(x,y) +#' @param angle in radians +#' @return dataframe of points +#' @examples +#'#Build and project some points +#'thepoints <- ptsSquare(200,0.1) +#'#rotate by 45 degrees +#'rpoints <- rotateP(thepoints,deg2rad(45)) +#'plot(rpoints,asp=1) +#' @export +#' @references +#' Moat, J., Bachman, S. P., Field, R., & Boyd, D. S. (2018). Refining area of occupancy to address the modifiable areal unit problem in ecology and conservation. Conservation biology, 32(6), 1278-1289. + +rotateP <- function(thepoints, angle){ + pointmatrix <- as.matrix(thepoints) + rotationmatrix <- matrix(c(cos(angle), -sin(angle), sin(angle), cos(angle)),byrow = TRUE, 2, 2) + pr <- pointmatrix %*% rotationmatrix + pdf <- as.data.frame(pr) + colnames(pdf) <- c("x","y") + return(pdf) +} + +########################################################### +#builds all corners for a square from the lower left corner, returns df id,x,y for use in ggplot +########################################################### +buildCellPolys <- function (llcorners,cellsize){ + mydf <- data.frame(id=integer(),x=double(),y=double()) + for (i in 1:nrow(llcorners)){ + mydf[nrow(mydf)+1,] <- c(i,llcorners[i,]$x,llcorners[i,]$y) + mydf[nrow(mydf)+1,] <- c(i,llcorners[i,]$x+cellsize,llcorners[i,]$y) + mydf[nrow(mydf)+1,] <- c(i,llcorners[i,]$x+cellsize,llcorners[i,]$y+cellsize) + mydf[nrow(mydf)+1,] <- c(i,llcorners[i,]$x,llcorners[i,]$y+cellsize) + mydf[nrow(mydf)+1,] <- c(i,llcorners[i,]$x,llcorners[i,]$y) + } + return(mydf) +} + +########################################################### +#builds all corners for a square from the lower left corner, +#rotation, shift in X and y +#returns polygons +########################################################### +#internal called from main scripts + +buildCells <- function (llcorners, cellsize, rot=0, shiftx=0, shifty=0, crs=""){ + #build cells + mincells <- buildCellPolys(as.data.frame(llcorners),cellsize) + #rotate these back to original point orientation + cells <- rotateP(mincells[, 2:3], rot) + #shift + cells$x <- cells$x + shiftx + cells$y <- cells$y + shifty + + cell_list <- split(cells, f=mincells$id) + poly_list <- lapply(cell_list, function(x) constructPolygon(x$x, x$y, crs)) + + do.call(c, poly_list) +} + + +#' Construct a polygon from vertices. +#' +#' Accepts an x and a y vector to define the vertices of +#' the polygon, to make it easier +constructPolygon <- function(x, y, crs){ + points <- cbind(x, y) + + is_closed <- all(points[1,] == points[nrow(points),]) + + if (! is_closed) { + points <- rbind(points, points[1,]) + } + + geom <- st_polygon(list(points)) + + # put geometry into an sfc so we can attach a crs + if (is.null(crs)) { + crs <- "" + } + + polygon <- st_sfc(geom, crs=crs) + + if (is.na(st_crs(polygon))) { + warning("No valid CRS provided so setting it to `NA`") + } + + polygon +} diff --git a/R/app.R b/R/app.R index b673118..2eaed7f 100644 --- a/R/app.R +++ b/R/app.R @@ -458,34 +458,15 @@ geocatApp <- function(...) { #output to analysis on/off switch calculateAnalyisis <- eventReactive(list(input$Analysis, input$gbif_onoff, input$csv_onoff), { - - if (input$Analysis) { - d <- values$analysis_data - if (!input$gbif_onoff) { - d <- dplyr::filter(d, source != "gbif") - } - - if (!input$csv_onoff) { - d <- dplyr::filter(d, source != "csv") - } - - if (nrow(d) == 0) { - return() - } - - d <- dplyr::select(d, -source) - - EOO <- red::eoo(d) - AOO <- red::aoo(d) - + if (input$Analysis) { str1 <- paste("Extent of occurrence (EOO): ", - format(round(as.numeric(EOO)), big.mark = ","), - "(km squared)") + format(round(as.numeric(values$eooarea)), big.mark = ","), + "km2") str2 <- paste("Area of occupancy (AOO): ", - format(round(as.numeric(AOO)), big.mark = ","), - "(km squared)") + format(round(as.numeric(values$aooarea)), big.mark = ","), + "km2") HTML(paste(str1, str2, sep = '
') ) } @@ -500,40 +481,56 @@ geocatApp <- function(...) { calculateAnalyisis() }) - # make a polygon from imported csv points - polyInput = shiny::reactive({ - df <- csvpointsInput() - - poly <- df %>% - dplyr::filter(if_all(c(longitude, latitude), ~!is.na(.))) %>% - dplyr::filter(longitude > -180, longitude < 180, - latitude > -90, latitude < 90) %>% - sf::st_as_sf(coords = c("longitude", "latitude"), crs = 4326) %>% - sf::st_combine() %>% - sf::st_convex_hull() - }) - - # proxy map to add polygon shiny::observeEvent(input$Analysis, { if (input$Analysis){ - - leaflet::leafletProxy("mymap",data = polyInput()) %>% - # add polygons input from csv + #analysis here + d <- values$analysis_data + if (!input$gbif_onoff) { + d <- dplyr::filter(d, source != "gbif") + } + if (!input$csv_onoff) { + d <- dplyr::filter(d, source != "csv") + } + if (nrow(d) == 0) { + return() + } + d <- dplyr::select(d, -source)#is this needed or is it the above needed, I think they are doing the same thing + #JMJJMJMJMJM + #project the data so we can work on it in a sensible space for areas and distance + projp <- simProjWiz(d) + EOO <- eoosh(projp) + AOO <- aoosh(projp) + values$eooarea <- EOO$area + values$aooarea <- AOO$area + #JMJMJMMJ + leaflet::leafletProxy("mymap",data = AOO$polysf) %>% leaflet::addPolygons( color = "#000000", stroke = T, - weight = 3, - fillOpacity = 0.4, + weight = 2, + fillOpacity = 0.3, fill = T, - fillColor = "#999999") + fillColor = "red", + group = "AOOpolys") + + leaflet::leafletProxy("mymap",data = EOO$polysf) %>% + leaflet::addPolygons( + color = "#000000", + stroke = T, + weight = 2, + fillOpacity = 0.2, + fill = T, + fillColor = "green") # TO DO - add AOO cells? } else { - leaflet::leafletProxy("mymap", data=polyInput()) %>% + + leaflet::leafletProxy("mymap") %>% # clear previous polygons leaflet::clearShapes() + } }) diff --git a/R/projWiz.R b/R/projWiz.R new file mode 100644 index 0000000..66ef27e --- /dev/null +++ b/R/projWiz.R @@ -0,0 +1,217 @@ +########################################################### +#Simple area Projection Wizard +########################################################### +#' @title Simple Projection Wizard +#' @description +#' Projects any set of latitude and longitude points to a "suitable" area projection, based on thieir "true centre of gravity". +#' Data is expected as lat long in decimal degrees and returned in metres. +#' Input data is checked to make sure it’s sensible before projection (i.e. lat and longs on the earth no null or NA values) +#' @author Justin Moat. J.Moat@kew.org +#' @note +#' Based around a simple continental projection, using two sets of projections \cr +#' equal area cylindrical = Cylindrical equal-area \cr +#' equal area azimuthal for polar (above 70) = Lambert azimuthal equal-area \cr +#' +#' NB these are not cartographically pleasing projections, they are just so we can get the data into something simple for areal and distance analysis. +#' See Šavric et al for a more cartographically pleasing projection engine \cr +#' Šavric, B., Jenny, B., Jenny, H., 2016. Projection Wizard – An Online Map Projection Selection Tool. Cartogr. J. 53, 1–9. doi:10.1080/00087041.2015.1131938 and https://projectionwizard.org/ +#' @param thepoints set of points as a dataframe with latitude and longitude +#' @param thecentre one point i.e. c(lat,long), if not specified this will be calculated from the center of gravity of all points +#' @param returnV switches to return either dataframe (x,y) or simple feature of points \cr +#' S = simple, returns as dataframe of x,y \cr +#' SF = simple feature of points +#' @return Defaults is a set of points in meters as a dataframe with projection details attributed (stored as crs to retrieve attr(myprojectedpoints,'crs')) +#' @examples +#'lat <- runif (200,-24,-12) +#'long <- runif (200,43,51) +#'ll <- data.frame(lat,long) +#'#let it choose the centre point from your set of points +#'pointsprojected <- simProjWiz(ll) +#'#using your own set of points +#'pointsprojected <- simProjWiz(ll,c(-18,47)) +#'#check projection returned +#'attr(pointsprojected,'crs') +#'#return a simple features +#'sf_points <- simProjWiz(ll,,"SF") +#'ppoints <- simProjWiz(ll,,"SF") +#' +#' @references +#' Šavric, B., Jenny, B., Jenny, H., 2016. Projection Wizard – An Online Map Projection Selection Tool. Cartogr. J. 53, 1–9. doi:10.1080/00087041.2015.1131938 +#' https://projectionwizard.org +#' +#' Snyder, J.P., 1987. Map projections: A working manual, Professional Paper. Washington, D.C. +#' @export +#' @import sf +#' @import rgdal +#' +#' + +library (sf) + +simProjWiz <- function(thepoints,thecentre,returnV="S"){ + #check dataframe is sensible + #llCheck(thepoints) + names(thepoints) <- c("long", "lat") + # + if (missing(thecentre)){ + thecentre <- trueCOGll(thepoints) + } + #setup and set projection to WGS84 + thepoints <- st_as_sf(thepoints, coords = c("long", "lat"), crs = 4326) + #depending on centre point, choose projection + if((thecentre[1] < 70) & (thecentre[1] > -70)){ + CRSstring <- paste("+proj=cea +lon_0=", thecentre[2], " +lat_ts=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs",sep = "") + } else { + CRSstring <- paste("+proj=laea +lat_0=", thecentre[1]," +lon_0=", thecentre[2], " +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs",sep = "") + } + + #reproject + xysp <- st_transform(thepoints, CRSstring) + + if(returnV=="SF"){return (xysp)} + else { + xy <- as.data.frame(st_coordinates(xysp)) + attr(xy,'crs') <- CRSstring + return(xy) + } +} + +###################################################################### +#calculates 'true' centre of gravity from a set of lat long points in decimal degrees # +#note z from mean of cartesian give some idea of weighted spread on the globe# +###################################################################### +#' @title True centre of gravity from a set of Lat longs +#' @description +#' Calculates the "true" centre of gravity (weighted) from a set of lat longs, using cartesian geometry. Used as part of the projection wizard. +#' @author Justin Moat. J.Moat@kew.org +#' @param thepoints set of points c(lat,long) +#' @return a point (lat,long) from centre +#' @examples +#'lat <- runif (200,-24,-12) +#'long <- runif (200,43,51) +#'ll <- data.frame(lat,long) +#'cp <- trueCOGll(ll) +#' @references Descartes, R., 1637. Discours de la methode. A Leyde, De l’imprimerie de I. Maire, Paris. +#' @export + + +trueCOGll <-function(thepoints){ + + llrad <- deg2rad(thepoints) #to radians + cartp <- ll2cart(llrad$lat,llrad$long) #to cartesian + mp <- data.frame(x=mean(cartp$x),y=mean(cartp$y),z=mean(cartp$z)) #central point + pmp <- pro2sph(mp$x,mp$y,mp$z) #projection to surface + pmprll <- cart2ll(pmp$x,pmp$y,pmp$z) #to ll in radians + pmpll <- rad2deg(pmprll) #to degrees + return(data.frame(lat=pmpll$latr,long=pmpll$longr)) +} + +###################################################################### +#calculates the Cartesian cordinates (x,y,z) from lat long in radians# +###################################################################### +#' @title Geographic coordinates to cartesian (x,y,z) +#' @description +#' Calculates the Cartesian coordinates (x,y,z) from lat long in radians. Used as part of the projection wizard. +#' @author Justin Moat. J.Moat@kew.org +#' @param latr latitude point in radians +#' @param longr longtitude point in radians +#' @return dataframe of x,y,z +#' @examples +#'lat <- runif (200,-24,-12) +#'long <- runif (200,43,51) +#'thepoints <- data.frame(lat,long) +#'llrad <- deg2rad(thepoints) +#'cartp <- ll2cart(llrad$lat,llrad$long) +#' @references Descartes, R., 1637. Discours de la methode. A Leyde, De l’imprimerie de I. Maire, Paris. +#' @export + +ll2cart <- function(latr,longr){ + x <- cos(latr) * cos(longr) + y <- cos(latr) * sin(longr) + z <- sin(latr) + return(data.frame(x,y,z)) +} + +###################################################################### +#calculates the lat long cordinates in radians from Cartesian (x,y,z)# +###################################################################### +#' @title Cartesian (x,y,z) to Geographic coordinates +#' @description +#' calculates the latitude and longitude cordinates in radians from Cartesian coordinates (x,y,z). Used as part of the projection wizard. +#' @author Justin Moat. J.Moat@kew.org +#' @param x East to West coordinate in metres +#' @param y South to North coordinate in metres +#' @param z height coordinate in metres +#' @return dataframe of latitude,longtitude +#' @export + +cart2ll <-function (x,y,z){ + latr <- asin(z) + longr <- atan2(y,x) + return(data.frame(latr,longr)) +} + + +###################################################################### +#calculates Cartesian (x,y,z), projected from the centre of the sphere +#to the earth surface, returns cartesian (x,y,z) +#used to calculate "true" centre of set of lat longs +# http://stackoverflow.com/questions/9604132/how-to-project-a-point-on-to-a-sphere +###################################################################### +#' @title Cartesian coordinate projection +#' @description +#' Used as part of the projection wizard, calculates Cartesian (x,y,z), projected from the centre of the sphere to the earth surface, returns cartesian coordinates (x,y,z) +#' +#' @author Justin Moat. J.Moat@kew.org +#' @note +#' http://stackoverflow.com/questions/9604132/how-to-project-a-point-on-to-a-sphere +#' +#' @param x East to West coordinate in metres +#' @param y South to North coordinate in metres +#' @param z height coordinate in metres +#' @return x,y,z +#' @references +#' Descartes, R., 1637. Discours de la methode. A Leyde, De l’imprimerie de I. Maire, Paris. +#' @export + +pro2sph <- function (x,y,z){ + sc <- 1/sqrt(x^2 + y^2 + z^2) + x <- x * sc + y <- y * sc + z <- z * sc + return(data.frame(x,y,z)) +} + +###################################################################### +#radians to degrees and degrees to radians +###################################################################### +#' @title Radians to Degrees +#' @description +#' Calculates degrees from radians +#' @author Justin Moat. J.Moat@kew.org +#' @param rad number in radians +#' @return number +#' @examples +#' b <- 0.392699 +#' rad2deg(b) +#' @export + +rad2deg <- function(rad) {(rad * 180) / (pi)} + +###################################################################### +#radians to degrees and degrees to radians +###################################################################### +#' @title +#' Degrees to radians +#' @description +#' Calculates radians from degrees +#' @author Justin Moat. J.Moat@kew.org +#' @param deg number in degrees +#' @return number +#' @examples +#' a <- 30 +#' deg2rad(a) +#' @export + +deg2rad <- function(deg) {(deg * pi) / (180)} + diff --git a/README.md b/README.md index d078bbb..1031bdc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # geocat_staging staging version of geocat shiny -JM version for testing, hopefully this works!!! +JM version for testing, hopefully I haven't broken it! \ No newline at end of file diff --git a/app.R b/app.R index bed1b28..b4e9f4d 100644 --- a/app.R +++ b/app.R @@ -1,4 +1,2 @@ pkgload::load_all(".") geocatApp() - -