') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - RSGInc/activitysim_visualizer · GitHub
Skip to content

Repository files navigation

ActivitySim Visualizer

ActivitySim Visualizer turns ActivitySim output into an interactive dashboard. Use it to examine one model run, compare multiple runs, or compare model results with survey data.

ActivitySim Visualizer can:

  • prepare and summarize household, person, tour, and trip output;
  • optionally add skim-derived trip and tour measures from OMX, HDF5, or CSV inputs;
  • compare travel patterns, model choices, and validation measures for multiple runs;
  • reuse valid cached results for faster startup; and
  • launch a local dashboard or create a standalone HTML file.

Quick Start

1. Install the project

From the repository root, use uv to create the environment and install the locked dependencies:

uv sync --locked

If Windows reports a hardlink problem, use:

uv sync --locked --link-mode=copy

2. Create a configuration

Copy config.yaml to local_config.yaml, then set each runs.dir value to an ActivitySim output directory:

runs:
- dir: C:\models\base\outputlabel: Base
- dir: C:\models\build\outputlabel: Build

The default file names are final_households, final_persons, final_day, final_tours, final_trips, final_vehicles, final_joint_tour_participants, and final_land_use. Day, vehicle, joint participant, and land-use tables are optional. The visualizer accepts CSV and Parquet input files.

For a small example configuration and instructions for nonstandard files or zones, see Getting Started and Configuring Your Data.

For the included Metro, LCOG, and SKATS configurations, use the SimOR Quick Start.

3. Start the visualizer

uv run activitysim-viz --config local_config.yaml

On the first run, the visualizer prepares the input, builds the required summary tables, and starts a local server at http://localhost:5006. Later runs reuse valid caches. Press Ctrl+C to stop the server.

If data is missing or the first run fails, see Troubleshooting.

How It Works

ActivitySim outputs
-> prepare canonical tables
-> optionally join skim-derived trip and tour values
-> summarize travel measures
-> display a live dashboard or export standalone HTML

The YAML configuration selects the input, workflow steps, output location, and dashboard mode. The start command stays the same for every workflow.

GoalWhere to learn more
Use raw ActivitySim output directoriesConfiguring Your Data
Use already-prepared tablesAlready-Prepared Tables
Add skim-derived trip and tour fieldsSkimjoin
Use dashboard-ready summary tablesDashboard-Ready Summary Tables
Run only the processorProcessor-Only Workflow
Create a standalone HTML dashboardHTML Export
Understand caches and workflow stepsRunning Workflows
Build summaries for configured subsetsSegmentation
Add district, county, or other zone groupingsGeography
Find an exact configuration fieldConfiguration Reference
Verify raw or prepared table requirementsInput Data Contract
Interpret cache manifests and rebuild decisionsCache And Manifest Reference
Understand a summary table or fieldSummary Catalog

Documentation

The wiki home is the main documentation index.

For a standard setup, read these chapters in order:

  1. Getting Started
  2. Configuring Your Data
  3. Running Workflows

Other user references:

For Contributors

Start with Architecture and Developer Workflows, then use the guide for your task:

Run focused tests during development. To run the full test suite, use:

uv run pytest --basetemp .pytest_tmp

If you change summary declarations or dashboard page definitions, regenerate the wiki catalogs from the code:

uv run python scripts/generate_wiki_catalogs.py

License

The GNU General Public License v3.0 applies to this project. See LICENSE.txt.

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages