Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions examples/miscellanea/simpsons-monorail-map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
"""
Recreation of the Monorail Map from The Simpsons
------------------------------------------------

This example demonstrates how to create a minimal outline map of a
defined area of land such as a continent, with optional labels at
specified locations within the region, in the form of a recreation of the
Monorail Map from The Simpsons with humorously oversized labelling (to
imitate handwriting/scribbles) and sparsity of marked locations
(which are all fictional).

Specifically, it aims to recreate to best likeness using Cartopy
the map of pre-Springfield Lyle Lanley Monorail locations from the
iconic episode 'Marge vs. the Monorail' (1993) of the TV Series, as
taken in likeness from the screen grab available at:
https://simpsons.fandom.com/wiki/Brockway.

"""

import matplotlib.pyplot as plt
from matplotlib.transforms import offset_copy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from matplotlib.transforms import offset_copy

Unused import


import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
from matplotlib.patches import Rectangle
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from matplotlib.patches import Rectangle

Unused import



# Define choices for projection and locations to plot
GEOM_PROJ = ccrs.PlateCarree()
# Not real places, so locations pulled from location on map in still image
# First value 2-tuple is the dot placemap location, second is where to write
# the text label relative to that dot, to best match the map from the show.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment that the integer is text rotation?

LOCATIONS_TO_PLOT = {
"Ogdenville": [(-111.8, 35.5), (1.5, -2.2), -6],
"North\nHaverbrook": [(-99.0, 43.5), (2.8, -0.5), -1],
"Brockway": [(-80.4, 33.6), (-3.4, -1.5), 3],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the second tuple here is expressed in degrees. If it was expressed in points then annotate could take xy=loc_coords, xytext=rel_text_pos.

Feel free to push back if there is a reason not to do that!

}


def main():
# Set up a plot with a light blue background and a white overall border.
# For proportions of land mass, font size and border to be as
# intended, need to keep 'figsize' and 'dpi' (4:3 ratio) as below.
fig = plt.figure(
figsize=(9, 7.5),
dpi=125,
facecolor="#AFCBBD",
edgecolor="white", # sets up white border without need for another axes
linewidth=30, # makes the border thicker as per original map
)
map_ax = fig.add_axes(
[0.035, 0.035, 0.93, 0.93], projection=ccrs.LambertConformal(), frameon=False
)

# Center on location of USA with a bit of space on all sides to pad
map_ax.set_extent([-120, -72.5, 20, 50], crs=ccrs.Geodetic())

# Plot only the USA landmass, in a fawn colour with a thin black border
shpfilename = shpreader.natural_earth(
resolution="110m", category="cultural", name="admin_0_countries"
)
countries = shpreader.Reader(shpfilename).records()
usa_border = [
country.geometry
for country in countries
if (country.attributes["NAME"] == "United States of America")
]
map_ax.add_geometries(
usa_border,
GEOM_PROJ,
facecolor="#C39B6A",
edgecolor="black",
)

# Now add the location labels one by one
for loc_name, loc_details in LOCATIONS_TO_PLOT.items():
loc_coords, rel_text_pos, text_rot = loc_details
map_ax.plot(
*loc_coords,
marker="o",
color="black",
markersize=6,
transform=GEOM_PROJ,
)

# Adjust position of location name text relative to location marker
text_loc_coords = (
loc_coords[0] + rel_text_pos[0],
loc_coords[1] + rel_text_pos[1],
)
# Text in uppercase, very bold handwriting-like font, as per the
# screen grab of the map from the show
map_ax.annotate(
loc_name.upper(),
xy=text_loc_coords,
transform=ccrs.Geodetic(),
xytext=(-25, 0), # shift text closer to point as per reference
textcoords="offset pixels",
verticalalignment="center",
horizontalalignment="left",
fontname="Charcoal", # ensure you have this font available
fontweight="black",
fontsize=28,
rotation=text_rot, # slightly wonky text for handwritten effect
)

leg_text = (
"Pre-Springfield Lanley\nMonorail locations in TV's\nThe Simpsons\n"
"(recreation of map at\nsimpsons.fandom.com/\nwiki/Brockway)"
)

# Add the bottom left 'compass' legend in spirit of the original map.
map_ax.text(
0.14,
0.10,
leg_text,
transform=map_ax.transAxes,
fontsize=11,
horizontalalignment="center",
verticalalignment="center",
style="italic",
bbox=dict(facecolor="#A5B5CE"),
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: could consider using AnchoredText here if you want the legend text right in the corner.


plt.show()


if __name__ == "__main__":
main()
Loading