Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding labels to plotly map created using plot_geo

Tags:

r

ggplot2

plotly

I have a choropleth map created using plotly::plot_geo. I would like to add labels on top of the map so that, for instance, over the location of Alabama on the map, it would say 'AL (68)', but for all states, as in the example below:

enter image description here

Can anyone tell me if there is a way to do this?

library(tidyverse)
library(plotly)

set.seed(1)

density <- sample(1:100, 50, replace = T)

g <- list(
  scope = 'usa',
  projection = list(type = 'albers usa'),
  lakecolor = toRGB('white')
)

plot_geo() %>%
  add_trace(
    z = ~density, text = state.name, span = I(0),
    locations = state.abb, locationmode = 'USA-states'
  ) %>%
  layout(geo = g) 
like image 446
DJC Avatar asked Jun 29 '21 15:06

DJC


People also ask

How to plot a geographical graph using Plotly?

You need to initiate plotly’s notebook mode to display the plot inside the notebook. This will allow you to generate graphs offline and save them in a local machine. We load our first dataset based on the USA’s agricultural export. Here, the code of the state is vital as it helps us with the location when we plot a geographical graph.

What is geographical plotting in Python?

Geographical plotting is a method of displaying data on a global scale as well as for states of a country, often in a colorful manner. It plays a significant role in data analysis and visualization. It is commonly used while building dashboards to present widespread data. In order to create interactive maps we use python’s plotly library.

Is it possible to map a marker/line/polygon using plot_geo () or plot_ly?

It’s possible to achieve the same effect using plot_ly () or plot_mapbox (), but the relevant marker/line/polygon data has to be put into an sf data structure before rendering (see Section 4.2.1 for more details). FIGURE 4.5: A comparison of plotly ’s integrated mapping solutions: plot_mapbox () (top) and plot_geo () (bottom).

What is the difference between plot_Mapbox () and plot_Geo ()?

The other integrated mapping solution in plotly is plot_geo (). Compared to plot_mapbox (), this approach has support for different mapping projections, but styling the basemap is limited and can be more cumbersome. Figure 4.


Video Answer


3 Answers

Using your example, this is possible with plotly::plot_ly()

set.seed(1)

density <- sample(1:100, 50, replace = T)

g <- list(
  scope = 'usa',
  projection = list(type = 'albers usa'),
  lakecolor = toRGB('white')
  )

plot_ly() %>%
  layout(geo = g) %>%
  add_trace(type = "choropleth", locationmode = 'USA-states',
            locations = state.abb,
            z = ~density, text = state.name,
            color = ~density, autocolorscale = TRUE) %>%
  add_trace(type = "scattergeo", locationmode = 'USA-states',
            locations = state.abb, text = paste0(state.abb, "\n", density),
            mode = "text",
            textfont = list(color = rgb(0,0,0), size = 12))

Output is:

enter image description here

Still not sure how to do this with plotly::plot_geo(), but this solution does allow you to stay within the plotly family.

like image 76
pseudorandom Avatar answered Oct 20 '22 05:10

pseudorandom


I don't think this is reasonably possible in R, at least for the time being. However, this is supported in python (see @r-beginners comment and https://plotly.com/python/text-and-annotations/).

I am showing a couple of examples of alternative approaches using ggplot and leaflet, but each presents considerable drawbacks if you are wedded to plotly. Mapbox appears to be another option, but I have never used it. Examples using all of these packages in the article that was already linked in the comments (https://plotly-r.com/maps.html).

Example dataset

library(sf)

set.seed(1)

nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
nc$density <- sample(1:100, nrow(nc), replace = T)

nc$lat <- st_coordinates(st_centroid(nc))[,"Y"]
nc$lon <- st_coordinates(st_centroid(nc))[,"X"]

Plot with ggplot (static)

library(ggplot2)

ggplot(nc) +
  geom_sf(aes(fill = density)) +
  geom_text(
    aes(x = lon, y = lat),
    label = paste0(nc$NAME, "\n", "(", nc$density, ")"),
    check_overlap = TRUE) +
  scale_fill_viridis_c() +
  theme_void()

Plot with leaflet (interactive)

library(leaflet)
library(viridis)

pal <- colorNumeric(viridis_pal(option = "C")(2), domain = nc$density)

leaflet() %>%
  addProviderTiles("CartoDB.Positron") %>%
  setView(-80, 34.5, zoom = 6.2) %>% 
  addPolygons(
    data = nc,
    fillColor = ~pal(nc$density),
    fillOpacity = 0.8,
    weight = 0.2,
    smoothFactor = 0.2,
    popup = ~density) %>%
  addLabelOnlyMarkers(
    lng = nc$lon,
    lat = nc$lat,
    label = paste0(nc$NAME, "\n", "(", nc$density, ")"),
    #label = "LABEL",
    labelOptions = labelOptions(noHide = T, textOnly = TRUE)) %>%
  addLegend(
    pal = pal,
    values = nc$density,
    position = "bottomright",
    title = "Density")
like image 2
Skaqqs Avatar answered Oct 20 '22 05:10

Skaqqs


Using tmap in view-mode allows to reach nearly what you want (shapes are used via the urbnmapr package):

library(tidyverse)
library(tmap)
library(sf)
library(urbnmapr)

states <- get_urbn_map("states", sf = T) %>%  
  as.tibble() %>% 
  mutate(density = sample(1:100, 51, replace = T)) %>% 
  mutate(abbvAndDens = str_c(state_abbv, " (", density, ")")) %>% 
  st_as_sf() 

tmap_mode("view")
tm_shape(states) +
tm_fill("density",
        palette = "viridis",
        style = "cont",
        breaks = seq(0, 100, 20)) +
tm_borders(lwd = .5, col = "black") +
tm_text("abbvAndDens", size= .75, col = "black")

enter image description here

like image 2
mgrund Avatar answered Oct 20 '22 05:10

mgrund