library(plotly)
# ── Zone centroids (approximate geographic centres) ──────────────────
zone_coords <- tribble(
~zone, ~lat, ~lon, ~label,
"DE_LU", 51.0, 10.0, "DE-LU",
"FR", 46.5, 2.5, "FR",
"NL", 52.0, 5.5, "NL",
"BE", 50.8, 4.5, "BE",
"AT", 47.5, 14.0, "AT",
"DK_1", 56.0, 9.5, "DK1",
"DK_2", 55.5, 12.0, "DK2",
"NO_1", 60.0, 10.5, "NO1",
"NO_2", 59.0, 6.0, "NO2",
"NO_3", 63.5, 10.5, "NO3",
"NO_4", 68.0, 15.5, "NO4",
"NO_5", 60.5, 6.5, "NO5",
"SE_1", 66.0, 18.0, "SE1",
"SE_2", 63.0, 16.0, "SE2",
"SE_3", 59.0, 16.0, "SE3",
"SE_4", 56.5, 14.5, "SE4",
"FI", 62.0, 26.0, "FI"
)
# ── DE-LU correlations ──────────────────────────────────────────────
delu_corr <- tibble(
zone = rownames(price_matrix),
corr_de_lu = price_matrix[, "DE_LU"]
) |>
filter(zone != "DE_LU") |>
left_join(zone_coords, by = "zone")
delu_point <- zone_coords |> filter(zone == "DE_LU")
# ── Colour mapping (sequential warm) ────────────────────────────────
corr_to_colour <- colorRamp(c("#F7F7F7", "#FDDBC7", "#EF8A62", "#B2182B"))
delu_corr <- delu_corr |>
mutate(
colour_rgb = map_chr(corr_de_lu, \(x) {
rgb_vals <- corr_to_colour(x)
sprintf("rgb(%d,%d,%d)",
round(rgb_vals[1]), round(rgb_vals[2]), round(rgb_vals[3]))
}),
hover_text = paste0(
"<b>", label, "</b><br>",
"Correlation with DE-LU: <b>", sprintf("%.2f", corr_de_lu), "</b>"
)
)
# ── Country-level averages for choropleth background ────────────────
zone_to_iso3 <- tribble(
~zone, ~iso3,
"FR", "FRA", "NL", "NLD", "BE", "BEL", "AT", "AUT",
"DK_1", "DNK", "DK_2", "DNK",
"NO_1", "NOR", "NO_2", "NOR", "NO_3", "NOR", "NO_4", "NOR", "NO_5", "NOR",
"SE_1", "SWE", "SE_2", "SWE", "SE_3", "SWE", "SE_4", "SWE",
"FI", "FIN"
)
country_corrs <- delu_corr |>
left_join(zone_to_iso3, by = "zone") |>
group_by(iso3) |>
summarise(corr_de_lu = mean(corr_de_lu), .groups = "drop") |>
bind_rows(tibble(iso3 = "DEU", corr_de_lu = 1.0))
# ── Build plotly geo map (responsive sizing) ──────────────────────────
fig <- plot_geo(height = 700) |>
# Choropleth background — country polygons filled by correlation
add_trace(
type = "choropleth",
locations = country_corrs$iso3,
z = country_corrs$corr_de_lu,
colorscale = list(
c(0, "rgb(222,235,247)"),
c(0.25, "rgb(247,247,247)"),
c(0.5, "rgb(253,208,162)"),
c(0.75, "rgb(227,120,71)"),
c(1, "rgb(178,24,43)")
),
zmin = 0.15, zmax = 1,
marker = list(line = list(color = "rgb(180,180,180)", width = 1)),
colorbar = list(title = "Correlation", len = 0.4, y = 0.5),
hoverinfo = "none",
showlegend = FALSE
) |>
layout(
title = list(
text = "How Correlated Are European Electricity Prices with Germany?",
font = list(size = 16)
),
geo = list(
scope = "europe",
projection = list(type = "mercator"),
lonaxis = list(range = c(-5, 30)),
lataxis = list(range = c(44, 72)),
showland = TRUE, landcolor = "rgb(235,235,235)",
showocean = TRUE, oceancolor = "rgb(225,235,245)",
showcountries = TRUE, countrycolor = "rgb(180,180,180)",
showlakes = TRUE, lakecolor = "rgb(225,235,245)",
showcoastlines = TRUE, coastlinecolor = "rgb(180,180,180)",
resolution = 50
),
showlegend = FALSE,
autosize = TRUE,
margin = list(t = 60, b = 20)
)
# ── Connection lines from DE-LU to each zone ────────────────────────
for (i in seq_len(nrow(delu_corr))) {
row <- delu_corr[i, ]
fig <- fig |>
add_trace(
type = "scattergeo", mode = "lines",
lon = c(delu_point$lon, row$lon),
lat = c(delu_point$lat, row$lat),
line = list(
width = row$corr_de_lu * 4,
color = row$colour_rgb
),
opacity = 0.9,
hoverinfo = "none",
showlegend = FALSE
)
}
# ── Zone markers (sized and coloured by correlation) ─────────────────
fig <- fig |>
add_trace(
type = "scattergeo", mode = "markers+text",
data = delu_corr,
lon = ~lon, lat = ~lat,
marker = list(
size = ~corr_de_lu * 25 + 5,
color = ~colour_rgb,
line = list(width = 1.5, color = "white")
),
text = ~paste0(label, " (", sprintf("%.2f", corr_de_lu), ")"),
textposition = "top center",
textfont = list(size = 10, color = "rgb(50,50,50)"),
hovertext = ~hover_text,
hoverinfo = "text",
showlegend = FALSE
)
# ── DE-LU reference marker ──────────────────────────────────────────
fig <- fig |>
add_trace(
type = "scattergeo", mode = "markers+text",
lon = delu_point$lon, lat = delu_point$lat,
marker = list(
size = 16, color = "#B2182B", symbol = "diamond",
line = list(width = 2, color = "white")
),
text = "DE-LU", textposition = "top center",
textfont = list(size = 12, color = "black", family = "Arial"),
hovertext = "<b>DE-LU</b><br>Reference zone",
hoverinfo = "text",
showlegend = FALSE
)
fig