how to use gganimate package plot a dynamic map in R? - r

As I know gganimate has been in version 1.0.3,we can use transition_* function to plot a dynamic graph. But when I run following code ,there is an error :
Error in `$<-.data.frame`(`*tmp*`, "group", value = "") :
replacement has 1 row, data has 0
code:
library(ggmap)
library(gganimate)
world <- map_data("world")
world <- world[world$region!="Antarctica",]
data <- data.frame(state = c("Alabama","Alaska","Alberta","Alberta","Arizona"),
lon = c(-86.55,-149.52,-114.05,-113.25,-112.05),
lat = c(33.30,61.13,51.05,53.34,33.30)
)
ggplot()+
geom_map(data = world,
map = world,
aes(long,lat,map_id = region),
color = '#333300',
fill = '#663300') +
geom_point(data = data,
aes(x = lon, y = lat),
size = 2.5) +
geom_jitter(width = 0.1) +
transition_states(states = state)

You have no data defined in the top level ggplot() line, so state in transition_* comes out of nowhere.
It's also unclear to me why you have a geom_jitter level in your code. Like transition_*, it has no top level data / aesthetic mappings to inherit, so it would have thrown an error too, had transition_* not triggered an error first. In addition, even if we add the mappings, given the range of lat/lon coordinates in your data, jittering by 0.1 is hardly going to matter visually.
You can try the following:
# put data in top level ggplot()
ggplot(data,
aes(x = lon, y = lat))+
geom_map(data = world,
map = world,
aes(long,lat,map_id = region),
color = '#333300', fill = '#663300',
# lighter background for better visibility
alpha = 0.5) +
geom_point(size = 2.5) +
# limit coordinates to relevant range
coord_quickmap(x = c(-180, -50), y = c(25, 85)) +
transition_states(states = state)

Related

Mapping geom-cordinates to a map object in R

I am attempting to map some geom-points/cordinates to a map of the country Sri Lanka. I am able to map the district borders, and the population as expected, but I am having trouble plotting the geom points onto the map.
Install package
devtools::install_github("thiyangt/ceylon")
Load package
library("ceylon")
library(tidyverse)
library(sp)
library(viridis)
data(sf_sl_0)
Mapping only Sri Lanka
ggplot(sf_sl_0) + geom_sf()
Mapping the districts of Sri Lanka + population
ggplot(district) + geom_sf(aes(fill = population), show.legend = TRUE) + scale_fill_viridis()
Mappping specific geom-cordinates onto the map of Sri Lanka districts
These are the cordinates I want to map (yes, they are definitely within SL)
df_cord <- data.frame (lat = c("6.2441521", "6.2234515"),
lon = c("80.0590804", "80.2126109"))
I tried:
ggplot(district) +
geom_sf(df_cord) + scale_fill_viridis() +
geom_point(
data = df_cord,
aes(x = lon, y = lat),
size = 4,
shape = 23,
fill = "darkred"
)
But I get an error: Error in validate_mapping():
! mapping must be created by aes()
It looks like I might need to find the x,y cordinates of every geom point, and then map it with cord_sf? But I am not having an luck figuring out how to do this. I found a cool function called usmap::usmap_transform, which converts US geom points to x,y cordinates... but I can't figure out how to do the same for this map of Sri Lanka.
I am very new to mapping -- could someone please advise? Many thanks! I am open to other approaches/solutions!
One way would be to convert the coordinates to an sf object using st_as_sf and plot them using geom_sf. Don't forget to reproject the data to the same coordinate sistem:
library(ceylon)
library(tidyverse)
library(sp)
library(viridis)
library(sf)
data(district)
df_cord <- data.frame (lat = c(6.2441521, 6.2234515),
lon = c(80.0590804, 80.2126109))
df_cord <- df_cord %>%
st_as_sf(coords = c("lon", "lat"), crs = 4326) %>%
st_transform(crs = st_crs(district)) #reproject coords using the coordinate system of the polygons
#plot
ggplot(district) +
geom_sf(aes(fill = population), show.legend = TRUE) +
geom_sf(data = df_cord ,
size = 4,
shape = 23,
fill = "darkred") +
scale_fill_viridis()
I think you can't assign two data frames in ggplot.
Put the latitude and longitude values ​​inside the geom_point's aes(). Remember that longitude is the x-axis and latitude is the y-axis.
Try this:
ggplot() +
geom_sf(district) +
scale_fill_viridis() +
geom_point(
aes(x = c("80.0590804", "80.2126109"),
y =c("6.2441521", "6.2234515")),
size = 4,
shape = 23,
fill = "darkred"
)
You can add annotations (annotate) which will display your two coordinates. Also, set the right coordinate system like this:
ggplot(district) +
geom_sf(aes(fill = population), show.legend = TRUE) +
annotate("point", x = 80.0590804, y = 6.2441521, colour = "red", size = 2) +
annotate("point", x = 80.2126109, y = 6.2234515, colour = "red", size = 2) +
coord_sf(default_crs = sf::st_crs(4326)) +
scale_fill_viridis()
Output:

Is there a polygon of world countries from -360 to 360 degrees in R?

I am kind of stuck on how to plot world maps that do not adjust to the map_data provide by the ggplot2 package, which is "world" (from -180 to 180 degrees) and "world2" (from 0 to 360 degrees). For example, if I want to plot from 100°E to 20°E, no polygon provide by ggplot2 is useful. Here is the code of the example:
library(ggplot2)
map1 <- map_data('world')
map2 <- map_data('world2')
ggplot() +
theme_bw() +
geom_polygon(data = map1,
mapping = aes(x = long,
y = lat,
group = group),
col = 'gray') +
coord_fixed(1.4, xlim = c(100,380))
ggplot() +
theme_bw() +
geom_polygon(data = map2,
mapping = aes(x = long,
y = lat,
group = group),
col = 'gray') +
coord_fixed(1.4, xlim = c(100,380))
So, are there world maps polygons like those of the example but with a greater range?
This is scrappy, but why not? You could show a duplicated world so that every region can be shown without going over the edge.
library(dplyr)
map1 <- map_data('world')
map2 <- map_data('world') %>% mutate(long = long+360)
map3 <- map_data('world') %>% mutate(long = long+720)
ggplot() +
theme_bw() +
geom_polygon(data = map1,
mapping = aes(x = long,
y = lat,
group = group),
col = 'gray') +
geom_polygon(data = map2,
mapping = aes(x = long,
y = lat,
group = group),
col = 'gray') +
geom_polygon(data = map3,
mapping = aes(x = long,
y = lat,
group = group),
col = 'gray') +
coord_fixed(1.4, xlim = c(100,480))
Rather than finding those polygons, you might just clip the longitude boundaries with a coord_quickmap() or coord_sf(). Note that coord_map() will incorrectly group polygon's points unless clipped before the ggplot() call.
library(tidyverse)
ggplot() +
theme_bw() +
geom_polygon(data = map2,
mapping = aes(x = long,
y = lat,
group = group),
col = 'gray') +
coord_sf(xlim = c(20,100))
#coord_quickmap(xlim = c(100,20)) is also an alternative to coord_sf()
"world" and "world2" are two versions of the world map that are implemented in the "maps" package. But that package actually allows you to define a world map with any boundaries, e.g. c(20,380) or c(100,460).
The simplest way is just to use the "wrap" option (which is described in the man page of maps::map). This option is passed to maps::map() (so look in the maps package for full help page)
map3 <- map_data('world', wrap=c(20,380))
This should give you a nice map for any meridian that you may choose. Note that in this case "wrap" must be be a vector and that the left and right boundaries must be exactly 360 apart.

Creating a Map with Custom Legend Using ggplot2 in R

I’m currently trying to display my data on a map as points. In fact I got two different data sets of two different studies which I’d like to combine on the map. But my first problem was where to find a map to use for my purpose.
#In the R graphics Cookbook I read about this code to create a map using the ggplot2 package
library(ggplot2)
library(maps)
states_map <- mapd_data(“state”)
ggplot(states_map, aes(x=long, y=lat, group=group)) +
geom_polygon(fill=”white”, colour=”black”) +
#Then I added the data of my two data sets and it worked perfectly fine.
geom_point(data = dat1, aes(x = longitude, y = latitude, group= NA), shape=21, col = "black", fill=”red”, size = dat1$var1) +
geom_point(data = dat2, aes(x = longitude, y = latitude, group= NA), shape=21, col = "black", fill=”blue”, size = dat2$var2)
Now I want to add two legends, one to explain the difference between the point colors and the other to explain the point size. Both data sets can share the same legend for the point size because Var1 and Var2 are on the same scale. But I don’t know how to add custom legends to a ggplot (I even don’t achieve to add any legend to the ggplot). It would be nice to have anything like legend()-function which adds a legend to a normal plot, but I think ggplot wasn’t programmed to solve problems like this on your own. Another approach to solve the problem could be to plot the map without using ggplot.
If you want a legend then you have to map on an aesthetic, i.e. move fill=... and size=... inside aes(). After doing so you could set your desired fill colors via scale_fill_manual:
library(ggplot2)
library(maps)
states_map <- map_data("state")
dat1 <- data.frame(longitude = -110, latitude = 35, var1 = 100)
dat2 <- data.frame(longitude = -90, latitude = 40, var2 = 200)
ggplot(states_map, aes(x=long, y=lat)) +
geom_polygon(aes(group=group), fill="white", colour="black") +
geom_point(data = dat1, aes(x = longitude, y = latitude, fill = "dat1", size = var1), shape=21, col = "black") +
geom_point(data = dat2, aes(x = longitude, y = latitude, fill = "dat2", size = var2), shape=21, col = "black") +
scale_fill_manual(values = c(dat1 = "red", dat2 ="blue"), labels = c(dat1 = "Data 1", dat2 ="Data 2"))

Cumulative points over year on map with R ggplot2 and ggplotly

I am trying to plot new locations opened over each month on a map cumulatively. I am able to create an animation with new locations each month, but not cumulatively. In other words, I want to see the new locations add to the existing ones.
Here is the sample data
DF <- data.frame("latitude" = c(42.29813,41.83280,41.83280,30.24354),
"longitude" =c(-71.23154,-72.72642,-72.72642,-81.62098),
"month" = c(1,2,3,4))
This is what I have tried
usa <- ggplot() +
borders("usa", colour = "gray85", fill = "gray80") +
theme_map()
map <- usa +
geom_point(aes(x = longitude, y = latitude, cumulative=TRUE,
frame=month,stat = 'identity' ),data = DF )
map
# Generate the Visual and a HTML output
ggp <- ggplotly(map)%>%
animation_opts(transition = 0)
ggp
The output does not show locations cumulatively. I want to see all four locations in the end basically.
If you use gganimate you can include transition_states to animate your points. For cumulative addition of points, use shadow_mark to include data behind the current frame.
library(ggthemes)
library(gganimate)
library(ggplot2)
DF <- data.frame("latitude" = c(42.29813,41.83280,41.83280,30.24354),
"longitude" =c(-71.23154,-72.72642,-72.72642,-81.62098),
"month" = c(1,2,3,4))
usa <- ggplot() +
borders("usa", colour = "gray85", fill = "gray80") +
theme_map()
map <- usa +
geom_point(aes(x = longitude, y = latitude), color = "black", data = DF) +
transition_states(month, transition_length = 0, state_length = 1) +
shadow_mark()
map
Edit: To save the animation as a .gif, use anim_save.
anim_save("mapanim.gif", map)
In addition, if you want to change the width/height of the final animation, you can specify, for example:
animate(map, height = 400, width = 600)

How do you combine a map with complex display of points in ggplot2?

I'm trying to plot points from study sites with a background map of Africa. I can create the two independently, but I am having a hard time overlaying them on top of eachother.
The map of Africa I am using is an Esri shapefile from maplibrary.org. It is available from my dropbox at https://www.dropbox.com/s/etqdw3nky52czv4/Africa%20map.zip. I have the points in a text file, also available from my drop box. https://www.dropbox.com/s/scvymytjsr5pvaf/SPM-437-22Nov12.txt. They refer to studies on molecular drug resistance of malaria parasites. I would like to plot them so that the color is the proportion of parasites with the drug resistant genetic marker and the size is the number of parasites tested.
Plotting the points independently:
qplot(Longitude, Latitude, data = d.spm.437, colour = Frc437, size = Tot437)
Plotting the map of Africa:
library(maptools)
africa = readShapePoly("Africa.shp")
africa.map = fortify(africa, region="COUNTRY")
qplot(long, lat, data = africa.map, geom="path", group=group)
Any help on putting these two together while preserving the display of the points would be appreciated.
Try something like this. Seems to work for me. I think some of your lat-long coordinates are wrong though. The fill colour for geom_point is currently set to Tot437 so you might want to change that.
library(ggplot2)
library(rgdal)
africa <- readOGR("c:/test", layer = "Africa")
africa.map = fortify(africa, region="COUNTRY")
africa.points = read.table("c:/test/SPM-437-22Nov12.txt", header = TRUE, sep = ",")
names(africa.points)[which(names(africa.points) == 'Longitude')] <- 'long' # rename lat and long for consistency with shp file
names(africa.points)[which(names(africa.points) == 'Latitude')] <- 'lat'
ggplot(africa.map, aes(x = long, y = lat, group = group)) +
geom_polygon(colour = "black", size = 1, fill = "white", aes(group = group)) +
geom_point(data = africa.points, aes(x = long, y = lat, fill = Tot437, group = NULL), size = 4, shape = 21, colour = "black", size = 3)
Incidentally, looking at your map you may have difficulty getting a good detailed view of individual areas, so one way to tackle that would be by subsetting, in this case with the data frames. You could do this:
africa.map <- africa.map[africa.map$id == 'Madagascar', ]
africa.points <- africa.points[africa.points$Country == 'Madagascar', ]
ggplot(africa.map, aes(x = long, y = lat, group = group)) +
geom_polygon(colour = "black", size = 1, fill = "white", aes(group = group)) +
geom_point(data = africa.points, aes(x = long, y = lat, fill = Tot437, group = NULL), size = 2, shape = 21, colour = "black", size = 2)
...which should get you something similar to this:

Resources