Package: RGraphSpace 1.4.4

Overview

This vignette demonstrates how to use RGraphSpace to visualize graph data within a spatial coordinate system. The example uses Brazilian aviation data, in which airports are represented as nodes and flights as directed edges.

This workflow is useful when graph elements need to be positioned according real-world coordinates, such as latitude and longitude, rather than an abstract graph layout. For visualization, RGraphSpace integrates ggplot2 and sf packages, allowing graph elements to be displayed together with geographic boundaries.

If you are not familiar with the basic structure of GraphSpace objects, we recommend consulting the interoperability vignette first.

Data and workflow overview

This vignette uses preprocessed data, which are: flights records, active Brazilian airports and geographical boundaries of Brazil, and the Brazil’s Southeast Region. For full reproducibility, the data-loading and filtering procedures are described in the Preprocessing Aviation Data vignette. The present example uses Brazilian flight records from 2024.

All source data and code used during preprocessing are available in the Preprocessing Aviation Data GitHub repository.

After the data are loaded, an igraph object is constructed by representing airports as vertices and flights as directed edges. The resulting graph is then converted into a GraphSpace object. Finally, a multilayered figure is constructed with ggplot2 (Wickham 2016) by combining several sf objects with RGraphSpace geometric layers (geoms).

Before you start

Computational requirement:

  • Hardware: RAM >= 12 GB

  • Software: R (>=4.5) and RStudio

Required Packages

# Check required packages for this vignette
if(!require("ggplot2", quietly = TRUE)){install.packages("ggplot2")}
if(!require("dplyr", quietly = TRUE)){install.packages("dplyr")}
if(!require("sf", quietly = TRUE)){install.packages("sf")}
if(!require("rnaturalearth", quietly = TRUE)){install.packages("rnaturalearth")}
if(!require("igraph", quietly = TRUE)){install.packages("igraph")}
if(!require("maps", quietly = TRUE)){install.packages("maps")}
if(!require("ggpubr", quietly = TRUE)){install.packages("ggpubr")}
if(!require("ggrepel", quietly = TRUE)){install.packages("ggrepel")}
if(!require("rnaturalearthhires", quietly = TRUE)){
  remotes::install_github("ropensci/rnaturalearthhires")}
if(!require("RGraphSpace", quietly = TRUE)){
  remotes::install_github("sysbiolab/RGraphSpace", build_vignettes=TRUE)}
# Load packages
library("RGraphSpace")
library("ggplot2")
library("dplyr")
library("sf")
library("igraph")
library("ggrepel")
library("ggpubr")

Brazil-wide flight network

Loading data

Here, we need to load the preprocessed RData.

rdata_url <- paste0(
  "https://raw.githubusercontent.com/",
  "flaviogckessler/PreprocessingAviationData/",
  "main/data/sf_brazilflights.RData")

rdata_file <- tempfile(fileext = ".RData")
download.file(url = rdata_url,destfile = rdata_file,
  mode = "wb",quiet = TRUE)

loaded_objects <- load(rdata_file)
loaded_objects
#> [1] "active_airports" "flights_cf"      "mapa_brasil"

rm(rdata_url,rdata_file,loaded_objects)

The loaded data comprise:

  1. Active Brazilian airports in the selected year (active_airports)

  2. Filtered flight records (flights_cf)

  3. The geographic boundaries of Brazil (mapa_brasil)

Building the graph

Creating an igraph object

Once the data have been loaded and filtered, the flight and airport datasets are fully compatible. We can therefore generate an igraph object using the flights as edges and the airports as vertices (nodes). To preserve the direction of each departure-arrival pair, the graph is directed. Moreover, the edges are weighted because we have the number of flights of each unique route.

graph_flights <- graph_from_data_frame(flights_cf,
                                       directed = TRUE,
                                       vertices = active_airports)

Converting igraph to GraphSpace

With the igraph object, we can readily convert it to a GraphSpace object using GraphSpace() function. The object is an S4 class, its nodes spot must contain columns named x and y for further usage of RGraphSpace geoms.

Although the coordinate system of an GraphSpace object is generally normalized to values between 0 and 1, here we keep the original latitude and longitude values. This is necessary because the graph coordinates must align with the sf object.

gs_flight <- GraphSpace(graph_flights)
gs_flight@nodes$x <- gs_flight@nodes$longitude
gs_flight@nodes$y <- gs_flight@nodes$latitude

Visualizing spatial networks

g <- ggplot() +
  geom_sf(data=mapa_brasil, fill="light grey", color="dark grey", size=.15, show.legend = FALSE) +
  geom_edgespace(aes(colour = log10(weight)), arrow_size = 0.5, 
                 arrow_offset = 0.01, data = gs_flight) + 
  scale_colour_continuous(palette = c("cyan","blue")) +
  geom_nodespace(aes(fill=type),size=1.5,data = gs_flight) +
  scale_fill_discrete(palette = c("#00BFC4","#F8766D")) + 
  labs(subtitle="Domestic flights in Brazil in 2024",colour="Log10 (n°of flights)",
       y = "Latitude",x= "Longitude",fill="Type") +
  theme_gspace_legend(key_fill = TRUE)+
  theme_minimal()

g

The figure above uses two geoms from RGraphSpace: (i) geom_edgespace(), and (ii) geom_nodespace(). Colour and fill aesthetics are used for edges and nodes mapping, respectively. Moreover, the figure followes the ggplot2 grammar and demonstrates interoperability with the sf package. In the next plot, additional aesthetics mappings are used.

Southeast regional network

Next, we create a regional subset focusing on the airports from the Brazil’s Southeast Region, which includes some of the busiest airports in the country. The goal is to examine the relationship between flight frequency and the population of the city served by each airport.

Load the preprocessed data

rdata_url <- paste0(
  "https://raw.githubusercontent.com/",
  "flaviogckessler/PreprocessingAviationData/",
  "main/data/sf_SoutheastFlights.RData")

rdata_file <- tempfile(fileext = ".RData")
download.file(url = rdata_url,destfile = rdata_file,
  mode = "wb",quiet = TRUE)

loaded_objects <- load(rdata_file)
loaded_objects
#> [1] "se_airports" "se_flights"  "se_states"

rm(rdata_url,rdata_file,loaded_objects)

The loaded data comprise:

  1. Active airports in Brazil’s Southeast Region during the selected year (se_airports)

  2. Filtered flight records for Brazil’s Southeast Region (se_flights)

  3. The geographic boundaries of Brazil’s Southeast Region (se_states)

Building the graph

Creating an igraph object

graph_se_flights <- graph_from_data_frame(se_flights,
                                       directed = TRUE,
                                       vertices = se_airports)

Converting igraph to GraphSpace

gs_se_flight <- GraphSpace(graph_se_flights)
gs_se_flight@nodes$x <- gs_se_flight@nodes$longitude
gs_se_flight@nodes$y <- gs_se_flight@nodes$latitude

Visualizing spatial networks

h <- ggplot() +
  geom_sf(data=se_states, fill="light grey", color="red", size=.5, show.legend = FALSE) +
  coord_sf(xlim = c(-53,-40))+
  geom_edgespace(aes(colour = log10(weight),linewidth=log10(weight)), arrow_size = 0.5, 
                 arrow_offset = 0.05, data = gs_se_flight) + 
  scale_colour_continuous(palette = c("cyan","blue")) +
  scale_linewidth(guide='none')+
  geom_nodespace(aes(fill=type,size = pop),data = gs_se_flight) +
  geom_label_repel(aes(label = gs_se_flight@nodes$name,
                       x=gs_se_flight@nodes$x,
                       y=gs_se_flight@nodes$y),
                   box.padding   = 0.35, 
                   point.padding = 0.5,
                   size = 3,
                   segment.color = 'grey50') +
  scale_size(range = c(1,10)) +
  scale_fill_discrete(palette = c("#F8766D","#00BFC4")) +  
  inject_nodespace() +
  labs(subtitle="Domestic flights in Brazil's Southeast Region in 2024",colour="Log10 (n°of flights)",
       y = "Latitude",x= "Longitude",fill="Type",size="Population",linewidth=NULL) +
  theme_gspace_legend(key_fill = TRUE)+
  theme_minimal()

h

This plot uses colour and linewidth aesthetics for edges and fill and size aesthetics for nodes. The utility function inject_nodespace() transfer node-size information to the edge layer, enabling it to become “node-aware” prior to final rendering. Therefore, the arrows can align with node when node sizes vary.

Combining plots

Generation a geometry union with all Southeast region states:

single_sf <- st_union(se_states$geometry[1]) %>%
  st_union(se_states$geometry[2]) %>%
  st_union(se_states$geometry[3]) %>%
  st_union(se_states$geometry[4])

Final figure arrangement:

g <- g + geom_sf(data=single_sf, fill="light grey", color="red",alpha=0, size=1, show.legend = FALSE)

ggarrange(g,h,
          labels = c("A","B"),
          font.label = list(size=22,face="bold"),
          ncol = 2,nrow=1)

Saving figure:

png('Flights_RGraphSpace.png', units="in", width=12, height=6, res=300)
ggarrange(g,h,
          labels = c("A","B"),
          font.label = list(size=22,face="bold"),
          ncol = 2,nrow=1)
dev.off()
#> png 
#>   2

Citation

If you use RGraphSpace, please cite:

  • Sysbiolab Team (2026). RGraphSpace: A lightweight interface between ‘igraph’ and ‘ggplot2’ graphics. R package version 1.2.4. DOI: 10.32614/CRAN.package.RGraphSpace

Session information

#> R version 4.6.1 (2026-06-24 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 11 x64 (build 26200)
#> 
#> Matrix products: default
#>   LAPACK version 3.12.1
#> 
#> locale:
#> [1] LC_COLLATE=Portuguese_Brazil.utf8  LC_CTYPE=Portuguese_Brazil.utf8   
#> [3] LC_MONETARY=Portuguese_Brazil.utf8 LC_NUMERIC=C                      
#> [5] LC_TIME=Portuguese_Brazil.utf8    
#> 
#> time zone: America/Sao_Paulo
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#>  [1] maps_3.4.3                    ggpubr_1.0.0                  ggrepel_0.9.8                
#>  [4] igraph_2.3.3                  RGraphSpace_1.4.4             rnaturalearthhires_1.0.0.9000
#>  [7] rnaturalearth_1.2.0           sf_1.1-1                      dplyr_1.2.1                  
#> [10] airportr_0.1.3                ggplot2_4.0.3                 data.table_1.18.4            
#> [13] flightsbr_1.1.1              
#> 
#> loaded via a namespace (and not attached):
#>  [1] tidyselect_1.2.1   vipor_0.4.7        farver_2.1.2       S7_0.2.2           fastmap_1.2.0     
#>  [6] janitor_2.2.1      digest_0.6.39      timechange_0.4.0   lifecycle_1.0.5    magrittr_2.0.5    
#> [11] compiler_4.6.1     rlang_1.3.0        sass_0.4.10        tools_4.6.1        yaml_2.3.12       
#> [16] knitr_1.51         ggsignif_0.6.4     labeling_0.4.3     classInt_0.4-11    curl_7.1.0        
#> [21] xml2_1.6.0         RColorBrewer_1.1-3 abind_1.4-8        KernSmooth_2.23-26 withr_3.0.3       
#> [26] purrr_1.2.2        grid_4.6.1         e1071_1.7-17       scales_1.4.0       cli_3.6.6         
#> [31] rmarkdown_2.31     generics_0.1.4     remotes_2.5.0      otel_0.2.0         httr_1.4.8        
#> [36] DBI_1.3.0          ggbeeswarm_0.7.3   cachem_1.1.0       proxy_0.4-29       stringr_1.6.0     
#> [41] rvest_1.0.5        selectr_0.6-0      s2_1.1.11          ggrastr_1.0.2      vctrs_0.7.3       
#> [46] Matrix_1.7-5       jsonlite_2.0.0     carData_3.0-6      car_3.1-5          rstatix_1.0.0     
#> [51] Formula_1.2-5      archive_1.1.13     beeswarm_0.4.0     jquerylib_0.1.4    tidyr_1.3.2       
#> [56] units_1.0-1        glue_1.8.1         cowplot_1.2.0      lubridate_1.9.5    stringi_1.8.7     
#> [61] gtable_0.3.6       tibble_3.3.1       pillar_1.11.1      parzer_0.4.4       htmltools_0.5.9   
#> [66] R6_2.6.1           wk_0.9.5           tidygraph_1.3.1    evaluate_1.0.5     lattice_0.22-9    
#> [71] backports_1.5.1    broom_1.0.13       snakecase_0.11.1   bslib_0.11.0       class_7.3-23      
#> [76] Rcpp_1.1.2         xfun_0.60          fs_2.1.0           pkgconfig_2.0.3

References

Wickham, Hadley. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org.