1

Using Eurostat I try to plot some values to the map of the EU, using the following code:

library(tidyverse)
library(eurostat)
library(leaflet)
library(sf)
library(scales)
library(cowplot)
library(ggthemes)

#----------- load dataset -----------
SHP <- get_eurostat_geospatial(resolution = 10, 
                        nuts_level = 0,
                        year = 2021)

#select EU countries only
EU28 <- eu_countries %>% 
  select(geo = code, name)
EU29 <- rbind(EU28, c("NO", "Norge"))  # add Norway since not EU country

SHP_29 <- SHP %>% 
  select(geo = NUTS_ID, geometry) %>% 
  inner_join(EU29, by = "geo") %>% 
  arrange(geo) %>% 
  st_as_sf()


# ------------ create values to map on EU --------------
test = data.table(
  geo=EU29$geo,
  values=c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29)
)
test <- SHP_29 %>% inner_join(test, by="geo") %>% arrange(geo) %>%  st_as_sf()
test$values <- as.numeric(test$values)
testSum= sum(test$values)


#---------- plot ---------- #
test %>% 
  ggplot(aes(fill=test$values)) +
  geom_sf() +
  geom_sf_text(aes(label=test$values)) +
  scale_fill_distiller(
    palette = 1,
    direction = 1,   # reverse default order
    name = "ID"
  ) +
  scale_x_continuous(limits = c(-10, 35)) +
  scale_y_continuous(limits = c(35, 70)) +
  labs(
    title = "Test",
    subtitle = sprintf("Countries=%s", testSum),
  ) +
  theme_void()

This results in a beautiful map. However, the value for Norway (=29) is not plotted on the map. Which is probably due to the second warning message obtained when plotting:

Warning messages:
1: In st_point_on_surface.sfc(sf::st_zm(x)) : st_point_on_surface may not give correct results for longitude/latitude data
2: Removed 1 rows containing missing values (geom_text).

Why does ggplot2 or eurostat skip plotting the value for Norway?

Stefan Verweij
  • 164
  • 2
  • 13
  • 1
    You have cut the number off for Norway by setting `scale_y_continuous`. If you remove this you will see the 29 is placed over Svalbard. – Allan Cameron Sep 06 '22 at 14:55

3 Answers3

1

The first warning is saying that you are plotting some points outside the continuous boundary limits you set.

Comment the two scale_#_continuous() lines and you will see #29 is being plotted on top of Svalbard, Norway, near the 80 degree North parallel!

Edit: The way to fix this is to "crop" the data first

crop_factor <- st_bbox(c(xmin = -10, 
                         xmax = 35, 
                         ymax = 35, 
                         ymin = 70),
                       crs = st_crs(test))

test_cropped <- st_crop(test, crop_factor)


test_cropped %>% 
  ggplot(aes(fill=values)) +
  geom_sf() +
  geom_sf_text(aes(label=values)) 

enter image description here

M.Viking
  • 5,067
  • 4
  • 17
  • 33
  • Ah snap, I already increased the limits, but not enough. Looks really weird now though. Would there be a way to have the number appear on the mainland Norway? – Stefan Verweij Sep 06 '22 at 15:54
  • 1
    Edited. Used the idea from https://stackoverflow.com/a/66032492/10276092 – M.Viking Sep 06 '22 at 16:09
1

The issue is caused by the fun.geometry argument of ggplot2::geom_sf_text() defaulting to point on surface; which can create issues such as when in your case the label is placed on Svarbald (off your limits).

A possible alternative is using centroid, which kind of helps - but it has its own issues, such as when the figure of France is plotted in Spain (due to pull of overseas France, likely the French Guiana).

The way out of this mess will be either:

  • removing invisible areas of map first (by doing sf::st_intersection() over your bounding box; this will cut Svarbald off and eliminate the issue
  • manually tweaking label placement via nudge_x and nudge_y arguments of the geom text call

I am sorry to report that with countries as irregularly shaped as Norway manual labeling is often unavoidable.

test %>% 
  ggplot(aes(fill=test$values)) +
  geom_sf() +
  geom_sf_text(aes(label=test$values),
               fun.geometry = \(x) sf::st_centroid(x , of_largest_polygon = T)) + # only change here
  scale_fill_distiller(
    palette = 1,
    direction = 1,   # reverse default order
    name = "ID"
  ) +
  scale_x_continuous(limits = c(-10, 35)) +
  scale_y_continuous(limits = c(35, 70)) +
  labs(
    title = "Test",
    subtitle = sprintf("Countries=%s", testSum),
  ) +
  theme_void()

enter image description here

Jindra Lacko
  • 7,814
  • 3
  • 22
  • 44
  • Tried this, but note that now France is placed in Spain.. I have found an answer for this issue which I will post asap. – Stefan Verweij Sep 06 '22 at 16:08
  • 1
    You can tweak the position of France by using centroid only of the largest polygon / which is Metropolitan France / but you will still likely need to tweak some data manually - Norway, Greece and Croatia are known troublemakers – Jindra Lacko Sep 06 '22 at 16:24
0

Besides the solution of @m-viking (which I did not try) it is also possible to alter the specific nudge of Norway (or any other country of interest) like this:

test2 <- test %>%
  mutate(my_nudge_x=ifelse(geo=='NO',-15,0) ,
         my_nudge_y=ifelse(geo=='NO',-20,0) ,
         geo = ifelse(geo=='NO','Nudged NO', geo)

test %>% 
  ggplot(aes(fill=test$values)) +
  geom_sf() +
  geom_sf_text(aes(label=test$values),
  nudge_x = test2%my_nudge_x,
  nudge_y = test2%my_nudge_y,
  ) +
  scale_fill_distiller(
    palette = 1,
    direction = 1,   # reverse default order
    name = "ID"
  ) +
  scale_x_continuous(limits = c(-10, 35)) +
  scale_y_continuous(limits = c(35, 70)) +
  labs(
    title = "Test",
    subtitle = sprintf("Countries=%s", testSum),
  ) +
  theme_void()

the coordinates for my_nudge_x and my_nudge_y were found using trial&error.

Thanks to https://community.rstudio.com/t/geom-sf-text-change-position-of-only-one-text-label/73419/4

Stefan Verweij
  • 164
  • 2
  • 13