Welcome to bubblegam! An R package to efficiently merge (geo)dataframes, identify, and move "spatial outliers" in geodata, create geographic plots, bubbleplots, and the animation between these plots.
Authors: Georg Starz (Code) & Anna Bischof (Code, Package Idea)
Contact: georg.starz@stud-mail.uni-wuerzburg.de & anna.bischof@stud-mail.uni-wuerzburg.de
Data source: Destatis
Data source: EDGAR
Data source: STATSAMERICA
The package was developed with R version 4.3.1 on Windows. Mac & Linux haven't been tested so far. To install and load bubblegam, enter these commands in your R console:
library(devtools)
install_github("Geo-99/bubblegam")
library(bubblegam)When testing the package we encountered some yet to be solved issues with two package dependencies. Therefore, for now, we recommend manually loading library(animation) & library(sf).
Here, we want to create this animation (based on a geopackage of the federal states of Spain and data on the GDP):
For a detailed description of all functions and their parameters, refer to the documentation, e.g. ?find_sim_change.
The source data is supplied with the installation of the package.spain_gdp is a data.frame and spain_gpkg is a sf data.frame.
We use the find_sim_change function to synchronize the names of the Spanish federal states for the subsequent merge function. There are three features, which are spelled slightly differently in the two datasets:
gdp_cleaned <- find_sim_change(df_main = spain_gpkg, df_main_col = "Texto",
df_change = spain_gdp, df_change_col = "CCAA")Then, we merge both dataframes with merge_gd_df:
spain_merged <- merge_gd_df(gdf_left = spain_gpkg, id_left = "Texto",
df_right = gdp_cleaned, id_right = "CCAA")
Optional: "Spatial outliers" in the geodata (in this case the Canary Islands) can complicate the map display. To automatically identify and then delete/define these outliers use outlier_identify and answer the prompts in the console (warnings may be displayed, which can be ignored):
spain_merged_outliers <- outlier_identify(geodata = spain_merged, id_col = "Texto")If the Canary Islands were defined as an outlier, their multipolygon can be "moved closer" towards mainland Spain using outlier_moving:
spain_merged_moved <- outlier_moving(geodata = spain_merged_outliers)
Use create_bubbles to create the bubble geodata:
spain_bubbles <- create_bubbles(merged_gdf = spain_merged_moved, col_name = "PIB_anual_EURO")We define the plot limit coordinates by referring to both geodataframes (map & bubbles) using define_limits. Note: This is done to ensure a consistent plot extent within the animation:
spain_limits_combined <- define_limits(data_start = spain_merged_moved, data_end = spain_bubbles)Next, we can create our start and bubble plot with plot_cont (you can then save the plots using ggsave()):
spain_plot <- plot_cont(gdf = spain_merged_moved, column = "PIB_Per_Capita_EURO",
plot_limits = spain_limits_combined,
fill_colorscale = c("lightyellow", "#f1434a","darkred"),
legend_limits = c(20000,40000),
edge_color = "#323232", edge_width = 0.1,
legend_text = 14,
title = "GDP per Capita in Spain 2022 [€]",
title_size = 24)
spain_plot
bubbles_plot <- plot_cont(gdf = spain_bubbles, column = "PIB_Per_Capita_EURO",
plot_limits = spain_limits_combined,
fill_colorscale = c("lightyellow", "#f1434a","darkred"),
legend_limits = c(20000,40000),
edge_color = "#323232", edge_width = 0.1,
legend_text = 14,
title = "GDP per Capita in Spain 2022 [€]\n→ Bubble Size: Total GDP per state",
title_size = 24)
bubbles_plot
Now, to start the creation of the animation, we first need to calculate the transition steps between spain_gdp_moved and spain_bubbles by using create_transition (warnings may be displayed, which can be ignored):
spain_transition <- create_transition(gdf = spain_merged_moved, bubble_gdf = spain_bubbles,
color_col = "PIB_Per_Capita_EURO", bubble_col = "PIB_anual_EURO")
anim_cont_raw is used to create the raw animation (slow sequence of all frames) and save it. Note: all parameters from plot_limits onwards are based on plot_cont:
anim_cont_raw(transition_df = spain_transition, path_file_name = "path/to/anim_raw.gif",
anim_width = 1900, anim_height = 2000, anim_res = 400,
plot_limits = spain_limits_combined,
fill_colorscale = c("lightyellow", "#f1434a","darkred"),
legend_limits = c(20000,40000),
edge_color = "#323232",
legend_text = 10,
title = "GDP per Capita in Spain 2022 [€]\n→ Bubble Size: Total GDP per state",
title_face = "bold", title_size = 15)To define the frames per second of the animation and add a delay at the start and end plot use anim_finalize:
anim_finalize(anim_raw = "path/to/anim_raw.gif", anim_path_file = "path/to/anim_final.gif",
fps_anim = 10, delay_anim = TRUE, delay_frames = 60)
Creating the animation can be quite time-intensive depending on the input data. As an alternative, you can use the following code to create a higher-resolution animation (execute as a whole). However, in our experience, this takes even longer:
library(magick)
img <- image_graph()
datalist <- split(spain_transition, spain_transition$.frame)
sf_datalist <- lapply(datalist, function(datalist) st_as_sf(datalist))
out <- lapply(sf_datalist, plot_cont,
column = "v_plot1", plot_limits = spain_limits_combined,
fill_colorscale = c("lightyellow", "#f1434a","darkred"),
legend_limits = c(20000,40000),
edge_color = "#323232", edge_width = 0.2,
legend_text = 14,
title = "GDP per Capita in Spain 2022 [€]\n→ Bubble Size: Total GDP per state",
title_face = "bold", title_size = 24)
out
dev.off()
animation <- image_animate(img, fps = 10)
animation_delayed <- animation[c(rep(1, each = 60), 2:(length(datalist)-1), rep(length(datalist), each = 60))]
image_write(animation, "path/to/anim_fps.gif")
image_write(animation_delayed, "path/to/anim_fps_delayed.gif")
- We are happy if you find our bubblegam package useful! When using it, please link our repo (e.g., like so: bubblegam R package, https://github.com/Geo-99/bubblegam)
- Feel free to send us plots and animations that you have created with bubblegam :)
- We are sure there are many possible code improvements. We're looking forward to any suggestions you might have!
- 4 bubblegam functions weren't shown in the Spain GDP example:
merge_df_dfenables inner merge of dataframes similar tomerge_gd_dfoutlier_restructurereincludes moved outlier subfeaturesplot_discr: same asplot_contbut for discrete dataanim_discr_raw: same asanim_cont_rawbut for discrete data
We are currently working on extending the functionality of bubblegam. Below you can find a list on what we are working on.
- Function to create an animation between different plots or images. The aim is to facilitate the morph transition between the plots.

- If your geodata uses a geographic and not a projected CRS, the bubbles can turn into ellipses in the plots/animations. Therefore, we recommend reprojecting it beforehand using
st_transform().
- To be continued ...
This package is inspired by and partly based on zumbov2's Switzerland version of Karim Douïeb's famous vizualization Land Doesn't Vote... People Do.
We want to thank Dr. Martin Wegmann and the Earth Observation Research Cluster's DevLab for the support and feedback during the development of the package.
This is a submission for the course Introduction to Programming and Statistics for Remote Sensing and GIS as part of the M.Sc. EAGLE program at the University of Würzburg.










