I am trying to do species distribution mapping in R for invasive oyster species (marine).
With the code that I am using, it will plot points only on land (ext= geographic.extent). I cannot find other "extent" options for example marine.extent or a way to do -geographic.extent so that it would be everything BUT the currently plotted area.
# Randomly sample points (same number as our observed points)
background <- randomPoints(mask = mask, # Provides resolution of sampling points
n = nrow(obs.data), # Number of random points
ext = geographic.extent, # Spatially restricts sampling
extf = 1.25) # Expands sampling a little bit
# Plot the base map
plot(wrld_simpl,
xlim = c(0, 30), #north and baltic sea
ylim = c(50, 70),
axes = TRUE,
col = "grey95",
main = "Presence and pseudo-absence points")
# Add the background points
points(background, col = "grey30", pch = 1, cex = 0.75)
geographic.extent is a variable that you supply. It is probably created in your own code, or else by a package you load. Can you edit your question and show what it is (print it)?
To only sample points from certain areas, use the mask argument (as you do). In your case all land areas should be NA and all marine areas should not be NA.
Related
I'm trying to fit Variance-Gamma distribution to empirical data of 1-minute logarithmic returns. In order to visualize the results I plotted together 2 histograms: empirical and theoretical.
(a is the vector of empirical data)
SP_hist <- hist(a,
col = "lightblue",
freq = FALSE,
breaks = seq(a, max(a), length.out = 141),
border = "white",
main = "",
xlab = "Value",
xlim = c(-0.001, 0.001))
hist(VG_sim_rescaled,
freq = FALSE,
breaks = seq(min(VG_sim_rescaled), max(VG_sim_rescaled), length.out = 141),
xlab = "Value",
main = "",
col = "orange",
add = TRUE)
(empirical histogram-blue, theoretical histogram-orange)
However, after having plotted 2 histograms together, I started wondering about 2 things:
In both histograms I stated, that freq = FALSE. Therefore, the y-axis should be in range (0, 1). In the actual picture values on the y-axis exceed 3,000. How could it happen? How to solve it?
I need to change the bucketing size (the width of the buckets) and the density per unit length of the x-axis. How is it possible to do these tasks?
Thank you for your help.
freq=FALSE means that the area of the entire histogram is normalized to one. As your x-axis has a very small range (about 10^(-4)), the y-values must be quite large to achieve an area (= x times y) of one.
The only way to set the number of bins is by providing a vector of break points to the parameter breaks. Theoretically, this parameter also accepts a single number, but this number is ignored by hist. Thus try the following:
bins <- 6 # number of cells
breaks <- seq(min(x),max(x),(max(x)-min(x))/bins)
hist(x, freq=FALSE, breaks=breaks)
I am trying to plot a bathymetry map of the the northeast US using the marmap library. The following code loads the correct extent but when I plot the map I have blank space between the border and the map either at the top/bottom or left/right of the map. This also occurs when exporting the plots. If I drag the plot viewer screen size the plot adjusts and I can remove almost all of the empty space but I will be running this script in a loop so its not practical to solve this problem this way. Because of the loop I also can't hard code any dimensions into the plot because it will change for each new extent. How can I set the border of the plot to match the extent of the bathymetry?
library(marmap)
library(maps)
atl<- getNOAA.bathy(-80.93645,-41.61417,30.2 ,60.905 ,resolution=4)
blues <- colorRampPalette(c("darkblue", "cyan"))
greys <- colorRampPalette(c(grey(0.4),grey(0.99)))
plot(atl, image = TRUE, land = TRUE, n=0,
bpal = list(c(0, max(atl), greys(100)),
c(min(atl), 0, blues(100))))
map(database= "state", col="black", fill=FALSE, add=TRUE)
text(x=state.center$x, y=state.center$y, state.abb, cex=0.5)
This behavior is caused by the asp argument of plot.bathy(). By default, it is fixed as asp = 1 to ensure that the scales on both axes are the same (one degree of longitude equals one degree of latitude). An unwelcome consequence of this default, is the white bands appearing either on the left/right sides of the graph, or on the top/bottom sides depending on the dimensions of your bathymetric map and the plotting device.
So I suppose you have 2 options:
If you don't mind having a slightly distorted perspective, you can set asp = NA in your call to plot.bathy()
If you want to have the correct aspect ratio but need to use the default size for your plotting region, then you have to download a bathymetric region that covers the whole plotting region of your active device. For instance, you could call plot.bathy() once to create a "default" plot, then, use par("usr") to determine the limits of the bathymetry needed to fill the entire plotting area. You would then download a second bathymetry with the appropriate ranges in longitude and latitude. Which is maybe not desirable.
Here is what the code would look like for the second option:
atl <- getNOAA.bathy(-80.93645, -41.61417, 30.2, 60.905, resolution = 4)
blues <- colorRampPalette(c("darkblue", "cyan"))
greys <- colorRampPalette(c(grey(0.4), grey(0.99)))
plot(atl, image = TRUE, land = TRUE, n = 0,
bpal = list(c(0, max(atl), greys(100)),
c(min(atl), 0, blues(100))))
coord <- par("usr")
atl2 <- getNOAA.bathy(coord[1], coord[2], coord[3], coord[4], res = 4)
plot(atl2, image = TRUE, land = TRUE, lwd = 0.2,
bpal = list(c(0, max(atl2), greys(100)),
c(min(atl2), 0, blues(100))))
map(database = "state", col = "black", fill = FALSE, add = TRUE)
text(x = state.center$x, y = state.center$y, state.abb, cex = 0.5)
I suppose the solution proposed by Roman Luštrik works too, but it has the inconvenience of leaving the white bands visible on both sides of the plot.
As an aside, if you have a lot of bathymetric regions to plot, you should maybe consider using the keep = TRUE argument of getNOAA.bathy() to avoid querying the NOAA servers each time you need to re-execute your code (and it is much faster to load local data than remote ones). And you could also download once and for all the global 4Go ETOPO1 and use subset.bathy() to, well, subset the bathymetry you need for each plot.
Here is a proposal using a workaround. The idea is to convert the bathy object into raster object and then make the plot using levelplot from rasterVisthat correctly fits the plotting area to the raster extent. Note that using raster allows having a defined pixel size and, therefore, a correct width/height ratio that you don't seem to have with marmap::plot method.
library(raster)
library(rasterVis)
r <- marmap::as.raster(atl)
state <- map('state', plot = FALSE)
state <- data.frame(lon = state$x, lat = state$y)
state.lab <- data.frame(lon = state.center$x, lat = state.center$y,
label = state.abb)
# you can remove the color legend by adding colorkey = FALSE in levelplot()
levelplot(r,
at = c(seq(min(atl), 0, length.out = 100),
seq(0, max(atl), length.out = 100)[-1]),
col.regions = c(blues(100), greys(100)),
margin = FALSE) +
xyplot(lat ~ lon, state, type = 'l',
col = 'black') +
xyplot(lat ~ lon, data = state.lab,
panel = function(y, x, ...) {
ltext(x = x, y = y, labels = state.lab$label, cex = 0.75)
})
I've successfully produced NMDS plots (monoMDS, bray-curtis, 3 dimensions, local model). Each point represents an animal and their diet composition.
I have two questions:
(1) how do I change the symbology of points to show 2 levels (a or j) within 1 column (Life stage) on the NMDS plot?!
(2) How should I show 3D NMDS, I can't get the 3D orgl- functions to work on the 3D plot. Should I just make a few plots showing different dimensions in 2D? Looking for thoughtful ideas.
The code used:
plot((BC.NMDS.length.corr), choices = c(1, 2), type = "points",
xlim = c(-2.0, 2.0),las = 1, ylim = c(-1, 1),
xlab = "NMDS Axis 1", ylab = "NMDS Axis 2",mgp = c(3.25, 1, 0),
cex.lab = 1.35, cex.axis = 1.25)
with(DATA,
points(BC.NMDS.length.corr, Class, draw = "points",col = "gray0",
show.groups = "Adult",label = TRUE, lty = 1, lwd = 2))
Using an example of what you want with the default example of the package:
# Load library
library(vegan)
# Load data
data(dune)
# Compute the distance
dis <- vegdist(dune)
Specify if you want a 3D plot, the representation of the three dimensions
# Run monoMDS
m <- monoMDS(dis, model = "loc", k=3)
# The 3D representation
plot(m)
# Load library for 3D representation
library(scatterplot3d)
Coordinates are in m$points; each column referring to each dimension.
# Graphical representation
scatterplot3d(x=m$points[,1], y=m$points[,2], z=m$points[,3])
Additionally, if you want to colour the plots depending on a factor, you can specify color=A, where A is a numeric value where groups are codified.
I am making a density map in R using ggmap and stat_density2d. The code looks like this:
riverside <- get_map('Riverside, IL', zoom = 14 , color = 'bw' )
RiversideMap <- ggmap(riverside, extent = 'device', legend = 'topleft')
# make the map:
RiversideMap +
stat_density2d(aes(x = lon, y = lat,
fill = ..level.. , alpha = ..level..),size = .01, bins = 16,
data = myData, geom = 'polygon') +
scale_fill_gradient(low = "yellow", high = "blue") +
scale_alpha(range = c(.0, 0.3), guide = FALSE)
The density shown in the map's color legend is normalized in stat_density2d by requiring the integral of the density over area equals 1.
In the map, the units of the x and y axes are decimal degrees. (For example, a point is specified by the coordinates lat = 41.81888 and lon = -87.84147).
For ease of interpretation, like to make two changes to the values of the density as displayed in the map legend.
First, I'd like the integral of the density to be N (the number of data points - or addresses - in the data set) rather than 1. So the values displayed in the legend need to be multiplied by N = nrow(myData).
Second, I'd like the unit of distance to be kilometers rather than decimal degrees. For the latitudes and longitudes that I am plotting, this requires dividing the values displayed in the legend by 9203.
With the default normalization of density in stat_density2d, I get these numbers in the legend: c(2000,1500,1000,500).
Taking N = 1600 and performing the above re-scalings, this becomes c(348, 261, 174, 87) (= 1600/9203 * 2000 etc). Obviously, these are not nice round numbers, so it would be even better if the legend numbers were say c(400,300,200,100) with their locations in the legend color bar adjusted accordingly.
The advantage of making these re-scalings is that the density in the map becomes easy to interpret: it is just the number of people per square km (rather than the probability density of people per square degree).
Is there an easy way to do this? I am new to ggmap and ggplot2. Thanks in advance.
In brief, use:
scale_fill_continuous(labels = scales::unit_format(unit = "k", scale = 1e-3))
This link is great help for managing scales, axes and labels: https://ggplot2-book.org/scales.html
I'm trying to add color to specific points in my circular data based on group membership (I have two groups: one with individuals with a certain medical condition and another group of just healthy controls). I've converted their data from degrees to radians and put it on the plot, but I haven't managed to be able to selectively change the color of the points based on the factor variable I have).
Know that I've loaded library (circular), which doesn't allow me to use ggplot. Here's the syntax I've been working with:
plot(bcirc, stack=FALSE, bins=60, shrink= 1, col=w$dx, axes=FALSE, xlab ="Basal sCORT", ylab = "Basal sAA")
If you've noticed, I specified the factor variable (which has two levels) in the color section, but it just keeps putting everything in one color. Any suggestions?
Seems plot.circular does not like to assign multiple colours. Here's one potential work-around:
library(circular)
## simulate circular data
bcirc1 <- rvonmises(100, circular(90), 10, control.circular=list(units="degrees"))
bcirc2 <- rvonmises(100, circular(0), 10, control.circular=list(units="degrees"))
bcirc <- c(bcirc1, bcirc2)
dx <- c(rep(1,100),rep(2,100))
## start with blank plot, then add group-specific points
plot(bcirc, stack=FALSE, bins=60, shrink= 1, col=NA,
axes=FALSE, xlab ="Basal sCORT", ylab = "Basal sAA")
points(bcirc[dx==1], col=rgb(1,0,0,0.1), cex=2) # note: a loop would be cleaner if dealing with >2 levels
points(bcirc[dx==2], col=rgb(0,0,1,0.1), cex=2)
Inspired by Paul Regular's example, here is a version using the same data where one condition is plotted stacking inwards and the other is plotted stacking outwards.
library(circular)
## simulate circular data
bcirc1 <- rvonmises(100, circular(90, units = 'degrees'), 10, control.circular=list(units="degrees"))
bcirc2 <- rvonmises(100, circular(0, units = 'degrees'), 10, control.circular=list(units="degrees"))
bcirc <- data.frame(condition = c(
rep(1,length(bcirc1)),
rep(2,length(bcirc2)) ),
angles = c(bcirc1,
bcirc2) )
## start with blank plot, then add group-specific points
dev.new(); par(mai = c(1, 1, 0.1,0.1))
plot(circular(subset(bcirc, condition == 1)$angles, units = 'degrees'), stack=T, bins=60, shrink= 1, col=1,sep = 0.005, tcl.text = -0.073,#text outside
axes=T, xlab ="Basal sCORT", ylab = "Basal sAA")
par(new = T)
plot(circular(subset(bcirc, condition == 2)$angles, units = 'degrees'), stack=T, bins=60, shrink= 1.05, col=2,
sep = -0.005, axes=F)#inner circle, no axes, stacks inwards