I have data for several pixels of the pacific ocean (each pixel is a 250km^2 square of the ocean represented by a lat and lon value). I have the following code in R to draw my map with the minor breaks representing each pixel I have data for:
mp1 <- fortify(map(fill=TRUE, plot=FALSE))
mp2 <- mp1
mp2$long <- mp2$long + 360
mp2$group <- mp2$group + max(mp2$group) + 1
mp <- rbind(mp1, mp2)
ggplot(aes(x = long, y = lat, group = group), data = mp) +
geom_path() +
scale_x_continuous(name="Longitude",minor_breaks=seq(170,246,2), limits = c(170, 246)) +
scale_y_continuous(name= "Latitude",minor_breaks=seq(30,64,2),limits = c(30, 64))
which gives:
For each pixel that isn't landlocked I'd initially like to colour in, say blue, to represent ocean. I'd also like a legend explaining this. Eventually, once I have processed the data, I would like to colour it by the classification it will be given. Will this be possible? If it helps I have a matrix of all possible lon/lat combinations that I have pixels for so they would be available for referencing.
Thanks
mp2 looks like its derived from a shapefile or vector data; I'm assuming you have a second raster (pixel) data layer. You could try using geom_raster or geom_tile:
ggplot(aes(x = long, y = lat, group = group), data = mp) +
geom_raster(data = rasterdat, aes(fill = colorvar)) +
geom_path() +
scale_x_continuous(name="Longitude",minor_breaks=seq(170,246,2),
limits = c(170, 246)) +
scale_y_continuous(name= "Latitude",minor_breaks=seq(30,64,2),
limits = c(30, 64))
where rasterdat is your dataframe of raster data and colorvar is some field that is used to specify the color. I'm also assuming that you can reshape your raster data so it has lat and lon columns like mp2. Note that you should add the geom_raster aesthetic BEFORE geom_path, so that the map lines are drawn on top.
Related
I am looking for a simple alternative to map_data('world') as a data set with which to easily draw the countries of the world. Ideally it's easily implementable with ggplot2.
The problem is that I am graphing some geographic points, some of which appear close to -90 (S). When I use map_data('world') to get my polygons, I see that Antarctica doesn't run all the way to -90 (lowest lat value for Antarctica is -85.19218 - see code below). Thus anything further south than that shows as if its off the map, which doesn't look great.
Here is an example of what I am talking about:
library('ggplot2') #Import library
world = map_data('world') #Get polygon data
data = data.frame(lat = -86, long = 0) #Create geographic data with southerly value
#plot
ggplot() +
geom_polygon(data = world,
aes(y = lat, x = long, group = group), col = 'grey', fill = NA) +
geom_point(data = data,
aes(y = lat, x = long), col = 'red')
Gives:
You can see the limits of the Antarctic extent as follows:
library('dplyr')
world %>%
filter(region == 'Antarctica') %>%
select(lat) %>%
min()
[1] -85.19218
Thus the problem is not the projection, its the data set. Does anyone know an alternative easily available rendering of the countries that has Antarctica running to -90?
There isn't any data for ggplot2 to plot below about 85 degrees south in the world data as a polygon. Using geom_polygon also has the drawback of connecting the data from the far left (west) to the data on the far right(east).
To get around having the straight line above the red dot, use the sf package and geom_sf to plot spatial data.
I don't know of a good way to plot Antarctica along with the entire rest of the globe. If you are mostly interested in the southern pole & it's surroundings, an orthographic projection might work.
library(tidyverse)
library(rnaturalearth)
world <- map_data('world') #Get polygon data
data = data.frame(lat = -86, long = 0) #Create geographic data with southerly value
#plot
p_polygon <- ggplot() +
geom_polygon(data = world,
aes(y = lat, x = long, group = group), col = 'grey', fill = NA) +
geom_point(data = data,
aes(y = lat, x = long), col = 'red')
# use rnaturalearth package to get coastline data in the sf format
world_sf <- ne_coastline(returnclass = 'sf')
# use geom_sf to plot the data
p_sf <- ggplot(world_sf) +
geom_sf() +
geom_point(data = data, aes(y = lat, x = long), col = 'red')
# geom_sf, using an orthographic projection
p_sf_ortho <- ggplot(world_sf) +
geom_sf() +
geom_point(data = data, aes(y = lat, x = long), col = 'red') +
coord_sf( crs= "+proj=ortho +lat_0=-80 +lon_0=90")
# the three plots together
cowplot::plot_grid(p_polygon, p_sf, p_sf_ortho,
labels = c('polygon', 'sf', 'sf orthographic'))
Created on 2021-08-27 by the reprex package (v0.3.0)
The {rnaturalearth} package has a good representation of Antarctica (and the other land masses too!) I have switched to using it for all my background mapping. This example:
world <- rnaturalearth::ne_countries(returnclass = "sf")
map_crs <- st_crs(3031) # WGS 84 / Antarctic Polar Stereographic
ggplot() + geom_sf(data = world %>% st_transform(map_crs)) +
coord_sf(datum = map_crs,
ylim = c(-3e6,3e6),
xlim = c(-3e6,3e6))
Produces this map - there is just a tiny sliver of unmapped Antarctica:
I am trying to label my polygons by using ggplot in R. I found a topic here on stackoverflow that I think is very close to what I want except with points.
Label points in geom_point
I found some methods online. Now I first need to find the central location of each shape and then I have to put these locations together with the name together. Then link this to the labeling function in geom_text()
ggplot centered names on a map
Since I have been trying for a long time now I decided to ask the question and hope that someone here can give me the final push to what I want. My plotting function:
region_of_interest.fort <- fortify(region_of_interest, region = "score")
region_of_interest.fort$id <- as.numeric(region_of_interest.fort$id)
region_of_interest.fort$id <- region_of_interest.fort$id
region_of_interest.fort1 <- fortify(region_of_interest, region = "GM_NAAM")
region_of_interest.fort1$id <- as.character(region_of_interest.fort1$id)
region_of_interest.fort1$id <- region_of_interest.fort1$id
idList <- unique(region_of_interest.fort1$id)
centroids.df <- as.data.frame(coordinates(region_of_interest))
names(centroids.df) <- c("Longitude", "Latitude")
randomMap.df <- data.frame(id = idList, shading = runif(length(idList)), centroids.df)
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
It gives me the error: ggplot2 doesn't know how to deal with data of class uneval
My data
region_of_interest$GM_NAAM
[1] Groningen Haren Ooststellingwerf Assen Aa en Hunze Borger- Odoorn
[7] Noordenveld Westerveld Tynaarlo Midden-Drenthe
415 Levels: 's-Gravenhage 's-Hertogenbosch Aa en Hunze Aalburg Aalsmeer Aalten ... Zwolle
region_of_interest$score
[1] 10 -2 -1 2 -1 -4 -4 -5 0 0
Try something like this?
Get a data frame of the centroids of your polygons from the
original map object.
In the data frame you are plotting, ensure there are columns for
the ID you want to label, and the longitude and latitude of those
centroids.
Use geom_text in ggplot to add the labels.
Based on this example I read a world map, extracting the ISO3 IDs to use as my polygon labels, and make a data frame of countries' ID, population, and longitude and latitude of centroids. I then plot the population data on a world map and add labels at the centroids.
library(rgdal) # used to read world map data
library(rgeos) # to fortify without needing gpclib
library(maptools)
library(ggplot2)
library(scales) # for formatting ggplot scales with commas
# Data from http://thematicmapping.org/downloads/world_borders.php.
# Direct link: http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip
# Unpack and put the files in a dir 'data'
worldMap <- readOGR(dsn="data", layer="TM_WORLD_BORDERS_SIMPL-0.3")
# Change "data" to your path in the above!
worldMap.fort <- fortify(world.map, region = "ISO3")
# Fortifying a map makes the data frame ggplot uses to draw the map outlines.
# "region" or "id" identifies those polygons, and links them to your data.
# Look at head(worldMap#data) to see other choices for id.
# Your data frame needs a column with matching ids to set as the map_id aesthetic in ggplot.
idList <- worldMap#data$ISO3
# "coordinates" extracts centroids of the polygons, in the order listed at worldMap#data
centroids.df <- as.data.frame(coordinates(worldMap))
names(centroids.df) <- c("Longitude", "Latitude") #more sensible column names
# This shapefile contained population data, let's plot it.
popList <- worldMap#data$POP2005
pop.df <- data.frame(id = idList, population = popList, centroids.df)
ggplot(pop.df, aes(map_id = id)) + #"id" is col in your df, not in the map object
geom_map(aes(fill = population), colour= "grey", map = worldMap.fort) +
expand_limits(x = worldMap.fort$long, y = worldMap.fort$lat) +
scale_fill_gradient(high = "red", low = "white", guide = "colorbar", labels = comma) +
geom_text(aes(label = id, x = Longitude, y = Latitude)) + #add labels at centroids
coord_equal(xlim = c(-90,-30), ylim = c(-60, 20)) + #let's view South America
labs(x = "Longitude", y = "Latitude", title = "World Population") +
theme_bw()
Minor technical note: actually coordinates in the sp package doesn't quite find the centroid, but it should usually give a sensible location for a label. Use gCentroid in the rgeos package if you want to label at the true centroid in more complex situations like non-contiguous shapes.
The accepted answer here may work, but the actual question asked specifically notes that there is an error "ggplot2 doesn't know how to deal with data of class uneval."
The reason that it is giving you the error is because the inclusion of centroids.df needs to be a named variable (e.g. accompanied by "data=")
Currently:
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
Should be (note: "data=centroids.df"):
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(data=centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
This issue was addressed here: How to deal with "data of class uneval" error from ggplot2?
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)
Hi visualization lovers,
I am trying to create a color map plot,like this one:
(source: https://github.com/hrbrmstr/albersusa)
BUT i want this maps to be biased so that the areas of the states to be proportional to the value I provide (in particular,I use GPD value).
What i mean is that I want some states to look bigger, some smaller that they are in reality but reminding the real USA map as much as possible.
No problems with the states moving or shape destroying.
Any ideas? Any ready solutions?
Currently I use R and albersusa package because it is something I am familiar with. Open to change!
My current code for the plot is:
gmap<-
ggplot() +
geom_map(data = counties#data, map = cmap,
aes(fill =atan(y/x),alpha=x+y, map_id = name),
color = "gray50") +
geom_map(data = smap, map = smap,
aes(x = long, y = lat, map_id = id),
color = "black", size = .5, fill = NA) +
theme_map(base_size = 12) +
theme(plot.title=element_text(size = 16, face="bold",margin=margin(b=10))) +
theme(plot.subtitle=element_text(size = 14, margin=margin(b=-20))) +
theme(plot.caption=element_text(size = 9, margin=margin(t=-15),hjust=0)) +
scale_fill_viridis()+guides(alpha=F,fill=F)
Here's a very ugly first try to get you started, using the outlines from the maps package and some data manipulation from dplyr.
library(maps)
library(dplyr)
library(ggplot2)
# Generate the base outlines
mapbase <- map_data("state.vbm")
# Load the centroids
data(state.vbm.center)
# Coerce the list to a dataframe, then add in state names
# Then generate some random value (or your variable of interest, like population)
# Then rescale that value to the range 0.25 to 0.95
df <- state.vbm.center %>% as.data.frame() %>%
mutate(region = unique(mapbase$region),
somevalue = rnorm(50),
scaling = scales::rescale(somevalue, to = c(0.25, 0.95)))
df
# Join your centers and data to the full state outlines
df2 <- df %>%
full_join(mapbase)
df2
# Within each state, scale the long and lat points to be closer
# to the centroid by the scaling factor
df3 <- df2 %>%
group_by(region) %>%
mutate(longscale = scaling*(long - x) + x,
latscale = scaling*(lat - y) + y)
df3
# Plot both the outlines for reference and the rescaled polygons
ggplot(df3, aes(long, lat, group = region, fill = somevalue)) +
geom_path() +
geom_polygon(aes(longscale, latscale)) +
coord_fixed() +
theme_void() +
scale_fill_viridis()
These outlines aren't the best, and the centroid positions they shrink toward cause the polygons to sometimes overlap the original state outline. But it's a start; you can find better shapes for US states and various centroid algorithms.
I am trying to label my polygons by using ggplot in R. I found a topic here on stackoverflow that I think is very close to what I want except with points.
Label points in geom_point
I found some methods online. Now I first need to find the central location of each shape and then I have to put these locations together with the name together. Then link this to the labeling function in geom_text()
ggplot centered names on a map
Since I have been trying for a long time now I decided to ask the question and hope that someone here can give me the final push to what I want. My plotting function:
region_of_interest.fort <- fortify(region_of_interest, region = "score")
region_of_interest.fort$id <- as.numeric(region_of_interest.fort$id)
region_of_interest.fort$id <- region_of_interest.fort$id
region_of_interest.fort1 <- fortify(region_of_interest, region = "GM_NAAM")
region_of_interest.fort1$id <- as.character(region_of_interest.fort1$id)
region_of_interest.fort1$id <- region_of_interest.fort1$id
idList <- unique(region_of_interest.fort1$id)
centroids.df <- as.data.frame(coordinates(region_of_interest))
names(centroids.df) <- c("Longitude", "Latitude")
randomMap.df <- data.frame(id = idList, shading = runif(length(idList)), centroids.df)
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
It gives me the error: ggplot2 doesn't know how to deal with data of class uneval
My data
region_of_interest$GM_NAAM
[1] Groningen Haren Ooststellingwerf Assen Aa en Hunze Borger- Odoorn
[7] Noordenveld Westerveld Tynaarlo Midden-Drenthe
415 Levels: 's-Gravenhage 's-Hertogenbosch Aa en Hunze Aalburg Aalsmeer Aalten ... Zwolle
region_of_interest$score
[1] 10 -2 -1 2 -1 -4 -4 -5 0 0
Try something like this?
Get a data frame of the centroids of your polygons from the
original map object.
In the data frame you are plotting, ensure there are columns for
the ID you want to label, and the longitude and latitude of those
centroids.
Use geom_text in ggplot to add the labels.
Based on this example I read a world map, extracting the ISO3 IDs to use as my polygon labels, and make a data frame of countries' ID, population, and longitude and latitude of centroids. I then plot the population data on a world map and add labels at the centroids.
library(rgdal) # used to read world map data
library(rgeos) # to fortify without needing gpclib
library(maptools)
library(ggplot2)
library(scales) # for formatting ggplot scales with commas
# Data from http://thematicmapping.org/downloads/world_borders.php.
# Direct link: http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip
# Unpack and put the files in a dir 'data'
worldMap <- readOGR(dsn="data", layer="TM_WORLD_BORDERS_SIMPL-0.3")
# Change "data" to your path in the above!
worldMap.fort <- fortify(world.map, region = "ISO3")
# Fortifying a map makes the data frame ggplot uses to draw the map outlines.
# "region" or "id" identifies those polygons, and links them to your data.
# Look at head(worldMap#data) to see other choices for id.
# Your data frame needs a column with matching ids to set as the map_id aesthetic in ggplot.
idList <- worldMap#data$ISO3
# "coordinates" extracts centroids of the polygons, in the order listed at worldMap#data
centroids.df <- as.data.frame(coordinates(worldMap))
names(centroids.df) <- c("Longitude", "Latitude") #more sensible column names
# This shapefile contained population data, let's plot it.
popList <- worldMap#data$POP2005
pop.df <- data.frame(id = idList, population = popList, centroids.df)
ggplot(pop.df, aes(map_id = id)) + #"id" is col in your df, not in the map object
geom_map(aes(fill = population), colour= "grey", map = worldMap.fort) +
expand_limits(x = worldMap.fort$long, y = worldMap.fort$lat) +
scale_fill_gradient(high = "red", low = "white", guide = "colorbar", labels = comma) +
geom_text(aes(label = id, x = Longitude, y = Latitude)) + #add labels at centroids
coord_equal(xlim = c(-90,-30), ylim = c(-60, 20)) + #let's view South America
labs(x = "Longitude", y = "Latitude", title = "World Population") +
theme_bw()
Minor technical note: actually coordinates in the sp package doesn't quite find the centroid, but it should usually give a sensible location for a label. Use gCentroid in the rgeos package if you want to label at the true centroid in more complex situations like non-contiguous shapes.
The accepted answer here may work, but the actual question asked specifically notes that there is an error "ggplot2 doesn't know how to deal with data of class uneval."
The reason that it is giving you the error is because the inclusion of centroids.df needs to be a named variable (e.g. accompanied by "data=")
Currently:
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
Should be (note: "data=centroids.df"):
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(data=centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
This issue was addressed here: How to deal with "data of class uneval" error from ggplot2?