R
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Data Structures
-
Section 4: Data Manipulation
-
Section 5: Visualization and Statistics
-
Section 6: Advanced R
-
Section 7: Practical Projects
-
Section 8: Interview Practice
-
Section 9: More Practice Exercises
-
Section 10: Shiny Apps in Depth
-
Section 11: More Data Wrangling
-
Section 12: Tidyverse Deep Dive
-
Section 13: Statistical Modeling Deep Dive
-
Section 14: Machine Learning in R
-
Section 15: R Visualization Deep Dive
-
Section 16: R Package Development Deep Dive
-
Section 17: R for Reproducible Research
-
Section 18: R and Databases
-
Section 19: R Performance Optimization
-
Section 20: Bioinformatics and Specialized R
-
Section 21: More Shiny Practice
-
Section 22: More Practice Exercises
-
Section 23: R Data Structures Deep Dive
-
Section 24: More Interview and Review
-
Section 25: R for Business Analytics
-
Section 26: R Text Mining and NLP
-
Section 27: R Spatial Data Analysis
-
Section 28: R Deep Learning
-
Section 29: Advanced Statistical Techniques
-
Section 30: R Object Systems Deep Dive
-
Section 31: R Environments and Metaprogramming
-
Section 32: R for Finance
-
Section 33: R for Clinical and Health Data
-
Section 34: More Shiny Advanced Practice
-
Section 35: R Data Cleaning Deep Dive
-
Section 36: R Reporting Automation
-
Section 37: More Practical Projects Round 2
-
Section 38: R Ecosystem and Career
-
Section 39: More Visualization Practice
-
Section 40: R for Experimentation
-
Section 41: R for Genomics and Bioinformatics Deep Dive
-
Section 42: R for Marketing Analytics
-
Section 43: R Data Import/Export Deep Dive
-
Section 44: R String Processing Deep Dive
-
Section 45: R for Actuarial and Insurance Analytics
-
Section 46: R Testing and Quality Assurance Deep Dive
-
Section 47: R Version Control and Collaboration
-
Section 48: R Advanced Functional Programming
-
Section 49: R for Supply Chain and Operations
-
Section 50: More Practice Exercises Round 3
-
Section 51: R Dashboards and BI Integration
-
Section 52: R Data Governance and Ethics
-
Section 53: More Modeling Practice
-
Section 54: R Final Capstone Projects
-
Section 55: R for Sports Analytics
-
Section 56: More Interview Practice Round 2
-
Section 57: R Networking and APIs
-
Section 58: R for Environmental Science
-
Section 59: R Notebook and Documentation Practices
-
Section 60: More Data Wrangling Mastery
-
Section 61: R for A/B Testing at Scale
-
Section 62: R Package Ecosystem Deep Dive
113: Choropleth Maps in R
When you first decide to build a choropleth map—those maps where regions are shaded based on a value—your instinct will probably be to treat it like any other ggplot2 visualization. You'll think, "I have a shapefile for the borders and a CSV for the data; I'll just join them and plot the polygons." This is exactly where most people get stuck in a loop of coordinate system errors and mismatched join keys.
The Trap of Treating Maps Like Polygons
The naive approach usually involves loading a shapefile using an older package like sp or trying to use geom_polygon(). I've seen a lot of developers do this because the documentation for older R projects still suggests it. The problem is that geom_polygon() expects you to manage the x and y coordinates manually. You end up with a data frame that is massive and redundant, and if you want to change the map's projection—say, moving from a flat Mercator projection to something that doesn't make Greenland look larger than Africa—you're in for a world of pain.
Furthermore, the "naive" way often leads to the NA nightmare. You join your EV adoption data to your state map, and suddenly half the map is grey. Why? Because your CSV says "California" but your shapefile says "Calif." or uses a FIPS code. If you're treating the map as just a collection of lines and points, debugging these joins is tedious because you can't easily "see" which geometry is failing until the whole plot renders (or crashes).
Why Simple Features (sf) Changed the Game
The better way is to use the sf package. If you aren't using sf, you're fighting the language. The brilliance of sf is that it treats spatial data as a standard data.frame (or tibble) with one special twist: a geometry column. This means you can use all your favorite dplyr verbs—filter(), mutate(), left_join()—without worrying about breaking the spatial integrity of the object.
library(sf)
library(ggplot2)
# The modern way: read the shapefile into an sf object
states_map <- st_read("us_states.shp")
# Join the data just like a normal table
map_data <- states_map %>%
left_join(ev_stats, by = "state_name")
# Plot using the dedicated geom_sf
ggplot(data = map_data) +
geom_sf(aes(fill = adoption_rate)) +
scale_fill_viridis_c()
By using geom_sf(), ggplot2 automatically understands the Coordinate Reference System (CRS). You don't have to manually specify the axes or the projection; the function looks at the geometry column and figures it out. It's cleaner, faster, and significantly harder to break.
The Trade-off: Precision vs. Performance
Now, there is a catch. sf objects can become incredibly heavy. If you're mapping every single census tract in the US, your R session might crawl to a halt. This is the trade-off: sf gives you an intuitive, data-frame-like experience, but it stores high-precision coordinates for every vertex of every polygon.
When I'm working with high-resolution maps, I always use st_simplify(). It reduces the number of vertices in your polygons. For a choropleth map, you usually don't need millimeter-precision on a coastline; simplifying the geometry by even a small fraction can reduce your file size by 90% without any visible loss in quality on a standard screen. I'd rather have a map that renders in 200ms with slightly "blockier" coastlines than one that takes 20 seconds to load every time I tweak a color.
Finally, a quick word on aesthetics: avoid the default rainbow palettes. For choropleths, always use a sequential palette (like viridis). Since you're representing a gradient of value, your readers' brains need a linear progression of color to interpret the data correctly. Anything else is just adding noise to your signal.
📋 Practical Task
Exercise: Mapping Renewable Energy Adoption by State
You have been provided with a shapefile of US states (us_states.shp) and a dataset (energy_data.csv) containing the percentage of electricity generated from renewable sources for each state. However, the energy dataset uses state abbreviations (e.g., "NY", "TX"), while the shapefile uses full state names (e.g., "New York", "Texas").
Write a script to:
- Load the shapefile using the
sfpackage. - Create a mapping table or use a helper package to align the state abbreviations in the CSV with the full names in the shapefile.
- Join the energy data to the spatial object using a
left_join. - Create a choropleth map using
geom_sf(). - Apply the
viridiscolor scale to represent the renewable energy percentage. - Simplify the map geometry using
st_simplify()to ensure the final plot renders efficiently.
There are no comments for now.