My vacation (and a little introduction to GeoPandas)

Hello everyone,

I’m currently on vacation, so today I won’t be talking about genetics. Instead, I’ll talk about myself.
This year, as in my previous trip, I visited the largest country in South America—the land of Pelé, the King of Football. If you don’t know who Pelé is, you’re probably calling the real football (a sport where players predominantly use their feet to kick a ball) “soccer” and referring to a sport that primarily involves carrying a prolate spheroid with hands as “football”. To avoid confusion, I propose renaming the latter to handspheroid. It’s also the land of Santos Dumont, the father of airplanes. Yes, I am talking about Brazil.

The best way to introduce it is by showing a map. Since we need to be mindful of intellectual property, let’s use a Python library called GeoPandas to create the map.

# Install GeoPandas
!pip install geopandas

# Import necessary libraries
import geopandas as gpd
import matplotlib.pyplot as plt
import pandas as pd

Next, we need to load some map data. I recommend downloading datasets from the Natural Earth website. According to their website: “Natural Earth is a public domain map dataset available at 1:10m, 1:50m, and 1:110 million scales. Featuring tightly integrated vector and raster data, with Natural Earth you can make a variety of visually pleasing, well-crafted maps with cartography or GIS software.”

Now, let’s introduce Brazil by first loading a “world map.”

# Load the world map
world = gpd.read_file("ne_10m_admin_0_countries.zip")

This action creates a Pandas-like GeoDataFrame with 169 columns containing a wealth of geographic and political information. Since we’re focusing on Brazil, let’s narrow it down by plotting only South America.

Here’s the code to create a map showing South America:

# Create a plot
fig, gax = plt.subplots(figsize=(20, 20))

# Query only South America using the CONTINENT column
world.query("CONTINENT == 'South America'").plot(ax=gax, edgecolor='black')

The current map includes too many countries, making it hard to focus on Brazil. To fix this, let’s plot only Brazil and use a color inspired by the Brazilian flag

fig, gax = plt.subplots(figsize=(20,20))

# Use green on edge and yellow on the color
world.query("NAME_EN == 'Brazil'").plot(ax=gax, edgecolor='#009739', color='#FEDD00')

Now, let’s map the airports involved in my trip so far. We’ll use the ne_10m_airports dataset to get airport coordinates and plot them on the map.

# Create the plot
fig, gax = plt.subplots(figsize=(20, 20))

# Load airport coordinates
airport = gpd.read_file("ne_10m_airports.zip")

# Get specific airport locations by their abbreviations
CLE = airport.query("abbrev == 'CLE'")["geometry"]
JFK = airport.query("abbrev == 'JFK'")["geometry"]
GIG = airport.query("abbrev == 'GIG'")["geometry"]

# Plot the map (North and South America)
world.query("CONTINENT == 'South America' or CONTINENT == 'North America'").plot(ax=gax, edgecolor='black', color="#009739")  # Green background

# Annotate the airports
plt.annotate(text="CLE", xy=(CLE.x, CLE.y), horizontalalignment='center', fontsize=30, color="red")
plt.annotate(text="JFK", xy=(JFK.x, JFK.y), horizontalalignment='center', fontsize=30, color="red")
plt.annotate(text="GIG", xy=(GIG.x, GIG.y), horizontalalignment='center', fontsize=30, color="red")

# Focus the map on a specific region by limiting x-coordinates
gax.set_xlim((-130, -30))

# Show the plot
plt.show()

Let’s make the map cleaner and more visually appealing. First, we’ll exclude Canada from the map to focus only on the regions relevant to the trip. Next, we’ll simplify the color scheme by using a neutral light gray for the background, as the previous green added too much visual noise. To further enhance clarity, we’ll remove unnecessary elements like axis lines, ticks, and labels. We will also mark the coordinates using red and blue points with the large text for a cleaner and more modern look. Finally, we’ll adjust the map view to focus on the region that covers the United States and South America, ensuring all the airports involved in the trip are clearly visible.

fig, gax = plt.subplots(figsize=(20,20))

#Get airport coodinates
airport = gpd.read_file("ne_10m_airports.zip")

CLE = airport.query("abbrev == 'CLE'")["geometry"]
JFK = airport.query("abbrev == 'JFK'")["geometry"]
GIG = airport.query("abbrev == 'GIG'")["geometry"]

#Select all American countires except Canada
world.query("(CONTINENT == 'South America' or CONTINENT == 'North America') and NAME_EN != 'Canada'").plot(ax=gax, edgecolor='black', color = "#d9dad8")


#Plot the airport name
plt.annotate(text="CLE", xy=(CLE.x, CLE.y), horizontalalignment='center',verticalalignment="top", size=30)
plt.annotate(text="JFK", xy=(JFK.x, JFK.y), horizontalalignment='center', size=30)
plt.annotate(text="GIG", xy=(GIG.x, GIG.y), horizontalalignment='center', size=30)

#Plot the airport as red point (US) and blue (BR)
CLE.plot(ax=gax, color='red', alpha = 1, markersize = 100)
JFK.plot(ax=gax, color='red', alpha = 1, markersize = 100)
GIG.plot(ax=gax, color='blue', alpha = 1, markersize = 100)

#Cut the plot and remove guides
gax.set_xlim((-130, -30))
gax.set_ylim((-60, 50))
gax.set_axis_off()

Now let’s focus on my vacation! Brazil is a vast country with 26 states, and while it would be amazing to visit them all, I’ll focus on just a few key destinations this time.

The journey starts in Rio de Janeiro, where I’ll handle visa obligations and enjoy the famous beauty of the Rio de Janeiro city. From there, I’ll travel to Minas Gerais, a state known for its rich culture, historical towns, and delicious cuisine. I’ll visit two cities there before heading to Paraná for a very special occasion—my brother’s wedding!

To visualize this itinerary, let’s create a map highlighting these states and marking the key cities I’ll visit along the way.

First get the states from Brazil

world = gpd.read_file("ne_10m_admin_1_states_provinces.zip")

fig, gax = plt.subplots(figsize=(20,20))

world.query("iso_a2 == 'BR'").plot(ax =gax, edgecolor='black', color = "#d9dad8")
gax.set_axis_off()

Now, let’s color the states where I will visit

#load map
world = gpd.read_file("ne_10m_admin_1_states_provinces.zip")

fig, gax = plt.subplots(figsize=(20,20))
#Get all BR states
world.query("iso_a2 == 'BR'").plot(ax =gax, edgecolor='black', color = "#d9dad8")
#Color RJ, MG and PR following the state flag color
world.query("iso_a2 == 'BR' and iso_3166_2 == 'BR-RJ'").plot(ax =gax, edgecolor='black', color = "#00AFEF")
world.query("iso_a2 == 'BR' and iso_3166_2 == 'BR-MG'").plot(ax =gax, edgecolor='black', color = "red")
world.query("iso_a2 == 'BR' and iso_3166_2 == 'BR-PR'").plot(ax =gax, edgecolor='black', color = "white")
gax.set_axis_off()

Now, let’s take a closer look at the cities on my tour. I’ve gathered the coordinates for each city and will label them in the order I plan to visit them.

RJ = (-43.2096, -22.9035)
CL = (-43.7855, -20.6597)
DV = (-44.8872, -20.1394)
GU = (-51.4562, -25.3935)
CB = (-49.2733, -25.4284)
BH = (-43.9542, -19.8157)

world = gpd.read_file("ne_10m_admin_1_states_provinces.zip")


fig, gax = plt.subplots(figsize=(20,20))

world.query("iso_a2 == 'BR'").plot(ax =gax, edgecolor='black', color = "#d9dad8")
world.query("iso_a2 == 'BR' and iso_3166_2 == 'BR-RJ'").plot(ax =gax, edgecolor='black', color = "#00AFEF")
world.query("iso_a2 == 'BR' and iso_3166_2 == 'BR-MG'").plot(ax =gax, edgecolor='black', color = "red")
world.query("iso_a2 == 'BR' and iso_3166_2 == 'BR-PR'").plot(ax =gax, edgecolor='black', color = "white")
plt.annotate(text="1", xy=RJ, horizontalalignment='left', size=25, xytext= (-43, -22.7), color = "black")
plt.annotate(text="2", xy=CL, horizontalalignment='left', size=25, color = "white")
plt.annotate(text="3", xy=DV, horizontalalignment='left', size=25, color = "white")
plt.annotate(text="4", xy=GU, horizontalalignment='left', size=25, color = "blue")
plt.annotate(text="5", xy=CB, horizontalalignment='left', size=25, color = "blue")
plt.annotate(text="6", xy=BH, horizontalalignment='left', size=25, color = "white")

gax.set_xlim((-60, -40))
gax.set_ylim((-30, -5))
gax.set_axis_off()

If you’re in any of these cities, please feel free to come and say hello!

Thank you, everyone! See you in the next post (probably about genetics—I’m definitely not a good travel influencer)

Thiago Peixoto Leal

4 Likes

You’ve taken map-making to a whole new level! This is an excellent tool for anyone who struggles, like me, to place pins on a map from memory. Also, long live football, much more exciting than handspheroid.

3 Likes