Interactive animated map showing student activity across St. Olaf College campus throughout the day. Buildings glow with their enrollment, students walk real sidewalks between classes, and the cafeteria tracks meal swipes.
Live: https://stolaf.dev/course-data-visualization/
Open index.html in a browser — it is fully self-contained, with every dataset
embedded, so it needs no server and makes no network requests.
Controls:
- Semester dropdown - Switch between Fall/Spring/Summer semesters
- Day tabs - Select weekday
- Play/Pause - Animate through the day (or press spacebar)
- Time slider - Scrub to a specific time
- Zoom - Scroll wheel or +/- buttons (bottom right)
- Pan - Click and drag
- Course enrollment: StoDevX/course-data —
catalog.db - Building shapes, roads, walkways: ArcGIS St. Olaf Campus Data
- Walking routes: StoDevX/ole-compass — a hand-surveyed pedestrian graph of campus, including building entrances, indoor connections, and stairs
- Dorm capacities: public sources
- Python 3
../course-data/catalog.db(clone the course-data repo alongside this one)
After regenerating anything in data/, embed it into the page:
python3 scripts/rebuild_html.pyWhen a new term lands in catalog.db:
python3 scripts/generate_activity_data.py
python3 scripts/rebuild_html.pyTerms with no enrollment yet (a semester that has not opened for registration) are skipped — they would render an empty campus.
python3 scripts/extract_building_coords.py
python3 scripts/rebuild_html.pyRebuild the route graph from a local checkout of ole-compass:
git clone https://github.com/StoDevX/ole-compass /tmp/ole-compass
python3 scripts/build_path_graph.py /tmp/ole-compass/data
python3 scripts/rebuild_html.pyole-compass stores its graph in pixels of a campus image, so this script
georeferences it into our lat/lon space: first an affine fit from building
entrances to building centroids, then an ICP pass that snaps the outdoor nodes
onto the ArcGIS walkway lines. It prints the resulting fit error, which should
land around 4 m. Anything much larger means the two datasets have drifted apart
and the mapping in NAME_TO_ABBR needs revisiting.
ole-compass does not reach every building. Flaten Art Barn and Ade Christenson sit over 100 m from anything it surveyed, and there is no footpath to the Art Barn in the ArcGIS data either — it is reached by road. For those, the script traces the drawn roads and walkways outward until they meet the surveyed network, and marks the result as map geometry so ordinary routes keep to surveyed paths. It reports each building it had to connect this way.
index.html # The visualization (all data embedded)
data/
building_coords.json # Building centroids
building_geometry.json # Building polygon shapes
campus_activity_multi.json # Enrollment by building/time/day/term
map_layers.json # Roads, walkways, campus boundary
campus_paths.json # Georeferenced walking graph + entrances
scripts/
generate_activity_data.py # Enrollment data from catalog.db
extract_building_coords.py # Building shapes from ArcGIS
build_path_graph.py # Georeference the ole-compass walking graph
rebuild_html.py # Embed the data files into index.html
- Building activity — academic buildings glow amber with the number of students currently in class there
- Residence halls — shown in blue, and unlabelled: we know their capacities but not who is in them, so they are somewhere for students to walk to and from rather than a count of anybody
- Cafeteria — Buntrock Commons glows green through each meal with a running swipe count, then fades once the meal ends
- Student movement — each dot follows an actual walking route: it leaves by whichever door faces its destination, walks the sidewalk network, and enters by the far building's nearest door. Routes are shortest-path over the ole-compass graph, computed once per building pair and reused, so playback stays smooth. Sidewalks are preferred over indoor shortcuts and stairs so the movement stays visible on the map.
- Counts respond to movement — a building's number drops as students leave and rises as they arrive, easing back toward the scheduled enrolment. A class starting or ending moves the figure at once rather than easing, so a room does not read as full after it has emptied.
A few rooms are in places the map cannot draw — Tostrud Center is the largest.
Their enrolment is left out rather than being attached to a nearby building,
and generate_activity_data.py lists what it dropped each time it runs.