---
id: wiki-2026-0508-geographic-information-systems
title: Geographic Information Systems
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [GIS, Geospatial, Spatial Data]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [geospatial, mapping, data, spatial-analysis]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
  language: Python
  framework: GeoPandas, Shapely, PostGIS, DuckDB-spatial, Lonboard
---

# Geographic Information Systems

## 매 한 줄
> **"매 spatially-referenced data 의 capture, storage, query, analysis, visualization"**. Roger Tomlinson 의 Canada GIS (1968) → Esri ArcInfo → 매 modern open stack (PostGIS, GeoPandas, GDAL, GeoParquet, DuckDB-spatial, deck.gl). 매 2026 trend: **cloud-native geospatial (COG, STAC, GeoParquet, FlatGeobuf), GPU vector rendering, ML-on-raster**.

## 매 핵심

### 매 two data models
- **Vector**: points, lines, polygons (Shapefile/GeoJSON/FlatGeobuf/GeoParquet). 매 discrete features.
- **Raster**: regular grid of cells (GeoTIFF, COG, Zarr). 매 continuous fields, satellite imagery.

### 매 핵심 concepts
- **CRS (Coordinate Reference System)**: WGS84 (EPSG:4326), Web Mercator (3857), UTM zones, local projected.
- **Topology**: contains/intersects/touches/crosses (DE-9IM).
- **Spatial index**: R-tree, Quadtree, **H3 / S2 hex grid** (Uber/Google), Geohash.
- **Map algebra**: raster arithmetic, focal/zonal stats.
- **Geocoding / reverse**: address ↔ coords.

### 매 modern (2026) stack
- **Storage**: GeoParquet, COG (Cloud-Optimized GeoTIFF), STAC catalogs, PMTiles.
- **Compute**: DuckDB-spatial, GeoPandas 1.x (PyArrow backend), Sedona, BigQuery GIS.
- **Render**: deck.gl, Lonboard (in-Jupyter GPU vector), MapLibre, Mapbox GL.
- **ML**: Segment-Anything-on-imagery, SatCLIP embeddings, prithvi geo-foundation model.

## 💻 패턴

### Read & reproject (GeoPandas)
```python
import geopandas as gpd
gdf = gpd.read_file("zip://./tl_2024_us_county.zip")
gdf = gdf.to_crs(epsg=3857)        # Web Mercator
print(gdf.geometry.area.head())    # m² in projected CRS
```

### Spatial join + index
```python
points = gpd.read_file("stores.geojson").to_crs(epsg=3857)
admin  = gpd.read_file("districts.geojson").to_crs(epsg=3857)
joined = gpd.sjoin(points, admin, how="left", predicate="within")
```

### PostGIS query
```sql
-- find restaurants within 500 m of a metro stop
SELECT r.id, r.name
FROM restaurants r
JOIN metro_stops m
  ON ST_DWithin(r.geom::geography, m.geom::geography, 500)
WHERE m.line = 'Line 2';
CREATE INDEX restaurants_geom_gix ON restaurants USING GIST (geom);
```

### DuckDB-spatial (single-file analytics)
```python
import duckdb
con = duckdb.connect()
con.install_extension("spatial"); con.load_extension("spatial")
con.sql("""
SELECT name, ST_Area(geom)/1e6 AS km2
FROM ST_Read('countries.fgb')
WHERE ST_Intersects(geom, ST_MakeEnvelope(-10,35,40,70))
ORDER BY km2 DESC LIMIT 5
""").show()
```

### Raster analysis (rioxarray)
```python
import rioxarray as rxr
ndvi_red = rxr.open_rasterio("B04.tif", masked=True)
ndvi_nir = rxr.open_rasterio("B08.tif", masked=True)
ndvi = (ndvi_nir - ndvi_red) / (ndvi_nir + ndvi_red)
ndvi.rio.to_raster("ndvi.tif", driver="COG")
```

### H3 hex aggregation
```python
import h3, pandas as pd
df = pd.read_csv("rides.csv")
df["h3"] = [h3.latlng_to_cell(lat, lng, 9) for lat,lng in zip(df.lat, df.lng)]
agg = df.groupby("h3").size().reset_index(name="rides")
```

### Routing (OSMnx + NetworkX)
```python
import osmnx as ox, networkx as nx
G = ox.graph_from_place("Berlin, Germany", network_type="drive")
orig = ox.distance.nearest_nodes(G, 13.405, 52.520)
dest = ox.distance.nearest_nodes(G, 13.450, 52.500)
route = nx.shortest_path(G, orig, dest, weight="length")
```

### GPU map render (Lonboard, in notebook)
```python
import lonboard
from lonboard import Map, ScatterplotLayer
layer = ScatterplotLayer.from_geopandas(points, get_radius=20, get_fill_color=[200,30,30])
Map(layer)
```

## 매 결정 기준
| 상황 | Approach |
|---|---|
| Single laptop, < 10 M rows | **GeoPandas 1.x** |
| Analytics, columnar | **DuckDB-spatial + GeoParquet** |
| Multi-user transactional | **PostGIS** |
| Cluster scale (≫ 100 GB) | **Apache Sedona / BigQuery GIS** |
| Satellite raster pipeline | **STAC + COG + rioxarray + Dask** |
| Aggregation by tile | **H3 / S2 hex** |
| Web map (millions of features) | **PMTiles + MapLibre / deck.gl** |
| ML on imagery | **prithvi / SatCLIP + SAM-Geo** |

**기본값**: 매 modern 의 **GeoParquet + DuckDB-spatial + Lonboard** trio (laptop-scale), 매 server 의 **PostGIS**.

## 🔗 Graph
- 응용: [[Routing]]
- Adjacent: [[PostGIS]]

## 🤖 LLM 활용
**언제**: 매 spatial-aware app 의 architecture, 매 CRS / projection 의 selection 의 explanation, 매 SQL 의 PostGIS 의 generation, 매 imagery analysis 의 prompting.
**언제 X**: 매 high-precision survey / cadastral 의 manual professional 검증 필수.

## ❌ 안티패턴
- **Mixed CRS without reproject**: 매 km vs degree 의 silent mismatch.
- **Web Mercator 의 area calc**: 매 high-latitude 의 huge distortion — 매 equal-area projection 사용.
- **Shapefile 의 still using**: 매 10-char column, 2 GB limit, no UTF-8 — 매 GeoParquet/FlatGeobuf 사용.
- **No spatial index**: 매 PostGIS GIST 없이 매 query 의 100-1000× slow.
- **Raster 매 in-memory full load**: 매 windowed read (rioxarray + Dask) 사용.
- **Lat/Lon swap**: 매 GeoJSON `[lng, lat]` vs human `(lat, lng)` 의 가장 흔한 bug.

## 🧪 검증 / 중복
- Verified (OGC standards; PostGIS docs; *Geocomputation with Python* 2024; Cloud-Native Geospatial Foundation).
- 신뢰도 A.

## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 placeholder |
| 2026-05-10 | Manual cleanup — modern 2026 stack + 8 patterns |
