library(sf)
library(leaflet)
# Create some fake data (like your confidence)
<- data.frame(
places location = c("Coffee Shop", "My House", "Regret"),
lon = c(-122.4, -122.5, -122.6),
lat = c(37.8, 37.9, 37.7)
)
# Turn it into spatial data (✨ magic ✨)
<- st_as_sf(places,
spatial_places coords = c("lon", "lat"),
crs = 4326) # 4326 = "GPS coordinates"
Welcome to GIS Hell (It’s Actually Pretty Cool)
GIS = Geographic Information Systems = “I put data on maps and somehow this became my job”
What you’ll learn: - How to not mess up coordinate systems (spoiler: you will anyway) - Make pretty maps that impress your boss - Pretend you know what you’re doing
Install This Stuff (Or Cry Later)
# R packages (install once, debug forever)
install.packages(c("sf", "leaflet", "tmap"))
# Python (because why make life easy?)
# pip install geopandas folium
Chapter 1: Your First Map (That Won’t Suck)
The Magic of Putting Dots on Maps
import geopandas as gpd
from shapely.geometry import Point
# Same fake data, different language
= {
data 'location': ['Coffee Shop', 'My House', 'Regret'],
'lon': [-122.4, -122.5, -122.6],
'lat': [37.8, 37.9, 37.7]
}
# GeoPandas: Pandas but with existential crisis about location
= gpd.GeoDataFrame(data,
gdf =[Point(x, y) for x, y in zip(data['lon'], data['lat'])],
geometry='EPSG:4326') crs
Make It Interactive (Impress People)
# Leaflet: Like Google Maps but you made it
leaflet(spatial_places) %>%
addTiles() %>% # Free maps (thanks OpenStreetMap!)
addMarkers(popup = ~location) %>%
setView(lng = -122.5, lat = 37.8, zoom = 10)
import folium
# Folium: Python's answer to "I want pretty maps"
= folium.Map(location=[37.8, -122.5], zoom_start=10)
m
for idx, row in gdf.iterrows():
folium.Marker([row.geometry.y, row.geometry.x], =row['location']).add_to(m)
popup
# Boom. Map. m
Chapter 2: Buffers (Circles Around Stuff)
Why buffers? “Everything within 1 mile of Starbucks” is a legitimate analysis.
# Transform to meters (because measuring in degrees is weird)
<- st_transform(spatial_places, crs = 3857)
places_meters
# Make 500m circles around each point
<- st_buffer(places_meters, dist = 500)
buffers
# Back to normal coordinates for mapping
<- st_transform(buffers, crs = 4326)
buffers
# Add to map
leaflet() %>%
addTiles() %>%
addPolygons(data = buffers, color = "blue", fillOpacity = 0.3) %>%
addMarkers(data = spatial_places, popup = ~location)
# Same thing, more typing
= gdf.to_crs('EPSG:3857')
gdf_meters = gdf_meters.buffer(500) # 500 meters
buffers = gpd.GeoDataFrame(gdf[['location']],
buffer_gdf =buffers).to_crs('EPSG:4326')
geometry
# Add to map
= folium.Map(location=[37.8, -122.5], zoom_start=10)
m
# Add buffers
for idx, row in buffer_gdf.iterrows():
folium.GeoJson(row.geometry, =lambda x: {'color': 'blue', 'fillOpacity': 0.3}).add_to(m)
style_function
# Add points
for idx, row in gdf.iterrows():
folium.Marker([row.geometry.y, row.geometry.x], =row['location']).add_to(m)
popup m
Chapter 3: Distance (How Far is Too Far?)
# Calculate distances between all points
<- st_distance(spatial_places)
distances print("Distances in meters (approximately):")
print(distances)
# Convert to miles because America
<- distances * 0.000621371
distances_miles print("Distances in freedom units:")
print(distances_miles)
from sklearn.metrics.pairwise import haversine_distances
import numpy as np
# Extract coordinates and calculate distances
= np.radians([[p.y, p.x] for p in gdf.geometry])
coords = haversine_distances(coords) * 6371000 # Earth radius
distances
print("Distances in meters:")
print(distances.astype(int))
Chapter 4: The Coordinate System Nightmare
Truth: You will spend 50% of your GIS career fixing coordinate systems.
Common CRS (Coordinate Reference Systems): - EPSG:4326
= GPS coordinates (lat/lon) - Use for web maps - EPSG:3857
= Web Mercator - Use for measurements - Local UTM zones - Use when you need to be precise
# Check what CRS you're using
st_crs(spatial_places)
# Transform between coordinate systems
<- st_transform(spatial_places, crs = 32610) # UTM Zone 10N
utm_data print("Now in UTM coordinates:")
print(st_coordinates(utm_data))
Chapter 5: Quick Wins
Load Real Data (Finally!)
# Load a shapefile (if you have one)
# data <- st_read("your_file.shp")
# Or get data from the internet
library(osmdata)
# Get coffee shops in your area
# coffee <- opq("San Francisco, CA") %>%
# add_osm_feature(key = "amenity", value = "cafe") %>%
# osmdata_sf()
Export Your Masterpiece
# Save as shapefile
# st_write(spatial_places, "my_awesome_data.shp")
# Save as GeoJSON (the cool kids format)
# st_write(spatial_places, "my_awesome_data.geojson")
The End (You Survived!)
What you learned: - Points on maps = happiness - Buffers = circles around things - CRS = the source of all problems - GIS = surprisingly addictive
Next steps: - Make more maps - Break more coordinate systems
- Blame ESRI for everything - Profit???
Pro tip: When in doubt, reproject to EPSG:4326. When that doesn’t work, try EPSG:3857. When that fails, panic quietly.
“In GIS, all roads lead to Rome… if your coordinate system is correct.”