library(sf)
library(leaflet)
# Create some fake data (like your confidence)
places <- data.frame(
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 ✨)
spatial_places <- st_as_sf(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 foliumChapter 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
gdf = gpd.GeoDataFrame(data,
geometry=[Point(x, y) for x, y in zip(data['lon'], data['lat'])],
crs='EPSG:4326')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"
m = folium.Map(location=[37.8, -122.5], zoom_start=10)
for idx, row in gdf.iterrows():
folium.Marker([row.geometry.y, row.geometry.x],
popup=row['location']).add_to(m)
m # Boom. Map.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)
places_meters <- st_transform(spatial_places, crs = 3857)
# Make 500m circles around each point
buffers <- st_buffer(places_meters, dist = 500)
# Back to normal coordinates for mapping
buffers <- st_transform(buffers, crs = 4326)
# Add to map
leaflet() %>%
addTiles() %>%
addPolygons(data = buffers, color = "blue", fillOpacity = 0.3) %>%
addMarkers(data = spatial_places, popup = ~location)# Same thing, more typing
gdf_meters = gdf.to_crs('EPSG:3857')
buffers = gdf_meters.buffer(500) # 500 meters
buffer_gdf = gpd.GeoDataFrame(gdf[['location']],
geometry=buffers).to_crs('EPSG:4326')
# Add to map
m = folium.Map(location=[37.8, -122.5], zoom_start=10)
# Add buffers
for idx, row in buffer_gdf.iterrows():
folium.GeoJson(row.geometry,
style_function=lambda x: {'color': 'blue', 'fillOpacity': 0.3}).add_to(m)
# Add points
for idx, row in gdf.iterrows():
folium.Marker([row.geometry.y, row.geometry.x],
popup=row['location']).add_to(m)
mChapter 3: Distance (How Far is Too Far?)
# Calculate distances between all points
distances <- st_distance(spatial_places)
print("Distances in meters (approximately):")
print(distances)
# Convert to miles because America
distances_miles <- distances * 0.000621371
print("Distances in freedom units:")
print(distances_miles)from sklearn.metrics.pairwise import haversine_distances
import numpy as np
# Extract coordinates and calculate distances
coords = np.radians([[p.y, p.x] for p in gdf.geometry])
distances = haversine_distances(coords) * 6371000 # Earth radius
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
utm_data <- st_transform(spatial_places, crs = 32610) # UTM Zone 10N
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.”