Skip to content

Repository files navigation

ActivitySim Visualizer

activitysim_visualizer is a Panel-based dashboard for exploring and comparing ActivitySim outputs. It can:

  • compare multiple model runs side by side
  • build and reuse prepared and summary caches
  • serve a live local dashboard
  • export a standalone HTML version for offline sharing

Quick Start

Install dependencies with uv:

uv sync --locked

Notebook tooling is optional; install it only when working with the repository's notebooks:

uv sync --locked --group notebooks

If uv sync fails because of a hardlink issue, retry with:

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

Create a project-specific config:

Copy-Item config.yaml local_config.yaml

Edit local_config.yaml, then run the app with that config:

uv run activitysim-viz --config local_config.yaml

By default, activitysim-viz follows pipeline.steps from the loaded config when no explicit step flags are supplied. The shipped example config defaults to summarize + dashboard, so a normal run will reuse summary caches when possible, rebuild them when needed, and then start the live dashboard on http://localhost:5006.

Dashboard Pages

Dashboard pages now use one shared authoring model:

  • page classes use @dashboard_page(...) and subclass DashboardPage
  • dropdowns use select(...); custom widgets use selector(...)
  • dynamic selectors declare an option provider and default policy
  • refreshable regions are registered with section(...)
  • large pages compose related selectors and sections with feature(...)
  • repeated chart transforms use query(...) without page-authored cache keys
  • live refresh and export metadata both derive from those registrations

The main shared page-helper modules live under dashboard/helpers/:

  • category_helpers.py
  • geography_helpers.py
  • person_type_helpers.py
  • time_distance_helpers.py
  • comparison_helpers.py

If you are adding or refactoring a page, start with the dashboard page recipes and figures/widgets guide. The dashboard extension cookbook covers the complete contributor path.

Config Setup

The repo ships with config.yaml as a template. In practice, most people should:

  1. Copy config.yaml to local_config.yaml or another machine-specific file.
  2. Update the runs section to point at real ActivitySim output folders.
  3. Update prepare.distance_skim, zones, and files if your model layout differs from the defaults.
  4. Run with --config your_file.yaml.

The canonical config layout is organized around a few top-level sections:

root: artifacts/log_level: INFOpipeline:
steps: [summarize, dashboard]dashboard_mode: liveoverwrite: falseprepare: ...summarize: ...segment: ...dashboard: ...display: ...skimjoin: ...extensions: ...

Removed keys such as processor.*, summaries.*, visualizer.*, top-level dashboard_labels, and top-level run_colors now fail validation and name the canonical replacement. Unknown keys also fail instead of being silently ignored.

The minimum useful config is usually:

root: artifacts/summary_cachepipeline:
steps:
- summarize
- dashboarddashboard_mode: liveruns:
- dir: path\to\run1label: Base
- dir: path\to\run2label: Buildskimjoin:
distance_skim:
file: path\to\skims.omxmatrix: SOV_DIST__MDzones:
use_maz: falsemaz_col: zone_idtaz_col: TAZfiles:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsjoint_tour_participants: final_joint_tour_participantsland_use: final_land_use

If runs use different raw filenames, keep files: as the default mapping and override only the differences inside runs[*].file_map:

files:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsruns:
- dir: path\to\run1label: Basefile_map:
households: final_hhtrips: trip_linked
- dir: path\to\run2label: Buildfile_map:
households: householdpersons: persontours: tourtrips: trip

If a run should skip raw prepare and use externally managed canonical prepared tables instead, point it at those files with runs[*].prepared_table_map:

runs:
- dir: path\to\raw_runlabel: Raw Run
- label: Custom Prepared Runprepared_table_map:
households: path\to\custom\households.parquetpersons: path\to\custom\persons.csvtours: path\to\custom\tours.parquettrips: path\to\custom\trips.csvjoint_tour_participants: path\to\custom\joint_tour_participants.parquetland_use: path\to\custom\land_use.csv

prepared_table_map is intended for canonical prepared tables that were already skimjoined and then optionally filtered or otherwise post-processed outside this repo. When a run uses prepared_table_map, the workflow loads those prepared tables directly and does not rerun raw prepare or integrated skimjoin for that run.

If a run already has dashboard-ready summary tables, point directly at those files with runs[*].summary_table_map:

runs:
- label: Summary Only Demosummary_table_map:
population_totals: path\to\summaries\population_totals.csvtraffic_count_comparisons: path\to\summaries\traffic_count_comparisons.parquet

summary_table_map uses registered summary IDs as keys, accepts explicit .csv or .parquet paths, and resolves relative paths from the config file directory. Mapped summaries are expected to already use the dashboard's canonical columns. During summarize they override the listed generated summaries; missing summaries can still be generated from raw/prepared inputs when those inputs exist. Some registered summary IDs are external/demo-only and are not generated by default for raw/prepared runs, which avoids writing __empty__ cache CSVs just to make those IDs available to summary_table_map.

Integrated skim enrichment can now be selected per run without forcing one shared skimjoin config for every skim structure. Keep the explicit skimjoin YAML logic in separate files, then choose the file and optional project-input overrides per run:

skimjoin:
defaults:
config_path: configs/skimjoin_default.yamlruns:
- dir: path\to\run_alabel: Run Askimjoin:
config_path: configs/skimjoin_odot_series15.yamlskim_files:
- path\to\run_a\skims\*.omx
- path\to\run_a\skims\maz_stop_walk.csvnetwork_los_file: path\to\run_a\network_los.yaml
- dir: path\to\run_blabel: Run Bskimjoin:
config_path: configs/skimjoin_combined_walk.yamlskim_files:
- path\to\run_b\skims\*.omx

Skimjoin override rules:

  • runs[*].skimjoin.config_path overrides global skimjoin.config_path.
  • runs[*].skimjoin.skim_files overrides the selected skimjoin config's project.skim_files.
  • runs[*].skimjoin.network_los_file overrides the selected skimjoin config's project.network_los_file.
  • skimjoin.failure_policy defaults to record; use error when skimjoin failures must stop a validation or batch run.
  • If a run omits runs[*].skimjoin, it uses the global skimjoin settings exactly as before.

Recommended rule of thumb:

  • If runs differ only by skim file locations, share one skimjoin config and override runs[*].skimjoin.skim_files.
  • If runs differ only by period definitions, share one skimjoin config and override runs[*].skimjoin.network_los_file.
  • If runs differ by lookup logic, fallback behavior, combined vs split components, or directional semantics, use different skimjoin config files.

VOT bin preparation stays in prepare.vot_bins and remains run-aware by run label.

Skimjoin dimensions are now standardized under dimensions, while activitysim only carries the structural trip/tour fields. The recommended integrated-runtime pattern is:

activitysim:
trip_mode_column: trip_modetrip_id_column: trip_idtour_mode_column: tour_modetour_id_column: tour_idoutbound_column: outbounddimensions:
PERIOD:
source_columns:
trip_source_column: depart_houroutbound_tour_source_column: start_hourinbound_tour_source_column: first_inbound_trip_departvalues_from_network_los: truevalues:
8: AM17: PMVOT:
source_columns:
trip_source_column: vot_binoutbound_tour_source_column: vot_bininbound_tour_source_column: vot_binvalues:
L: LM: MH: H

Period behavior is directional by design:

  • trips use dimensions.PERIOD.source_columns.trip_source_column
  • outbound tours use dimensions.PERIOD.source_columns.outbound_tour_source_column
  • inbound tours use dimensions.PERIOD.source_columns.inbound_tour_source_column

In the standard prepare workflow, first_inbound_trip_depart is derived from the first inbound trip on each tour before integrated skimjoin runs.

Prepared endpoint columns are also standardized before skimjoin runs:

  • prepared trips and tours always include OTAZ and DTAZ
  • when zones.use_maz: true, prepare also materializes o_maz and d_maz
  • inbound tour lookups reuse those same column names, while skimjoin swaps their logical direction in the inbound tour context

The normal prepare step can also write prepared caches as CSV when needed:

prepare:
output:
file_format: csvvalidation:
relationship_checks: warn

Important path rules:

  • root is resolved relative to the config file if you give a relative path.
  • The prepared cache is created automatically next to root as prepared_cache/.
  • runs[*].dir should point at an ActivitySim output directory.
  • prepare.distance_skim.file may be absolute, or relative to each run directory.
  • File entries under files can be bare stems like final_trips or explicit filenames like final_trips.csv.
  • runs[*].file_map uses the same filename rules as files, but applies only to that run.
  • runs[*].prepared_table_map must use explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • runs[*].summary_table_map must use registered summary IDs with explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • prepare.output.file_format controls how standard prepared caches are written; supported values are parquet and csv, with parquet as the default.
  • prepare.validation.relationship_checks controls prepared-table foreign-key validation. Use warn to log inconsistencies and continue, error to fail the run, or off to skip the checks.
  • dashboard.export.output_path, when relative, is resolved from root.

Config Reference

These are the sections most people need to touch:

SectionPurpose
rootWhere summary caches are stored
pipelineDefault workflow steps, dashboard mode, and overwrite behavior
runsRun directories, display labels, and optional per-run skim, raw file-map, custom prepared-table map, custom summary-table map, and weight overrides
prepare.distance_skimDefault distance skim file and matrix name used by summaries
zonesMAZ/TAZ settings for skim joins and zone normalization
filesDefault ActivitySim output file stems or filenames used unless a run overrides them
columnsColumn aliases when outputs use non-default names
prepare.output.file_formatOn-disk format for prepared caches written by the normal prepare workflow
prepare.validation.relationship_checksWhether cross-table prepared-key validation is disabled, warns, or errors
prepare.student_typesOptional school/university enrollment definitions for shadow pricing pages
dashboard.titleTitle used in the live dashboard and HTML export
dashboard.include_notesShow per-plot and per-table calculation notes in the live dashboard and HTML export (default: true)
dashboard.live.pagesOrdered list of live pages/groups to show
dashboard.exportExport-only output path, page selection, and selector-state controls
display.run_colorsPlot colors by run
display.labelsPresentation-only labels and ordering for dashboard/export
weighting.modesNamed weighting alternatives backed by household, person, and/or trip columns
extensionsAdvanced importable weighting calculations and their summary-affecting settings
summarize.weighting_modesOrdered built-in, declarative, or custom weighting-mode IDs to build
summarize.failure_policyrecord keeps failed summaries visible as diagnostics; error stops immediately on a builder exception
summarize.geographyOptional configured district/county/zone mappings
summarize.pnr_tour_modesWhich tour modes count as park-and-ride in summary builders
summarize.group_*_tour_purposesSummary-time purpose regrouping switches
summarize.category_normalizationSummary-affecting category normalization/regrouping
modesOptional mode ordering and grouped mode display
display.labels.person_typeOptional display labels for ptype values

Weighting rules:

  • If a run sets hh_weight_col, person_weight_col, or trip_weight_col, those are used.
  • Otherwise, if a sample_rate column is available, weights are derived from it.
  • Otherwise, weights default to 1.
  • weighting.modes can select additional prepared household, person, and trip columns as named alternatives without replacing the primary weighted mode.

Geography summary notes:

  • Summaries may emit all_geographies total rows independently of the geography config.
  • Native prepared geographies such as home_taz, home_county, and home_mpo may appear whenever those columns are available in prepared data, even when summarize.geography.enabled: false.
  • summarize.geography controls additional mapped geography aggregations, such as home_geo__school_district, work_geo__county, or land_use_geo__district.

Removed config notes:

  • Prefer the canonical top-level schema: root, pipeline, dashboard, display, summarize, segment, and skimjoin.
  • Older keys such as processor.root, summaries.weighting_modes, visualizer.dashboard_pages, top-level run_colors, top-level summary_categories, and top-level student_types are rejected with their canonical replacement.

Geography note:

  • summarize.geography.enabled: false disables mapped geography aggregation columns. Set it to true for aggregation-based geography summaries.

Category config note:

  • Use summarize.category_normalization when a mapping changes summary values, grouping membership, or canonical category values.
  • Use display.labels when a change is cosmetic and should only affect dashboard/export labels or ordering.

Live Pages And Export Pages

dashboard.live.pages controls the live dashboard only. dashboard.export controls what goes into the standalone HTML export.

Current top-level page ids are:

  • overview
  • long_term_choices
  • daily_travel
  • joint_travel
  • tour_summaries
  • trip_summaries
  • validation
  • raw_trip_demo

Grouped page ids support either the whole group or specific child pages. For example:

dashboard:
# Set to false to omit all per-plot and per-table calculation notes.include_notes: truelive:
pages:
- overview
- long_term_choices:
- individual_choices
- mandatory_location_choice
- shadow_pricing
- daily_travel: default
- tour_summaries: all
- trip_summaries:
- trip_mode
- trip_stop_time

Notes:

  • default means "the group's default enabled children".
  • all means every child page in the group.
  • A plain group id like tour_summaries behaves like the group's default selection.
  • raw_trip_demo is disabled by default and requests prepared trip tables, so keep it out unless you explicitly want that behavior.

For HTML export, start with the live page set and override selector states or parts as needed:

dashboard:
export:
dashboard:
weighting: [unweighted]values: [percent]exclude_groups: [validation]pages:
long_term_choices:
shadow_pricing:
geography_level: [all]student_type: [all]parts:
workplace_table:
enabled: falseschool_table:
enabled: false

Rules worth remembering:

  • If dashboard.live.pages is omitted, the app uses its built-in default page set.
  • Export always starts from the live page set. Entries under dashboard.export.pages modify matching pages; they are not an allow-list.
  • Export selector requests accept default, all, or a list of explicit values.
  • Set a page override's enabled to false, or use dashboard.export.exclude_pages / exclude_groups, to remove pages from export without changing the live dashboard.

Run Modes

The CLI exposes three workflow steps:

  1. prepare
  2. summarize
  3. dashboard

Common commands:

CommandWhat it does
python run.py --config local_config.yamlReuse or build summaries, then start the live dashboard
python run.py --config local_config.yaml --prepare-onlyBuild prepared caches and exit
python run.py --config local_config.yaml --summarizeReuse or build summary caches and exit
python run.py --config local_config.yaml --summarize --dashboardExplicit form of the default live workflow
python run.py --config local_config.yaml --dashboardStart the dashboard from existing summary caches for the configured runs
python run.py --config local_config.yaml --prepare --summarize --dashboardForce the full prepare -> summarize -> dashboard chain in one run
python run.py --config local_config.yaml --from-csvsStart the dashboard from existing summary caches only
python run.py --config local_config.yaml --from-csvs --export-html output.htmlBuild a standalone HTML export from existing summary caches
python run.py --config local_config.yaml --summarize --write-csvsRebuild summaries and write fresh cache files
python run.py --config local_config.yaml --summarize --skip-summary-cache-writeBuild summaries for this run without writing cache updates
python run.py --config local_config.yaml --summarize --refresh-summary-cacheDelete and rebuild summary caches for the selected runs
python run.py --config local_config.yaml --summarize --refresh-prepared-cacheRebuild summaries from freshly prepared tables instead of prepared-cache hits
python run.py --config local_config.yaml --prepare --summarize --refresh-cachesDelete and rebuild both prepared and summary caches for the selected runs

Behavior details:

  • --from-csvs is cache-only: it reads visualizer summary-cache directories with manifests, not loose summary CSVs.
  • --from-csvs path\to\cache1 path\to\cache2 lets you point directly at specific summary cache directories.
  • Use runs[*].summary_table_map when you have loose dashboard-ready summary files instead of visualizer cache directories.
  • --dashboard by itself is valid when summary caches already exist for the configured runs.
  • During summarize, the app will reuse prepared cache when possible and rebuild from raw outputs only when needed.
  • --refresh-prepared-cache deletes the selected runs' prepared-cache directories first, then disables prepared-cache reuse for that invocation.
  • --refresh-summary-cache deletes the selected runs' summary-cache directories first, then disables summary-cache reuse for that invocation.
  • --refresh-caches is shorthand for both refresh flags together.

Cache Layout

Prepared caches are written automatically next to the summary cache root:

<summary_root_parent>/
prepared_cache/
<run_key>/
manifest.json
households.parquet|csv
persons.parquet|csv
tours.parquet|csv
trips.parquet|csv
joint_tour_participants.parquet|csv
land_use.parquet|csv

Summary caches are written under root:

<summary_root>/
<run_key>/
manifest.json
weighted/
unweighted/

Both cache layers validate manifests before reuse. Cache invalidation is driven by:

  • the run inputs
  • the prepare and summary config digests
  • the prepared-manifest identity used to build summary caches
  • per-summary summary digests inside the summary-cache manifest

That means presentation-only config changes usually do not force summary rebuilds, and adding a newly requested summary can backfill just that table instead of rebuilding the entire summary bundle.

CLI Overrides

You can override runs on the command line instead of putting them in the config:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build"

Optional per-run skim overrides can be supplied in the same order:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build" ^
--run-skim C:\path\to\base_skims.omx C:\path\to\build_skims.omx

Use null, None, or an empty string in --run-skim to fall back to the configured prepare.distance_skim.file.

Codebase Map

activitysim_visualizer/
|-- run.py
|-- runtime/
| |-- workflows/
|-- runtime/
| `-- config/
|-- processor/
| |-- prepare/
| |-- summarize/
| `-- models.py
|-- dashboard/
| |-- app.py
| |-- export/
| |-- page_base.py
| |-- page_declarations.py
| |-- page_diagnostics.py
| |-- page_features.py
| |-- page_lifecycle.py
| |-- page_navigation.py
| |-- page_definitions.py
| |-- page_registry.py
| |-- state.py
| `-- pages/
`-- tests/

Documentation

The main user and contributor documentation lives in the wiki/ chapter set. Start with:

The wiki is the sole documentation source. Add or revise a wiki chapter instead of creating a parallel documentation tree.

Documentation Maintenance Checklist

When behavior changes, update docs in the same change:

  • New config key or config behavior: update chapters 11 and 13.
  • New summary declaration or contract: update chapter 23 and regenerate catalogs.
  • New page, selector, or plotting behavior: update chapters 31 through 33 and regenerate catalogs.
  • New export payload/runtime behavior: update chapter 34.
  • Architecture or runtime-flow changes: update chapters 12, 20, and 30 as applicable.

Tests

See Developer Workflows for the normal test loop and Testing for the fast/full split and offline-export boundary.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - OrMSC/activitysim_visualizer · GitHub
Skip to content

Repository files navigation

ActivitySim Visualizer

activitysim_visualizer is a Panel-based dashboard for exploring and comparing ActivitySim outputs. It can:

  • compare multiple model runs side by side
  • build and reuse prepared and summary caches
  • serve a live local dashboard
  • export a standalone HTML version for offline sharing

Quick Start

Install dependencies with uv:

uv sync --locked

Notebook tooling is optional; install it only when working with the repository's notebooks:

uv sync --locked --group notebooks

If uv sync fails because of a hardlink issue, retry with:

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

Create a project-specific config:

Copy-Item config.yaml local_config.yaml

Edit local_config.yaml, then run the app with that config:

uv run activitysim-viz --config local_config.yaml

By default, activitysim-viz follows pipeline.steps from the loaded config when no explicit step flags are supplied. The shipped example config defaults to summarize + dashboard, so a normal run will reuse summary caches when possible, rebuild them when needed, and then start the live dashboard on http://localhost:5006.

Dashboard Pages

Dashboard pages now use one shared authoring model:

  • page classes use @dashboard_page(...) and subclass DashboardPage
  • dropdowns use select(...); custom widgets use selector(...)
  • dynamic selectors declare an option provider and default policy
  • refreshable regions are registered with section(...)
  • large pages compose related selectors and sections with feature(...)
  • repeated chart transforms use query(...) without page-authored cache keys
  • live refresh and export metadata both derive from those registrations

The main shared page-helper modules live under dashboard/helpers/:

  • category_helpers.py
  • geography_helpers.py
  • person_type_helpers.py
  • time_distance_helpers.py
  • comparison_helpers.py

If you are adding or refactoring a page, start with the dashboard page recipes and figures/widgets guide. The dashboard extension cookbook covers the complete contributor path.

Config Setup

The repo ships with config.yaml as a template. In practice, most people should:

  1. Copy config.yaml to local_config.yaml or another machine-specific file.
  2. Update the runs section to point at real ActivitySim output folders.
  3. Update prepare.distance_skim, zones, and files if your model layout differs from the defaults.
  4. Run with --config your_file.yaml.

The canonical config layout is organized around a few top-level sections:

root: artifacts/log_level: INFOpipeline:
steps: [summarize, dashboard]dashboard_mode: liveoverwrite: falseprepare: ...summarize: ...segment: ...dashboard: ...display: ...skimjoin: ...extensions: ...

Removed keys such as processor.*, summaries.*, visualizer.*, top-level dashboard_labels, and top-level run_colors now fail validation and name the canonical replacement. Unknown keys also fail instead of being silently ignored.

The minimum useful config is usually:

root: artifacts/summary_cachepipeline:
steps:
- summarize
- dashboarddashboard_mode: liveruns:
- dir: path\to\run1label: Base
- dir: path\to\run2label: Buildskimjoin:
distance_skim:
file: path\to\skims.omxmatrix: SOV_DIST__MDzones:
use_maz: falsemaz_col: zone_idtaz_col: TAZfiles:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsjoint_tour_participants: final_joint_tour_participantsland_use: final_land_use

If runs use different raw filenames, keep files: as the default mapping and override only the differences inside runs[*].file_map:

files:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsruns:
- dir: path\to\run1label: Basefile_map:
households: final_hhtrips: trip_linked
- dir: path\to\run2label: Buildfile_map:
households: householdpersons: persontours: tourtrips: trip

If a run should skip raw prepare and use externally managed canonical prepared tables instead, point it at those files with runs[*].prepared_table_map:

runs:
- dir: path\to\raw_runlabel: Raw Run
- label: Custom Prepared Runprepared_table_map:
households: path\to\custom\households.parquetpersons: path\to\custom\persons.csvtours: path\to\custom\tours.parquettrips: path\to\custom\trips.csvjoint_tour_participants: path\to\custom\joint_tour_participants.parquetland_use: path\to\custom\land_use.csv

prepared_table_map is intended for canonical prepared tables that were already skimjoined and then optionally filtered or otherwise post-processed outside this repo. When a run uses prepared_table_map, the workflow loads those prepared tables directly and does not rerun raw prepare or integrated skimjoin for that run.

If a run already has dashboard-ready summary tables, point directly at those files with runs[*].summary_table_map:

runs:
- label: Summary Only Demosummary_table_map:
population_totals: path\to\summaries\population_totals.csvtraffic_count_comparisons: path\to\summaries\traffic_count_comparisons.parquet

summary_table_map uses registered summary IDs as keys, accepts explicit .csv or .parquet paths, and resolves relative paths from the config file directory. Mapped summaries are expected to already use the dashboard's canonical columns. During summarize they override the listed generated summaries; missing summaries can still be generated from raw/prepared inputs when those inputs exist. Some registered summary IDs are external/demo-only and are not generated by default for raw/prepared runs, which avoids writing __empty__ cache CSVs just to make those IDs available to summary_table_map.

Integrated skim enrichment can now be selected per run without forcing one shared skimjoin config for every skim structure. Keep the explicit skimjoin YAML logic in separate files, then choose the file and optional project-input overrides per run:

skimjoin:
defaults:
config_path: configs/skimjoin_default.yamlruns:
- dir: path\to\run_alabel: Run Askimjoin:
config_path: configs/skimjoin_odot_series15.yamlskim_files:
- path\to\run_a\skims\*.omx
- path\to\run_a\skims\maz_stop_walk.csvnetwork_los_file: path\to\run_a\network_los.yaml
- dir: path\to\run_blabel: Run Bskimjoin:
config_path: configs/skimjoin_combined_walk.yamlskim_files:
- path\to\run_b\skims\*.omx

Skimjoin override rules:

  • runs[*].skimjoin.config_path overrides global skimjoin.config_path.
  • runs[*].skimjoin.skim_files overrides the selected skimjoin config's project.skim_files.
  • runs[*].skimjoin.network_los_file overrides the selected skimjoin config's project.network_los_file.
  • skimjoin.failure_policy defaults to record; use error when skimjoin failures must stop a validation or batch run.
  • If a run omits runs[*].skimjoin, it uses the global skimjoin settings exactly as before.

Recommended rule of thumb:

  • If runs differ only by skim file locations, share one skimjoin config and override runs[*].skimjoin.skim_files.
  • If runs differ only by period definitions, share one skimjoin config and override runs[*].skimjoin.network_los_file.
  • If runs differ by lookup logic, fallback behavior, combined vs split components, or directional semantics, use different skimjoin config files.

VOT bin preparation stays in prepare.vot_bins and remains run-aware by run label.

Skimjoin dimensions are now standardized under dimensions, while activitysim only carries the structural trip/tour fields. The recommended integrated-runtime pattern is:

activitysim:
trip_mode_column: trip_modetrip_id_column: trip_idtour_mode_column: tour_modetour_id_column: tour_idoutbound_column: outbounddimensions:
PERIOD:
source_columns:
trip_source_column: depart_houroutbound_tour_source_column: start_hourinbound_tour_source_column: first_inbound_trip_departvalues_from_network_los: truevalues:
8: AM17: PMVOT:
source_columns:
trip_source_column: vot_binoutbound_tour_source_column: vot_bininbound_tour_source_column: vot_binvalues:
L: LM: MH: H

Period behavior is directional by design:

  • trips use dimensions.PERIOD.source_columns.trip_source_column
  • outbound tours use dimensions.PERIOD.source_columns.outbound_tour_source_column
  • inbound tours use dimensions.PERIOD.source_columns.inbound_tour_source_column

In the standard prepare workflow, first_inbound_trip_depart is derived from the first inbound trip on each tour before integrated skimjoin runs.

Prepared endpoint columns are also standardized before skimjoin runs:

  • prepared trips and tours always include OTAZ and DTAZ
  • when zones.use_maz: true, prepare also materializes o_maz and d_maz
  • inbound tour lookups reuse those same column names, while skimjoin swaps their logical direction in the inbound tour context

The normal prepare step can also write prepared caches as CSV when needed:

prepare:
output:
file_format: csvvalidation:
relationship_checks: warn

Important path rules:

  • root is resolved relative to the config file if you give a relative path.
  • The prepared cache is created automatically next to root as prepared_cache/.
  • runs[*].dir should point at an ActivitySim output directory.
  • prepare.distance_skim.file may be absolute, or relative to each run directory.
  • File entries under files can be bare stems like final_trips or explicit filenames like final_trips.csv.
  • runs[*].file_map uses the same filename rules as files, but applies only to that run.
  • runs[*].prepared_table_map must use explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • runs[*].summary_table_map must use registered summary IDs with explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • prepare.output.file_format controls how standard prepared caches are written; supported values are parquet and csv, with parquet as the default.
  • prepare.validation.relationship_checks controls prepared-table foreign-key validation. Use warn to log inconsistencies and continue, error to fail the run, or off to skip the checks.
  • dashboard.export.output_path, when relative, is resolved from root.

Config Reference

These are the sections most people need to touch:

SectionPurpose
rootWhere summary caches are stored
pipelineDefault workflow steps, dashboard mode, and overwrite behavior
runsRun directories, display labels, and optional per-run skim, raw file-map, custom prepared-table map, custom summary-table map, and weight overrides
prepare.distance_skimDefault distance skim file and matrix name used by summaries
zonesMAZ/TAZ settings for skim joins and zone normalization
filesDefault ActivitySim output file stems or filenames used unless a run overrides them
columnsColumn aliases when outputs use non-default names
prepare.output.file_formatOn-disk format for prepared caches written by the normal prepare workflow
prepare.validation.relationship_checksWhether cross-table prepared-key validation is disabled, warns, or errors
prepare.student_typesOptional school/university enrollment definitions for shadow pricing pages
dashboard.titleTitle used in the live dashboard and HTML export
dashboard.include_notesShow per-plot and per-table calculation notes in the live dashboard and HTML export (default: true)
dashboard.live.pagesOrdered list of live pages/groups to show
dashboard.exportExport-only output path, page selection, and selector-state controls
display.run_colorsPlot colors by run
display.labelsPresentation-only labels and ordering for dashboard/export
weighting.modesNamed weighting alternatives backed by household, person, and/or trip columns
extensionsAdvanced importable weighting calculations and their summary-affecting settings
summarize.weighting_modesOrdered built-in, declarative, or custom weighting-mode IDs to build
summarize.failure_policyrecord keeps failed summaries visible as diagnostics; error stops immediately on a builder exception
summarize.geographyOptional configured district/county/zone mappings
summarize.pnr_tour_modesWhich tour modes count as park-and-ride in summary builders
summarize.group_*_tour_purposesSummary-time purpose regrouping switches
summarize.category_normalizationSummary-affecting category normalization/regrouping
modesOptional mode ordering and grouped mode display
display.labels.person_typeOptional display labels for ptype values

Weighting rules:

  • If a run sets hh_weight_col, person_weight_col, or trip_weight_col, those are used.
  • Otherwise, if a sample_rate column is available, weights are derived from it.
  • Otherwise, weights default to 1.
  • weighting.modes can select additional prepared household, person, and trip columns as named alternatives without replacing the primary weighted mode.

Geography summary notes:

  • Summaries may emit all_geographies total rows independently of the geography config.
  • Native prepared geographies such as home_taz, home_county, and home_mpo may appear whenever those columns are available in prepared data, even when summarize.geography.enabled: false.
  • summarize.geography controls additional mapped geography aggregations, such as home_geo__school_district, work_geo__county, or land_use_geo__district.

Removed config notes:

  • Prefer the canonical top-level schema: root, pipeline, dashboard, display, summarize, segment, and skimjoin.
  • Older keys such as processor.root, summaries.weighting_modes, visualizer.dashboard_pages, top-level run_colors, top-level summary_categories, and top-level student_types are rejected with their canonical replacement.

Geography note:

  • summarize.geography.enabled: false disables mapped geography aggregation columns. Set it to true for aggregation-based geography summaries.

Category config note:

  • Use summarize.category_normalization when a mapping changes summary values, grouping membership, or canonical category values.
  • Use display.labels when a change is cosmetic and should only affect dashboard/export labels or ordering.

Live Pages And Export Pages

dashboard.live.pages controls the live dashboard only. dashboard.export controls what goes into the standalone HTML export.

Current top-level page ids are:

  • overview
  • long_term_choices
  • daily_travel
  • joint_travel
  • tour_summaries
  • trip_summaries
  • validation
  • raw_trip_demo

Grouped page ids support either the whole group or specific child pages. For example:

dashboard:
# Set to false to omit all per-plot and per-table calculation notes.include_notes: truelive:
pages:
- overview
- long_term_choices:
- individual_choices
- mandatory_location_choice
- shadow_pricing
- daily_travel: default
- tour_summaries: all
- trip_summaries:
- trip_mode
- trip_stop_time

Notes:

  • default means "the group's default enabled children".
  • all means every child page in the group.
  • A plain group id like tour_summaries behaves like the group's default selection.
  • raw_trip_demo is disabled by default and requests prepared trip tables, so keep it out unless you explicitly want that behavior.

For HTML export, start with the live page set and override selector states or parts as needed:

dashboard:
export:
dashboard:
weighting: [unweighted]values: [percent]exclude_groups: [validation]pages:
long_term_choices:
shadow_pricing:
geography_level: [all]student_type: [all]parts:
workplace_table:
enabled: falseschool_table:
enabled: false

Rules worth remembering:

  • If dashboard.live.pages is omitted, the app uses its built-in default page set.
  • Export always starts from the live page set. Entries under dashboard.export.pages modify matching pages; they are not an allow-list.
  • Export selector requests accept default, all, or a list of explicit values.
  • Set a page override's enabled to false, or use dashboard.export.exclude_pages / exclude_groups, to remove pages from export without changing the live dashboard.

Run Modes

The CLI exposes three workflow steps:

  1. prepare
  2. summarize
  3. dashboard

Common commands:

CommandWhat it does
python run.py --config local_config.yamlReuse or build summaries, then start the live dashboard
python run.py --config local_config.yaml --prepare-onlyBuild prepared caches and exit
python run.py --config local_config.yaml --summarizeReuse or build summary caches and exit
python run.py --config local_config.yaml --summarize --dashboardExplicit form of the default live workflow
python run.py --config local_config.yaml --dashboardStart the dashboard from existing summary caches for the configured runs
python run.py --config local_config.yaml --prepare --summarize --dashboardForce the full prepare -> summarize -> dashboard chain in one run
python run.py --config local_config.yaml --from-csvsStart the dashboard from existing summary caches only
python run.py --config local_config.yaml --from-csvs --export-html output.htmlBuild a standalone HTML export from existing summary caches
python run.py --config local_config.yaml --summarize --write-csvsRebuild summaries and write fresh cache files
python run.py --config local_config.yaml --summarize --skip-summary-cache-writeBuild summaries for this run without writing cache updates
python run.py --config local_config.yaml --summarize --refresh-summary-cacheDelete and rebuild summary caches for the selected runs
python run.py --config local_config.yaml --summarize --refresh-prepared-cacheRebuild summaries from freshly prepared tables instead of prepared-cache hits
python run.py --config local_config.yaml --prepare --summarize --refresh-cachesDelete and rebuild both prepared and summary caches for the selected runs

Behavior details:

  • --from-csvs is cache-only: it reads visualizer summary-cache directories with manifests, not loose summary CSVs.
  • --from-csvs path\to\cache1 path\to\cache2 lets you point directly at specific summary cache directories.
  • Use runs[*].summary_table_map when you have loose dashboard-ready summary files instead of visualizer cache directories.
  • --dashboard by itself is valid when summary caches already exist for the configured runs.
  • During summarize, the app will reuse prepared cache when possible and rebuild from raw outputs only when needed.
  • --refresh-prepared-cache deletes the selected runs' prepared-cache directories first, then disables prepared-cache reuse for that invocation.
  • --refresh-summary-cache deletes the selected runs' summary-cache directories first, then disables summary-cache reuse for that invocation.
  • --refresh-caches is shorthand for both refresh flags together.

Cache Layout

Prepared caches are written automatically next to the summary cache root:

<summary_root_parent>/
prepared_cache/
<run_key>/
manifest.json
households.parquet|csv
persons.parquet|csv
tours.parquet|csv
trips.parquet|csv
joint_tour_participants.parquet|csv
land_use.parquet|csv

Summary caches are written under root:

<summary_root>/
<run_key>/
manifest.json
weighted/
unweighted/

Both cache layers validate manifests before reuse. Cache invalidation is driven by:

  • the run inputs
  • the prepare and summary config digests
  • the prepared-manifest identity used to build summary caches
  • per-summary summary digests inside the summary-cache manifest

That means presentation-only config changes usually do not force summary rebuilds, and adding a newly requested summary can backfill just that table instead of rebuilding the entire summary bundle.

CLI Overrides

You can override runs on the command line instead of putting them in the config:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build"

Optional per-run skim overrides can be supplied in the same order:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build" ^
--run-skim C:\path\to\base_skims.omx C:\path\to\build_skims.omx

Use null, None, or an empty string in --run-skim to fall back to the configured prepare.distance_skim.file.

Codebase Map

activitysim_visualizer/
|-- run.py
|-- runtime/
| |-- workflows/
|-- runtime/
| `-- config/
|-- processor/
| |-- prepare/
| |-- summarize/
| `-- models.py
|-- dashboard/
| |-- app.py
| |-- export/
| |-- page_base.py
| |-- page_declarations.py
| |-- page_diagnostics.py
| |-- page_features.py
| |-- page_lifecycle.py
| |-- page_navigation.py
| |-- page_definitions.py
| |-- page_registry.py
| |-- state.py
| `-- pages/
`-- tests/

Documentation

The main user and contributor documentation lives in the wiki/ chapter set. Start with:

The wiki is the sole documentation source. Add or revise a wiki chapter instead of creating a parallel documentation tree.

Documentation Maintenance Checklist

When behavior changes, update docs in the same change:

  • New config key or config behavior: update chapters 11 and 13.
  • New summary declaration or contract: update chapter 23 and regenerate catalogs.
  • New page, selector, or plotting behavior: update chapters 31 through 33 and regenerate catalogs.
  • New export payload/runtime behavior: update chapter 34.
  • Architecture or runtime-flow changes: update chapters 12, 20, and 30 as applicable.

Tests

See Developer Workflows for the normal test loop and Testing for the fast/full split and offline-export boundary.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - OrMSC/activitysim_visualizer · GitHub
Skip to content

Repository files navigation

ActivitySim Visualizer

activitysim_visualizer is a Panel-based dashboard for exploring and comparing ActivitySim outputs. It can:

  • compare multiple model runs side by side
  • build and reuse prepared and summary caches
  • serve a live local dashboard
  • export a standalone HTML version for offline sharing

Quick Start

Install dependencies with uv:

uv sync --locked

Notebook tooling is optional; install it only when working with the repository's notebooks:

uv sync --locked --group notebooks

If uv sync fails because of a hardlink issue, retry with:

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

Create a project-specific config:

Copy-Item config.yaml local_config.yaml

Edit local_config.yaml, then run the app with that config:

uv run activitysim-viz --config local_config.yaml

By default, activitysim-viz follows pipeline.steps from the loaded config when no explicit step flags are supplied. The shipped example config defaults to summarize + dashboard, so a normal run will reuse summary caches when possible, rebuild them when needed, and then start the live dashboard on http://localhost:5006.

Dashboard Pages

Dashboard pages now use one shared authoring model:

  • page classes use @dashboard_page(...) and subclass DashboardPage
  • dropdowns use select(...); custom widgets use selector(...)
  • dynamic selectors declare an option provider and default policy
  • refreshable regions are registered with section(...)
  • large pages compose related selectors and sections with feature(...)
  • repeated chart transforms use query(...) without page-authored cache keys
  • live refresh and export metadata both derive from those registrations

The main shared page-helper modules live under dashboard/helpers/:

  • category_helpers.py
  • geography_helpers.py
  • person_type_helpers.py
  • time_distance_helpers.py
  • comparison_helpers.py

If you are adding or refactoring a page, start with the dashboard page recipes and figures/widgets guide. The dashboard extension cookbook covers the complete contributor path.

Config Setup

The repo ships with config.yaml as a template. In practice, most people should:

  1. Copy config.yaml to local_config.yaml or another machine-specific file.
  2. Update the runs section to point at real ActivitySim output folders.
  3. Update prepare.distance_skim, zones, and files if your model layout differs from the defaults.
  4. Run with --config your_file.yaml.

The canonical config layout is organized around a few top-level sections:

root: artifacts/log_level: INFOpipeline:
steps: [summarize, dashboard]dashboard_mode: liveoverwrite: falseprepare: ...summarize: ...segment: ...dashboard: ...display: ...skimjoin: ...extensions: ...

Removed keys such as processor.*, summaries.*, visualizer.*, top-level dashboard_labels, and top-level run_colors now fail validation and name the canonical replacement. Unknown keys also fail instead of being silently ignored.

The minimum useful config is usually:

root: artifacts/summary_cachepipeline:
steps:
- summarize
- dashboarddashboard_mode: liveruns:
- dir: path\to\run1label: Base
- dir: path\to\run2label: Buildskimjoin:
distance_skim:
file: path\to\skims.omxmatrix: SOV_DIST__MDzones:
use_maz: falsemaz_col: zone_idtaz_col: TAZfiles:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsjoint_tour_participants: final_joint_tour_participantsland_use: final_land_use

If runs use different raw filenames, keep files: as the default mapping and override only the differences inside runs[*].file_map:

files:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsruns:
- dir: path\to\run1label: Basefile_map:
households: final_hhtrips: trip_linked
- dir: path\to\run2label: Buildfile_map:
households: householdpersons: persontours: tourtrips: trip

If a run should skip raw prepare and use externally managed canonical prepared tables instead, point it at those files with runs[*].prepared_table_map:

runs:
- dir: path\to\raw_runlabel: Raw Run
- label: Custom Prepared Runprepared_table_map:
households: path\to\custom\households.parquetpersons: path\to\custom\persons.csvtours: path\to\custom\tours.parquettrips: path\to\custom\trips.csvjoint_tour_participants: path\to\custom\joint_tour_participants.parquetland_use: path\to\custom\land_use.csv

prepared_table_map is intended for canonical prepared tables that were already skimjoined and then optionally filtered or otherwise post-processed outside this repo. When a run uses prepared_table_map, the workflow loads those prepared tables directly and does not rerun raw prepare or integrated skimjoin for that run.

If a run already has dashboard-ready summary tables, point directly at those files with runs[*].summary_table_map:

runs:
- label: Summary Only Demosummary_table_map:
population_totals: path\to\summaries\population_totals.csvtraffic_count_comparisons: path\to\summaries\traffic_count_comparisons.parquet

summary_table_map uses registered summary IDs as keys, accepts explicit .csv or .parquet paths, and resolves relative paths from the config file directory. Mapped summaries are expected to already use the dashboard's canonical columns. During summarize they override the listed generated summaries; missing summaries can still be generated from raw/prepared inputs when those inputs exist. Some registered summary IDs are external/demo-only and are not generated by default for raw/prepared runs, which avoids writing __empty__ cache CSVs just to make those IDs available to summary_table_map.

Integrated skim enrichment can now be selected per run without forcing one shared skimjoin config for every skim structure. Keep the explicit skimjoin YAML logic in separate files, then choose the file and optional project-input overrides per run:

skimjoin:
defaults:
config_path: configs/skimjoin_default.yamlruns:
- dir: path\to\run_alabel: Run Askimjoin:
config_path: configs/skimjoin_odot_series15.yamlskim_files:
- path\to\run_a\skims\*.omx
- path\to\run_a\skims\maz_stop_walk.csvnetwork_los_file: path\to\run_a\network_los.yaml
- dir: path\to\run_blabel: Run Bskimjoin:
config_path: configs/skimjoin_combined_walk.yamlskim_files:
- path\to\run_b\skims\*.omx

Skimjoin override rules:

  • runs[*].skimjoin.config_path overrides global skimjoin.config_path.
  • runs[*].skimjoin.skim_files overrides the selected skimjoin config's project.skim_files.
  • runs[*].skimjoin.network_los_file overrides the selected skimjoin config's project.network_los_file.
  • skimjoin.failure_policy defaults to record; use error when skimjoin failures must stop a validation or batch run.
  • If a run omits runs[*].skimjoin, it uses the global skimjoin settings exactly as before.

Recommended rule of thumb:

  • If runs differ only by skim file locations, share one skimjoin config and override runs[*].skimjoin.skim_files.
  • If runs differ only by period definitions, share one skimjoin config and override runs[*].skimjoin.network_los_file.
  • If runs differ by lookup logic, fallback behavior, combined vs split components, or directional semantics, use different skimjoin config files.

VOT bin preparation stays in prepare.vot_bins and remains run-aware by run label.

Skimjoin dimensions are now standardized under dimensions, while activitysim only carries the structural trip/tour fields. The recommended integrated-runtime pattern is:

activitysim:
trip_mode_column: trip_modetrip_id_column: trip_idtour_mode_column: tour_modetour_id_column: tour_idoutbound_column: outbounddimensions:
PERIOD:
source_columns:
trip_source_column: depart_houroutbound_tour_source_column: start_hourinbound_tour_source_column: first_inbound_trip_departvalues_from_network_los: truevalues:
8: AM17: PMVOT:
source_columns:
trip_source_column: vot_binoutbound_tour_source_column: vot_bininbound_tour_source_column: vot_binvalues:
L: LM: MH: H

Period behavior is directional by design:

  • trips use dimensions.PERIOD.source_columns.trip_source_column
  • outbound tours use dimensions.PERIOD.source_columns.outbound_tour_source_column
  • inbound tours use dimensions.PERIOD.source_columns.inbound_tour_source_column

In the standard prepare workflow, first_inbound_trip_depart is derived from the first inbound trip on each tour before integrated skimjoin runs.

Prepared endpoint columns are also standardized before skimjoin runs:

  • prepared trips and tours always include OTAZ and DTAZ
  • when zones.use_maz: true, prepare also materializes o_maz and d_maz
  • inbound tour lookups reuse those same column names, while skimjoin swaps their logical direction in the inbound tour context

The normal prepare step can also write prepared caches as CSV when needed:

prepare:
output:
file_format: csvvalidation:
relationship_checks: warn

Important path rules:

  • root is resolved relative to the config file if you give a relative path.
  • The prepared cache is created automatically next to root as prepared_cache/.
  • runs[*].dir should point at an ActivitySim output directory.
  • prepare.distance_skim.file may be absolute, or relative to each run directory.
  • File entries under files can be bare stems like final_trips or explicit filenames like final_trips.csv.
  • runs[*].file_map uses the same filename rules as files, but applies only to that run.
  • runs[*].prepared_table_map must use explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • runs[*].summary_table_map must use registered summary IDs with explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • prepare.output.file_format controls how standard prepared caches are written; supported values are parquet and csv, with parquet as the default.
  • prepare.validation.relationship_checks controls prepared-table foreign-key validation. Use warn to log inconsistencies and continue, error to fail the run, or off to skip the checks.
  • dashboard.export.output_path, when relative, is resolved from root.

Config Reference

These are the sections most people need to touch:

SectionPurpose
rootWhere summary caches are stored
pipelineDefault workflow steps, dashboard mode, and overwrite behavior
runsRun directories, display labels, and optional per-run skim, raw file-map, custom prepared-table map, custom summary-table map, and weight overrides
prepare.distance_skimDefault distance skim file and matrix name used by summaries
zonesMAZ/TAZ settings for skim joins and zone normalization
filesDefault ActivitySim output file stems or filenames used unless a run overrides them
columnsColumn aliases when outputs use non-default names
prepare.output.file_formatOn-disk format for prepared caches written by the normal prepare workflow
prepare.validation.relationship_checksWhether cross-table prepared-key validation is disabled, warns, or errors
prepare.student_typesOptional school/university enrollment definitions for shadow pricing pages
dashboard.titleTitle used in the live dashboard and HTML export
dashboard.include_notesShow per-plot and per-table calculation notes in the live dashboard and HTML export (default: true)
dashboard.live.pagesOrdered list of live pages/groups to show
dashboard.exportExport-only output path, page selection, and selector-state controls
display.run_colorsPlot colors by run
display.labelsPresentation-only labels and ordering for dashboard/export
weighting.modesNamed weighting alternatives backed by household, person, and/or trip columns
extensionsAdvanced importable weighting calculations and their summary-affecting settings
summarize.weighting_modesOrdered built-in, declarative, or custom weighting-mode IDs to build
summarize.failure_policyrecord keeps failed summaries visible as diagnostics; error stops immediately on a builder exception
summarize.geographyOptional configured district/county/zone mappings
summarize.pnr_tour_modesWhich tour modes count as park-and-ride in summary builders
summarize.group_*_tour_purposesSummary-time purpose regrouping switches
summarize.category_normalizationSummary-affecting category normalization/regrouping
modesOptional mode ordering and grouped mode display
display.labels.person_typeOptional display labels for ptype values

Weighting rules:

  • If a run sets hh_weight_col, person_weight_col, or trip_weight_col, those are used.
  • Otherwise, if a sample_rate column is available, weights are derived from it.
  • Otherwise, weights default to 1.
  • weighting.modes can select additional prepared household, person, and trip columns as named alternatives without replacing the primary weighted mode.

Geography summary notes:

  • Summaries may emit all_geographies total rows independently of the geography config.
  • Native prepared geographies such as home_taz, home_county, and home_mpo may appear whenever those columns are available in prepared data, even when summarize.geography.enabled: false.
  • summarize.geography controls additional mapped geography aggregations, such as home_geo__school_district, work_geo__county, or land_use_geo__district.

Removed config notes:

  • Prefer the canonical top-level schema: root, pipeline, dashboard, display, summarize, segment, and skimjoin.
  • Older keys such as processor.root, summaries.weighting_modes, visualizer.dashboard_pages, top-level run_colors, top-level summary_categories, and top-level student_types are rejected with their canonical replacement.

Geography note:

  • summarize.geography.enabled: false disables mapped geography aggregation columns. Set it to true for aggregation-based geography summaries.

Category config note:

  • Use summarize.category_normalization when a mapping changes summary values, grouping membership, or canonical category values.
  • Use display.labels when a change is cosmetic and should only affect dashboard/export labels or ordering.

Live Pages And Export Pages

dashboard.live.pages controls the live dashboard only. dashboard.export controls what goes into the standalone HTML export.

Current top-level page ids are:

  • overview
  • long_term_choices
  • daily_travel
  • joint_travel
  • tour_summaries
  • trip_summaries
  • validation
  • raw_trip_demo

Grouped page ids support either the whole group or specific child pages. For example:

dashboard:
# Set to false to omit all per-plot and per-table calculation notes.include_notes: truelive:
pages:
- overview
- long_term_choices:
- individual_choices
- mandatory_location_choice
- shadow_pricing
- daily_travel: default
- tour_summaries: all
- trip_summaries:
- trip_mode
- trip_stop_time

Notes:

  • default means "the group's default enabled children".
  • all means every child page in the group.
  • A plain group id like tour_summaries behaves like the group's default selection.
  • raw_trip_demo is disabled by default and requests prepared trip tables, so keep it out unless you explicitly want that behavior.

For HTML export, start with the live page set and override selector states or parts as needed:

dashboard:
export:
dashboard:
weighting: [unweighted]values: [percent]exclude_groups: [validation]pages:
long_term_choices:
shadow_pricing:
geography_level: [all]student_type: [all]parts:
workplace_table:
enabled: falseschool_table:
enabled: false

Rules worth remembering:

  • If dashboard.live.pages is omitted, the app uses its built-in default page set.
  • Export always starts from the live page set. Entries under dashboard.export.pages modify matching pages; they are not an allow-list.
  • Export selector requests accept default, all, or a list of explicit values.
  • Set a page override's enabled to false, or use dashboard.export.exclude_pages / exclude_groups, to remove pages from export without changing the live dashboard.

Run Modes

The CLI exposes three workflow steps:

  1. prepare
  2. summarize
  3. dashboard

Common commands:

CommandWhat it does
python run.py --config local_config.yamlReuse or build summaries, then start the live dashboard
python run.py --config local_config.yaml --prepare-onlyBuild prepared caches and exit
python run.py --config local_config.yaml --summarizeReuse or build summary caches and exit
python run.py --config local_config.yaml --summarize --dashboardExplicit form of the default live workflow
python run.py --config local_config.yaml --dashboardStart the dashboard from existing summary caches for the configured runs
python run.py --config local_config.yaml --prepare --summarize --dashboardForce the full prepare -> summarize -> dashboard chain in one run
python run.py --config local_config.yaml --from-csvsStart the dashboard from existing summary caches only
python run.py --config local_config.yaml --from-csvs --export-html output.htmlBuild a standalone HTML export from existing summary caches
python run.py --config local_config.yaml --summarize --write-csvsRebuild summaries and write fresh cache files
python run.py --config local_config.yaml --summarize --skip-summary-cache-writeBuild summaries for this run without writing cache updates
python run.py --config local_config.yaml --summarize --refresh-summary-cacheDelete and rebuild summary caches for the selected runs
python run.py --config local_config.yaml --summarize --refresh-prepared-cacheRebuild summaries from freshly prepared tables instead of prepared-cache hits
python run.py --config local_config.yaml --prepare --summarize --refresh-cachesDelete and rebuild both prepared and summary caches for the selected runs

Behavior details:

  • --from-csvs is cache-only: it reads visualizer summary-cache directories with manifests, not loose summary CSVs.
  • --from-csvs path\to\cache1 path\to\cache2 lets you point directly at specific summary cache directories.
  • Use runs[*].summary_table_map when you have loose dashboard-ready summary files instead of visualizer cache directories.
  • --dashboard by itself is valid when summary caches already exist for the configured runs.
  • During summarize, the app will reuse prepared cache when possible and rebuild from raw outputs only when needed.
  • --refresh-prepared-cache deletes the selected runs' prepared-cache directories first, then disables prepared-cache reuse for that invocation.
  • --refresh-summary-cache deletes the selected runs' summary-cache directories first, then disables summary-cache reuse for that invocation.
  • --refresh-caches is shorthand for both refresh flags together.

Cache Layout

Prepared caches are written automatically next to the summary cache root:

<summary_root_parent>/
prepared_cache/
<run_key>/
manifest.json
households.parquet|csv
persons.parquet|csv
tours.parquet|csv
trips.parquet|csv
joint_tour_participants.parquet|csv
land_use.parquet|csv

Summary caches are written under root:

<summary_root>/
<run_key>/
manifest.json
weighted/
unweighted/

Both cache layers validate manifests before reuse. Cache invalidation is driven by:

  • the run inputs
  • the prepare and summary config digests
  • the prepared-manifest identity used to build summary caches
  • per-summary summary digests inside the summary-cache manifest

That means presentation-only config changes usually do not force summary rebuilds, and adding a newly requested summary can backfill just that table instead of rebuilding the entire summary bundle.

CLI Overrides

You can override runs on the command line instead of putting them in the config:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build"

Optional per-run skim overrides can be supplied in the same order:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build" ^
--run-skim C:\path\to\base_skims.omx C:\path\to\build_skims.omx

Use null, None, or an empty string in --run-skim to fall back to the configured prepare.distance_skim.file.

Codebase Map

activitysim_visualizer/
|-- run.py
|-- runtime/
| |-- workflows/
|-- runtime/
| `-- config/
|-- processor/
| |-- prepare/
| |-- summarize/
| `-- models.py
|-- dashboard/
| |-- app.py
| |-- export/
| |-- page_base.py
| |-- page_declarations.py
| |-- page_diagnostics.py
| |-- page_features.py
| |-- page_lifecycle.py
| |-- page_navigation.py
| |-- page_definitions.py
| |-- page_registry.py
| |-- state.py
| `-- pages/
`-- tests/

Documentation

The main user and contributor documentation lives in the wiki/ chapter set. Start with:

The wiki is the sole documentation source. Add or revise a wiki chapter instead of creating a parallel documentation tree.

Documentation Maintenance Checklist

When behavior changes, update docs in the same change:

  • New config key or config behavior: update chapters 11 and 13.
  • New summary declaration or contract: update chapter 23 and regenerate catalogs.
  • New page, selector, or plotting behavior: update chapters 31 through 33 and regenerate catalogs.
  • New export payload/runtime behavior: update chapter 34.
  • Architecture or runtime-flow changes: update chapters 12, 20, and 30 as applicable.

Tests

See Developer Workflows for the normal test loop and Testing for the fast/full split and offline-export boundary.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', '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('^' + ".*" + ' GitHub - OrMSC/activitysim_visualizer · GitHub
Skip to content

Repository files navigation

ActivitySim Visualizer

activitysim_visualizer is a Panel-based dashboard for exploring and comparing ActivitySim outputs. It can:

  • compare multiple model runs side by side
  • build and reuse prepared and summary caches
  • serve a live local dashboard
  • export a standalone HTML version for offline sharing

Quick Start

Install dependencies with uv:

uv sync --locked

Notebook tooling is optional; install it only when working with the repository's notebooks:

uv sync --locked --group notebooks

If uv sync fails because of a hardlink issue, retry with:

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

Create a project-specific config:

Copy-Item config.yaml local_config.yaml

Edit local_config.yaml, then run the app with that config:

uv run activitysim-viz --config local_config.yaml

By default, activitysim-viz follows pipeline.steps from the loaded config when no explicit step flags are supplied. The shipped example config defaults to summarize + dashboard, so a normal run will reuse summary caches when possible, rebuild them when needed, and then start the live dashboard on http://localhost:5006.

Dashboard Pages

Dashboard pages now use one shared authoring model:

  • page classes use @dashboard_page(...) and subclass DashboardPage
  • dropdowns use select(...); custom widgets use selector(...)
  • dynamic selectors declare an option provider and default policy
  • refreshable regions are registered with section(...)
  • large pages compose related selectors and sections with feature(...)
  • repeated chart transforms use query(...) without page-authored cache keys
  • live refresh and export metadata both derive from those registrations

The main shared page-helper modules live under dashboard/helpers/:

  • category_helpers.py
  • geography_helpers.py
  • person_type_helpers.py
  • time_distance_helpers.py
  • comparison_helpers.py

If you are adding or refactoring a page, start with the dashboard page recipes and figures/widgets guide. The dashboard extension cookbook covers the complete contributor path.

Config Setup

The repo ships with config.yaml as a template. In practice, most people should:

  1. Copy config.yaml to local_config.yaml or another machine-specific file.
  2. Update the runs section to point at real ActivitySim output folders.
  3. Update prepare.distance_skim, zones, and files if your model layout differs from the defaults.
  4. Run with --config your_file.yaml.

The canonical config layout is organized around a few top-level sections:

root: artifacts/log_level: INFOpipeline:
steps: [summarize, dashboard]dashboard_mode: liveoverwrite: falseprepare: ...summarize: ...segment: ...dashboard: ...display: ...skimjoin: ...extensions: ...

Removed keys such as processor.*, summaries.*, visualizer.*, top-level dashboard_labels, and top-level run_colors now fail validation and name the canonical replacement. Unknown keys also fail instead of being silently ignored.

The minimum useful config is usually:

root: artifacts/summary_cachepipeline:
steps:
- summarize
- dashboarddashboard_mode: liveruns:
- dir: path\to\run1label: Base
- dir: path\to\run2label: Buildskimjoin:
distance_skim:
file: path\to\skims.omxmatrix: SOV_DIST__MDzones:
use_maz: falsemaz_col: zone_idtaz_col: TAZfiles:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsjoint_tour_participants: final_joint_tour_participantsland_use: final_land_use

If runs use different raw filenames, keep files: as the default mapping and override only the differences inside runs[*].file_map:

files:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsruns:
- dir: path\to\run1label: Basefile_map:
households: final_hhtrips: trip_linked
- dir: path\to\run2label: Buildfile_map:
households: householdpersons: persontours: tourtrips: trip

If a run should skip raw prepare and use externally managed canonical prepared tables instead, point it at those files with runs[*].prepared_table_map:

runs:
- dir: path\to\raw_runlabel: Raw Run
- label: Custom Prepared Runprepared_table_map:
households: path\to\custom\households.parquetpersons: path\to\custom\persons.csvtours: path\to\custom\tours.parquettrips: path\to\custom\trips.csvjoint_tour_participants: path\to\custom\joint_tour_participants.parquetland_use: path\to\custom\land_use.csv

prepared_table_map is intended for canonical prepared tables that were already skimjoined and then optionally filtered or otherwise post-processed outside this repo. When a run uses prepared_table_map, the workflow loads those prepared tables directly and does not rerun raw prepare or integrated skimjoin for that run.

If a run already has dashboard-ready summary tables, point directly at those files with runs[*].summary_table_map:

runs:
- label: Summary Only Demosummary_table_map:
population_totals: path\to\summaries\population_totals.csvtraffic_count_comparisons: path\to\summaries\traffic_count_comparisons.parquet

summary_table_map uses registered summary IDs as keys, accepts explicit .csv or .parquet paths, and resolves relative paths from the config file directory. Mapped summaries are expected to already use the dashboard's canonical columns. During summarize they override the listed generated summaries; missing summaries can still be generated from raw/prepared inputs when those inputs exist. Some registered summary IDs are external/demo-only and are not generated by default for raw/prepared runs, which avoids writing __empty__ cache CSVs just to make those IDs available to summary_table_map.

Integrated skim enrichment can now be selected per run without forcing one shared skimjoin config for every skim structure. Keep the explicit skimjoin YAML logic in separate files, then choose the file and optional project-input overrides per run:

skimjoin:
defaults:
config_path: configs/skimjoin_default.yamlruns:
- dir: path\to\run_alabel: Run Askimjoin:
config_path: configs/skimjoin_odot_series15.yamlskim_files:
- path\to\run_a\skims\*.omx
- path\to\run_a\skims\maz_stop_walk.csvnetwork_los_file: path\to\run_a\network_los.yaml
- dir: path\to\run_blabel: Run Bskimjoin:
config_path: configs/skimjoin_combined_walk.yamlskim_files:
- path\to\run_b\skims\*.omx

Skimjoin override rules:

  • runs[*].skimjoin.config_path overrides global skimjoin.config_path.
  • runs[*].skimjoin.skim_files overrides the selected skimjoin config's project.skim_files.
  • runs[*].skimjoin.network_los_file overrides the selected skimjoin config's project.network_los_file.
  • skimjoin.failure_policy defaults to record; use error when skimjoin failures must stop a validation or batch run.
  • If a run omits runs[*].skimjoin, it uses the global skimjoin settings exactly as before.

Recommended rule of thumb:

  • If runs differ only by skim file locations, share one skimjoin config and override runs[*].skimjoin.skim_files.
  • If runs differ only by period definitions, share one skimjoin config and override runs[*].skimjoin.network_los_file.
  • If runs differ by lookup logic, fallback behavior, combined vs split components, or directional semantics, use different skimjoin config files.

VOT bin preparation stays in prepare.vot_bins and remains run-aware by run label.

Skimjoin dimensions are now standardized under dimensions, while activitysim only carries the structural trip/tour fields. The recommended integrated-runtime pattern is:

activitysim:
trip_mode_column: trip_modetrip_id_column: trip_idtour_mode_column: tour_modetour_id_column: tour_idoutbound_column: outbounddimensions:
PERIOD:
source_columns:
trip_source_column: depart_houroutbound_tour_source_column: start_hourinbound_tour_source_column: first_inbound_trip_departvalues_from_network_los: truevalues:
8: AM17: PMVOT:
source_columns:
trip_source_column: vot_binoutbound_tour_source_column: vot_bininbound_tour_source_column: vot_binvalues:
L: LM: MH: H

Period behavior is directional by design:

  • trips use dimensions.PERIOD.source_columns.trip_source_column
  • outbound tours use dimensions.PERIOD.source_columns.outbound_tour_source_column
  • inbound tours use dimensions.PERIOD.source_columns.inbound_tour_source_column

In the standard prepare workflow, first_inbound_trip_depart is derived from the first inbound trip on each tour before integrated skimjoin runs.

Prepared endpoint columns are also standardized before skimjoin runs:

  • prepared trips and tours always include OTAZ and DTAZ
  • when zones.use_maz: true, prepare also materializes o_maz and d_maz
  • inbound tour lookups reuse those same column names, while skimjoin swaps their logical direction in the inbound tour context

The normal prepare step can also write prepared caches as CSV when needed:

prepare:
output:
file_format: csvvalidation:
relationship_checks: warn

Important path rules:

  • root is resolved relative to the config file if you give a relative path.
  • The prepared cache is created automatically next to root as prepared_cache/.
  • runs[*].dir should point at an ActivitySim output directory.
  • prepare.distance_skim.file may be absolute, or relative to each run directory.
  • File entries under files can be bare stems like final_trips or explicit filenames like final_trips.csv.
  • runs[*].file_map uses the same filename rules as files, but applies only to that run.
  • runs[*].prepared_table_map must use explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • runs[*].summary_table_map must use registered summary IDs with explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • prepare.output.file_format controls how standard prepared caches are written; supported values are parquet and csv, with parquet as the default.
  • prepare.validation.relationship_checks controls prepared-table foreign-key validation. Use warn to log inconsistencies and continue, error to fail the run, or off to skip the checks.
  • dashboard.export.output_path, when relative, is resolved from root.

Config Reference

These are the sections most people need to touch:

SectionPurpose
rootWhere summary caches are stored
pipelineDefault workflow steps, dashboard mode, and overwrite behavior
runsRun directories, display labels, and optional per-run skim, raw file-map, custom prepared-table map, custom summary-table map, and weight overrides
prepare.distance_skimDefault distance skim file and matrix name used by summaries
zonesMAZ/TAZ settings for skim joins and zone normalization
filesDefault ActivitySim output file stems or filenames used unless a run overrides them
columnsColumn aliases when outputs use non-default names
prepare.output.file_formatOn-disk format for prepared caches written by the normal prepare workflow
prepare.validation.relationship_checksWhether cross-table prepared-key validation is disabled, warns, or errors
prepare.student_typesOptional school/university enrollment definitions for shadow pricing pages
dashboard.titleTitle used in the live dashboard and HTML export
dashboard.include_notesShow per-plot and per-table calculation notes in the live dashboard and HTML export (default: true)
dashboard.live.pagesOrdered list of live pages/groups to show
dashboard.exportExport-only output path, page selection, and selector-state controls
display.run_colorsPlot colors by run
display.labelsPresentation-only labels and ordering for dashboard/export
weighting.modesNamed weighting alternatives backed by household, person, and/or trip columns
extensionsAdvanced importable weighting calculations and their summary-affecting settings
summarize.weighting_modesOrdered built-in, declarative, or custom weighting-mode IDs to build
summarize.failure_policyrecord keeps failed summaries visible as diagnostics; error stops immediately on a builder exception
summarize.geographyOptional configured district/county/zone mappings
summarize.pnr_tour_modesWhich tour modes count as park-and-ride in summary builders
summarize.group_*_tour_purposesSummary-time purpose regrouping switches
summarize.category_normalizationSummary-affecting category normalization/regrouping
modesOptional mode ordering and grouped mode display
display.labels.person_typeOptional display labels for ptype values

Weighting rules:

  • If a run sets hh_weight_col, person_weight_col, or trip_weight_col, those are used.
  • Otherwise, if a sample_rate column is available, weights are derived from it.
  • Otherwise, weights default to 1.
  • weighting.modes can select additional prepared household, person, and trip columns as named alternatives without replacing the primary weighted mode.

Geography summary notes:

  • Summaries may emit all_geographies total rows independently of the geography config.
  • Native prepared geographies such as home_taz, home_county, and home_mpo may appear whenever those columns are available in prepared data, even when summarize.geography.enabled: false.
  • summarize.geography controls additional mapped geography aggregations, such as home_geo__school_district, work_geo__county, or land_use_geo__district.

Removed config notes:

  • Prefer the canonical top-level schema: root, pipeline, dashboard, display, summarize, segment, and skimjoin.
  • Older keys such as processor.root, summaries.weighting_modes, visualizer.dashboard_pages, top-level run_colors, top-level summary_categories, and top-level student_types are rejected with their canonical replacement.

Geography note:

  • summarize.geography.enabled: false disables mapped geography aggregation columns. Set it to true for aggregation-based geography summaries.

Category config note:

  • Use summarize.category_normalization when a mapping changes summary values, grouping membership, or canonical category values.
  • Use display.labels when a change is cosmetic and should only affect dashboard/export labels or ordering.

Live Pages And Export Pages

dashboard.live.pages controls the live dashboard only. dashboard.export controls what goes into the standalone HTML export.

Current top-level page ids are:

  • overview
  • long_term_choices
  • daily_travel
  • joint_travel
  • tour_summaries
  • trip_summaries
  • validation
  • raw_trip_demo

Grouped page ids support either the whole group or specific child pages. For example:

dashboard:
# Set to false to omit all per-plot and per-table calculation notes.include_notes: truelive:
pages:
- overview
- long_term_choices:
- individual_choices
- mandatory_location_choice
- shadow_pricing
- daily_travel: default
- tour_summaries: all
- trip_summaries:
- trip_mode
- trip_stop_time

Notes:

  • default means "the group's default enabled children".
  • all means every child page in the group.
  • A plain group id like tour_summaries behaves like the group's default selection.
  • raw_trip_demo is disabled by default and requests prepared trip tables, so keep it out unless you explicitly want that behavior.

For HTML export, start with the live page set and override selector states or parts as needed:

dashboard:
export:
dashboard:
weighting: [unweighted]values: [percent]exclude_groups: [validation]pages:
long_term_choices:
shadow_pricing:
geography_level: [all]student_type: [all]parts:
workplace_table:
enabled: falseschool_table:
enabled: false

Rules worth remembering:

  • If dashboard.live.pages is omitted, the app uses its built-in default page set.
  • Export always starts from the live page set. Entries under dashboard.export.pages modify matching pages; they are not an allow-list.
  • Export selector requests accept default, all, or a list of explicit values.
  • Set a page override's enabled to false, or use dashboard.export.exclude_pages / exclude_groups, to remove pages from export without changing the live dashboard.

Run Modes

The CLI exposes three workflow steps:

  1. prepare
  2. summarize
  3. dashboard

Common commands:

CommandWhat it does
python run.py --config local_config.yamlReuse or build summaries, then start the live dashboard
python run.py --config local_config.yaml --prepare-onlyBuild prepared caches and exit
python run.py --config local_config.yaml --summarizeReuse or build summary caches and exit
python run.py --config local_config.yaml --summarize --dashboardExplicit form of the default live workflow
python run.py --config local_config.yaml --dashboardStart the dashboard from existing summary caches for the configured runs
python run.py --config local_config.yaml --prepare --summarize --dashboardForce the full prepare -> summarize -> dashboard chain in one run
python run.py --config local_config.yaml --from-csvsStart the dashboard from existing summary caches only
python run.py --config local_config.yaml --from-csvs --export-html output.htmlBuild a standalone HTML export from existing summary caches
python run.py --config local_config.yaml --summarize --write-csvsRebuild summaries and write fresh cache files
python run.py --config local_config.yaml --summarize --skip-summary-cache-writeBuild summaries for this run without writing cache updates
python run.py --config local_config.yaml --summarize --refresh-summary-cacheDelete and rebuild summary caches for the selected runs
python run.py --config local_config.yaml --summarize --refresh-prepared-cacheRebuild summaries from freshly prepared tables instead of prepared-cache hits
python run.py --config local_config.yaml --prepare --summarize --refresh-cachesDelete and rebuild both prepared and summary caches for the selected runs

Behavior details:

  • --from-csvs is cache-only: it reads visualizer summary-cache directories with manifests, not loose summary CSVs.
  • --from-csvs path\to\cache1 path\to\cache2 lets you point directly at specific summary cache directories.
  • Use runs[*].summary_table_map when you have loose dashboard-ready summary files instead of visualizer cache directories.
  • --dashboard by itself is valid when summary caches already exist for the configured runs.
  • During summarize, the app will reuse prepared cache when possible and rebuild from raw outputs only when needed.
  • --refresh-prepared-cache deletes the selected runs' prepared-cache directories first, then disables prepared-cache reuse for that invocation.
  • --refresh-summary-cache deletes the selected runs' summary-cache directories first, then disables summary-cache reuse for that invocation.
  • --refresh-caches is shorthand for both refresh flags together.

Cache Layout

Prepared caches are written automatically next to the summary cache root:

<summary_root_parent>/
prepared_cache/
<run_key>/
manifest.json
households.parquet|csv
persons.parquet|csv
tours.parquet|csv
trips.parquet|csv
joint_tour_participants.parquet|csv
land_use.parquet|csv

Summary caches are written under root:

<summary_root>/
<run_key>/
manifest.json
weighted/
unweighted/

Both cache layers validate manifests before reuse. Cache invalidation is driven by:

  • the run inputs
  • the prepare and summary config digests
  • the prepared-manifest identity used to build summary caches
  • per-summary summary digests inside the summary-cache manifest

That means presentation-only config changes usually do not force summary rebuilds, and adding a newly requested summary can backfill just that table instead of rebuilding the entire summary bundle.

CLI Overrides

You can override runs on the command line instead of putting them in the config:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build"

Optional per-run skim overrides can be supplied in the same order:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build" ^
--run-skim C:\path\to\base_skims.omx C:\path\to\build_skims.omx

Use null, None, or an empty string in --run-skim to fall back to the configured prepare.distance_skim.file.

Codebase Map

activitysim_visualizer/
|-- run.py
|-- runtime/
| |-- workflows/
|-- runtime/
| `-- config/
|-- processor/
| |-- prepare/
| |-- summarize/
| `-- models.py
|-- dashboard/
| |-- app.py
| |-- export/
| |-- page_base.py
| |-- page_declarations.py
| |-- page_diagnostics.py
| |-- page_features.py
| |-- page_lifecycle.py
| |-- page_navigation.py
| |-- page_definitions.py
| |-- page_registry.py
| |-- state.py
| `-- pages/
`-- tests/

Documentation

The main user and contributor documentation lives in the wiki/ chapter set. Start with:

The wiki is the sole documentation source. Add or revise a wiki chapter instead of creating a parallel documentation tree.

Documentation Maintenance Checklist

When behavior changes, update docs in the same change:

  • New config key or config behavior: update chapters 11 and 13.
  • New summary declaration or contract: update chapter 23 and regenerate catalogs.
  • New page, selector, or plotting behavior: update chapters 31 through 33 and regenerate catalogs.
  • New export payload/runtime behavior: update chapter 34.
  • Architecture or runtime-flow changes: update chapters 12, 20, and 30 as applicable.

Tests

See Developer Workflows for the normal test loop and Testing for the fast/full split and offline-export boundary.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, '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" + ' GitHub - OrMSC/activitysim_visualizer · GitHub
Skip to content

Repository files navigation

ActivitySim Visualizer

activitysim_visualizer is a Panel-based dashboard for exploring and comparing ActivitySim outputs. It can:

  • compare multiple model runs side by side
  • build and reuse prepared and summary caches
  • serve a live local dashboard
  • export a standalone HTML version for offline sharing

Quick Start

Install dependencies with uv:

uv sync --locked

Notebook tooling is optional; install it only when working with the repository's notebooks:

uv sync --locked --group notebooks

If uv sync fails because of a hardlink issue, retry with:

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

Create a project-specific config:

Copy-Item config.yaml local_config.yaml

Edit local_config.yaml, then run the app with that config:

uv run activitysim-viz --config local_config.yaml

By default, activitysim-viz follows pipeline.steps from the loaded config when no explicit step flags are supplied. The shipped example config defaults to summarize + dashboard, so a normal run will reuse summary caches when possible, rebuild them when needed, and then start the live dashboard on http://localhost:5006.

Dashboard Pages

Dashboard pages now use one shared authoring model:

  • page classes use @dashboard_page(...) and subclass DashboardPage
  • dropdowns use select(...); custom widgets use selector(...)
  • dynamic selectors declare an option provider and default policy
  • refreshable regions are registered with section(...)
  • large pages compose related selectors and sections with feature(...)
  • repeated chart transforms use query(...) without page-authored cache keys
  • live refresh and export metadata both derive from those registrations

The main shared page-helper modules live under dashboard/helpers/:

  • category_helpers.py
  • geography_helpers.py
  • person_type_helpers.py
  • time_distance_helpers.py
  • comparison_helpers.py

If you are adding or refactoring a page, start with the dashboard page recipes and figures/widgets guide. The dashboard extension cookbook covers the complete contributor path.

Config Setup

The repo ships with config.yaml as a template. In practice, most people should:

  1. Copy config.yaml to local_config.yaml or another machine-specific file.
  2. Update the runs section to point at real ActivitySim output folders.
  3. Update prepare.distance_skim, zones, and files if your model layout differs from the defaults.
  4. Run with --config your_file.yaml.

The canonical config layout is organized around a few top-level sections:

root: artifacts/log_level: INFOpipeline:
steps: [summarize, dashboard]dashboard_mode: liveoverwrite: falseprepare: ...summarize: ...segment: ...dashboard: ...display: ...skimjoin: ...extensions: ...

Removed keys such as processor.*, summaries.*, visualizer.*, top-level dashboard_labels, and top-level run_colors now fail validation and name the canonical replacement. Unknown keys also fail instead of being silently ignored.

The minimum useful config is usually:

root: artifacts/summary_cachepipeline:
steps:
- summarize
- dashboarddashboard_mode: liveruns:
- dir: path\to\run1label: Base
- dir: path\to\run2label: Buildskimjoin:
distance_skim:
file: path\to\skims.omxmatrix: SOV_DIST__MDzones:
use_maz: falsemaz_col: zone_idtaz_col: TAZfiles:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsjoint_tour_participants: final_joint_tour_participantsland_use: final_land_use

If runs use different raw filenames, keep files: as the default mapping and override only the differences inside runs[*].file_map:

files:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsruns:
- dir: path\to\run1label: Basefile_map:
households: final_hhtrips: trip_linked
- dir: path\to\run2label: Buildfile_map:
households: householdpersons: persontours: tourtrips: trip

If a run should skip raw prepare and use externally managed canonical prepared tables instead, point it at those files with runs[*].prepared_table_map:

runs:
- dir: path\to\raw_runlabel: Raw Run
- label: Custom Prepared Runprepared_table_map:
households: path\to\custom\households.parquetpersons: path\to\custom\persons.csvtours: path\to\custom\tours.parquettrips: path\to\custom\trips.csvjoint_tour_participants: path\to\custom\joint_tour_participants.parquetland_use: path\to\custom\land_use.csv

prepared_table_map is intended for canonical prepared tables that were already skimjoined and then optionally filtered or otherwise post-processed outside this repo. When a run uses prepared_table_map, the workflow loads those prepared tables directly and does not rerun raw prepare or integrated skimjoin for that run.

If a run already has dashboard-ready summary tables, point directly at those files with runs[*].summary_table_map:

runs:
- label: Summary Only Demosummary_table_map:
population_totals: path\to\summaries\population_totals.csvtraffic_count_comparisons: path\to\summaries\traffic_count_comparisons.parquet

summary_table_map uses registered summary IDs as keys, accepts explicit .csv or .parquet paths, and resolves relative paths from the config file directory. Mapped summaries are expected to already use the dashboard's canonical columns. During summarize they override the listed generated summaries; missing summaries can still be generated from raw/prepared inputs when those inputs exist. Some registered summary IDs are external/demo-only and are not generated by default for raw/prepared runs, which avoids writing __empty__ cache CSVs just to make those IDs available to summary_table_map.

Integrated skim enrichment can now be selected per run without forcing one shared skimjoin config for every skim structure. Keep the explicit skimjoin YAML logic in separate files, then choose the file and optional project-input overrides per run:

skimjoin:
defaults:
config_path: configs/skimjoin_default.yamlruns:
- dir: path\to\run_alabel: Run Askimjoin:
config_path: configs/skimjoin_odot_series15.yamlskim_files:
- path\to\run_a\skims\*.omx
- path\to\run_a\skims\maz_stop_walk.csvnetwork_los_file: path\to\run_a\network_los.yaml
- dir: path\to\run_blabel: Run Bskimjoin:
config_path: configs/skimjoin_combined_walk.yamlskim_files:
- path\to\run_b\skims\*.omx

Skimjoin override rules:

  • runs[*].skimjoin.config_path overrides global skimjoin.config_path.
  • runs[*].skimjoin.skim_files overrides the selected skimjoin config's project.skim_files.
  • runs[*].skimjoin.network_los_file overrides the selected skimjoin config's project.network_los_file.
  • skimjoin.failure_policy defaults to record; use error when skimjoin failures must stop a validation or batch run.
  • If a run omits runs[*].skimjoin, it uses the global skimjoin settings exactly as before.

Recommended rule of thumb:

  • If runs differ only by skim file locations, share one skimjoin config and override runs[*].skimjoin.skim_files.
  • If runs differ only by period definitions, share one skimjoin config and override runs[*].skimjoin.network_los_file.
  • If runs differ by lookup logic, fallback behavior, combined vs split components, or directional semantics, use different skimjoin config files.

VOT bin preparation stays in prepare.vot_bins and remains run-aware by run label.

Skimjoin dimensions are now standardized under dimensions, while activitysim only carries the structural trip/tour fields. The recommended integrated-runtime pattern is:

activitysim:
trip_mode_column: trip_modetrip_id_column: trip_idtour_mode_column: tour_modetour_id_column: tour_idoutbound_column: outbounddimensions:
PERIOD:
source_columns:
trip_source_column: depart_houroutbound_tour_source_column: start_hourinbound_tour_source_column: first_inbound_trip_departvalues_from_network_los: truevalues:
8: AM17: PMVOT:
source_columns:
trip_source_column: vot_binoutbound_tour_source_column: vot_bininbound_tour_source_column: vot_binvalues:
L: LM: MH: H

Period behavior is directional by design:

  • trips use dimensions.PERIOD.source_columns.trip_source_column
  • outbound tours use dimensions.PERIOD.source_columns.outbound_tour_source_column
  • inbound tours use dimensions.PERIOD.source_columns.inbound_tour_source_column

In the standard prepare workflow, first_inbound_trip_depart is derived from the first inbound trip on each tour before integrated skimjoin runs.

Prepared endpoint columns are also standardized before skimjoin runs:

  • prepared trips and tours always include OTAZ and DTAZ
  • when zones.use_maz: true, prepare also materializes o_maz and d_maz
  • inbound tour lookups reuse those same column names, while skimjoin swaps their logical direction in the inbound tour context

The normal prepare step can also write prepared caches as CSV when needed:

prepare:
output:
file_format: csvvalidation:
relationship_checks: warn

Important path rules:

  • root is resolved relative to the config file if you give a relative path.
  • The prepared cache is created automatically next to root as prepared_cache/.
  • runs[*].dir should point at an ActivitySim output directory.
  • prepare.distance_skim.file may be absolute, or relative to each run directory.
  • File entries under files can be bare stems like final_trips or explicit filenames like final_trips.csv.
  • runs[*].file_map uses the same filename rules as files, but applies only to that run.
  • runs[*].prepared_table_map must use explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • runs[*].summary_table_map must use registered summary IDs with explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • prepare.output.file_format controls how standard prepared caches are written; supported values are parquet and csv, with parquet as the default.
  • prepare.validation.relationship_checks controls prepared-table foreign-key validation. Use warn to log inconsistencies and continue, error to fail the run, or off to skip the checks.
  • dashboard.export.output_path, when relative, is resolved from root.

Config Reference

These are the sections most people need to touch:

SectionPurpose
rootWhere summary caches are stored
pipelineDefault workflow steps, dashboard mode, and overwrite behavior
runsRun directories, display labels, and optional per-run skim, raw file-map, custom prepared-table map, custom summary-table map, and weight overrides
prepare.distance_skimDefault distance skim file and matrix name used by summaries
zonesMAZ/TAZ settings for skim joins and zone normalization
filesDefault ActivitySim output file stems or filenames used unless a run overrides them
columnsColumn aliases when outputs use non-default names
prepare.output.file_formatOn-disk format for prepared caches written by the normal prepare workflow
prepare.validation.relationship_checksWhether cross-table prepared-key validation is disabled, warns, or errors
prepare.student_typesOptional school/university enrollment definitions for shadow pricing pages
dashboard.titleTitle used in the live dashboard and HTML export
dashboard.include_notesShow per-plot and per-table calculation notes in the live dashboard and HTML export (default: true)
dashboard.live.pagesOrdered list of live pages/groups to show
dashboard.exportExport-only output path, page selection, and selector-state controls
display.run_colorsPlot colors by run
display.labelsPresentation-only labels and ordering for dashboard/export
weighting.modesNamed weighting alternatives backed by household, person, and/or trip columns
extensionsAdvanced importable weighting calculations and their summary-affecting settings
summarize.weighting_modesOrdered built-in, declarative, or custom weighting-mode IDs to build
summarize.failure_policyrecord keeps failed summaries visible as diagnostics; error stops immediately on a builder exception
summarize.geographyOptional configured district/county/zone mappings
summarize.pnr_tour_modesWhich tour modes count as park-and-ride in summary builders
summarize.group_*_tour_purposesSummary-time purpose regrouping switches
summarize.category_normalizationSummary-affecting category normalization/regrouping
modesOptional mode ordering and grouped mode display
display.labels.person_typeOptional display labels for ptype values

Weighting rules:

  • If a run sets hh_weight_col, person_weight_col, or trip_weight_col, those are used.
  • Otherwise, if a sample_rate column is available, weights are derived from it.
  • Otherwise, weights default to 1.
  • weighting.modes can select additional prepared household, person, and trip columns as named alternatives without replacing the primary weighted mode.

Geography summary notes:

  • Summaries may emit all_geographies total rows independently of the geography config.
  • Native prepared geographies such as home_taz, home_county, and home_mpo may appear whenever those columns are available in prepared data, even when summarize.geography.enabled: false.
  • summarize.geography controls additional mapped geography aggregations, such as home_geo__school_district, work_geo__county, or land_use_geo__district.

Removed config notes:

  • Prefer the canonical top-level schema: root, pipeline, dashboard, display, summarize, segment, and skimjoin.
  • Older keys such as processor.root, summaries.weighting_modes, visualizer.dashboard_pages, top-level run_colors, top-level summary_categories, and top-level student_types are rejected with their canonical replacement.

Geography note:

  • summarize.geography.enabled: false disables mapped geography aggregation columns. Set it to true for aggregation-based geography summaries.

Category config note:

  • Use summarize.category_normalization when a mapping changes summary values, grouping membership, or canonical category values.
  • Use display.labels when a change is cosmetic and should only affect dashboard/export labels or ordering.

Live Pages And Export Pages

dashboard.live.pages controls the live dashboard only. dashboard.export controls what goes into the standalone HTML export.

Current top-level page ids are:

  • overview
  • long_term_choices
  • daily_travel
  • joint_travel
  • tour_summaries
  • trip_summaries
  • validation
  • raw_trip_demo

Grouped page ids support either the whole group or specific child pages. For example:

dashboard:
# Set to false to omit all per-plot and per-table calculation notes.include_notes: truelive:
pages:
- overview
- long_term_choices:
- individual_choices
- mandatory_location_choice
- shadow_pricing
- daily_travel: default
- tour_summaries: all
- trip_summaries:
- trip_mode
- trip_stop_time

Notes:

  • default means "the group's default enabled children".
  • all means every child page in the group.
  • A plain group id like tour_summaries behaves like the group's default selection.
  • raw_trip_demo is disabled by default and requests prepared trip tables, so keep it out unless you explicitly want that behavior.

For HTML export, start with the live page set and override selector states or parts as needed:

dashboard:
export:
dashboard:
weighting: [unweighted]values: [percent]exclude_groups: [validation]pages:
long_term_choices:
shadow_pricing:
geography_level: [all]student_type: [all]parts:
workplace_table:
enabled: falseschool_table:
enabled: false

Rules worth remembering:

  • If dashboard.live.pages is omitted, the app uses its built-in default page set.
  • Export always starts from the live page set. Entries under dashboard.export.pages modify matching pages; they are not an allow-list.
  • Export selector requests accept default, all, or a list of explicit values.
  • Set a page override's enabled to false, or use dashboard.export.exclude_pages / exclude_groups, to remove pages from export without changing the live dashboard.

Run Modes

The CLI exposes three workflow steps:

  1. prepare
  2. summarize
  3. dashboard

Common commands:

CommandWhat it does
python run.py --config local_config.yamlReuse or build summaries, then start the live dashboard
python run.py --config local_config.yaml --prepare-onlyBuild prepared caches and exit
python run.py --config local_config.yaml --summarizeReuse or build summary caches and exit
python run.py --config local_config.yaml --summarize --dashboardExplicit form of the default live workflow
python run.py --config local_config.yaml --dashboardStart the dashboard from existing summary caches for the configured runs
python run.py --config local_config.yaml --prepare --summarize --dashboardForce the full prepare -> summarize -> dashboard chain in one run
python run.py --config local_config.yaml --from-csvsStart the dashboard from existing summary caches only
python run.py --config local_config.yaml --from-csvs --export-html output.htmlBuild a standalone HTML export from existing summary caches
python run.py --config local_config.yaml --summarize --write-csvsRebuild summaries and write fresh cache files
python run.py --config local_config.yaml --summarize --skip-summary-cache-writeBuild summaries for this run without writing cache updates
python run.py --config local_config.yaml --summarize --refresh-summary-cacheDelete and rebuild summary caches for the selected runs
python run.py --config local_config.yaml --summarize --refresh-prepared-cacheRebuild summaries from freshly prepared tables instead of prepared-cache hits
python run.py --config local_config.yaml --prepare --summarize --refresh-cachesDelete and rebuild both prepared and summary caches for the selected runs

Behavior details:

  • --from-csvs is cache-only: it reads visualizer summary-cache directories with manifests, not loose summary CSVs.
  • --from-csvs path\to\cache1 path\to\cache2 lets you point directly at specific summary cache directories.
  • Use runs[*].summary_table_map when you have loose dashboard-ready summary files instead of visualizer cache directories.
  • --dashboard by itself is valid when summary caches already exist for the configured runs.
  • During summarize, the app will reuse prepared cache when possible and rebuild from raw outputs only when needed.
  • --refresh-prepared-cache deletes the selected runs' prepared-cache directories first, then disables prepared-cache reuse for that invocation.
  • --refresh-summary-cache deletes the selected runs' summary-cache directories first, then disables summary-cache reuse for that invocation.
  • --refresh-caches is shorthand for both refresh flags together.

Cache Layout

Prepared caches are written automatically next to the summary cache root:

<summary_root_parent>/
prepared_cache/
<run_key>/
manifest.json
households.parquet|csv
persons.parquet|csv
tours.parquet|csv
trips.parquet|csv
joint_tour_participants.parquet|csv
land_use.parquet|csv

Summary caches are written under root:

<summary_root>/
<run_key>/
manifest.json
weighted/
unweighted/

Both cache layers validate manifests before reuse. Cache invalidation is driven by:

  • the run inputs
  • the prepare and summary config digests
  • the prepared-manifest identity used to build summary caches
  • per-summary summary digests inside the summary-cache manifest

That means presentation-only config changes usually do not force summary rebuilds, and adding a newly requested summary can backfill just that table instead of rebuilding the entire summary bundle.

CLI Overrides

You can override runs on the command line instead of putting them in the config:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build"

Optional per-run skim overrides can be supplied in the same order:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build" ^
--run-skim C:\path\to\base_skims.omx C:\path\to\build_skims.omx

Use null, None, or an empty string in --run-skim to fall back to the configured prepare.distance_skim.file.

Codebase Map

activitysim_visualizer/
|-- run.py
|-- runtime/
| |-- workflows/
|-- runtime/
| `-- config/
|-- processor/
| |-- prepare/
| |-- summarize/
| `-- models.py
|-- dashboard/
| |-- app.py
| |-- export/
| |-- page_base.py
| |-- page_declarations.py
| |-- page_diagnostics.py
| |-- page_features.py
| |-- page_lifecycle.py
| |-- page_navigation.py
| |-- page_definitions.py
| |-- page_registry.py
| |-- state.py
| `-- pages/
`-- tests/

Documentation

The main user and contributor documentation lives in the wiki/ chapter set. Start with:

The wiki is the sole documentation source. Add or revise a wiki chapter instead of creating a parallel documentation tree.

Documentation Maintenance Checklist

When behavior changes, update docs in the same change:

  • New config key or config behavior: update chapters 11 and 13.
  • New summary declaration or contract: update chapter 23 and regenerate catalogs.
  • New page, selector, or plotting behavior: update chapters 31 through 33 and regenerate catalogs.
  • New export payload/runtime behavior: update chapter 34.
  • Architecture or runtime-flow changes: update chapters 12, 20, and 30 as applicable.

Tests

See Developer Workflows for the normal test loop and Testing for the fast/full split and offline-export boundary.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, '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('^' + ".*" + ' GitHub - OrMSC/activitysim_visualizer · GitHub
Skip to content

Repository files navigation

ActivitySim Visualizer

activitysim_visualizer is a Panel-based dashboard for exploring and comparing ActivitySim outputs. It can:

  • compare multiple model runs side by side
  • build and reuse prepared and summary caches
  • serve a live local dashboard
  • export a standalone HTML version for offline sharing

Quick Start

Install dependencies with uv:

uv sync --locked

Notebook tooling is optional; install it only when working with the repository's notebooks:

uv sync --locked --group notebooks

If uv sync fails because of a hardlink issue, retry with:

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

Create a project-specific config:

Copy-Item config.yaml local_config.yaml

Edit local_config.yaml, then run the app with that config:

uv run activitysim-viz --config local_config.yaml

By default, activitysim-viz follows pipeline.steps from the loaded config when no explicit step flags are supplied. The shipped example config defaults to summarize + dashboard, so a normal run will reuse summary caches when possible, rebuild them when needed, and then start the live dashboard on http://localhost:5006.

Dashboard Pages

Dashboard pages now use one shared authoring model:

  • page classes use @dashboard_page(...) and subclass DashboardPage
  • dropdowns use select(...); custom widgets use selector(...)
  • dynamic selectors declare an option provider and default policy
  • refreshable regions are registered with section(...)
  • large pages compose related selectors and sections with feature(...)
  • repeated chart transforms use query(...) without page-authored cache keys
  • live refresh and export metadata both derive from those registrations

The main shared page-helper modules live under dashboard/helpers/:

  • category_helpers.py
  • geography_helpers.py
  • person_type_helpers.py
  • time_distance_helpers.py
  • comparison_helpers.py

If you are adding or refactoring a page, start with the dashboard page recipes and figures/widgets guide. The dashboard extension cookbook covers the complete contributor path.

Config Setup

The repo ships with config.yaml as a template. In practice, most people should:

  1. Copy config.yaml to local_config.yaml or another machine-specific file.
  2. Update the runs section to point at real ActivitySim output folders.
  3. Update prepare.distance_skim, zones, and files if your model layout differs from the defaults.
  4. Run with --config your_file.yaml.

The canonical config layout is organized around a few top-level sections:

root: artifacts/log_level: INFOpipeline:
steps: [summarize, dashboard]dashboard_mode: liveoverwrite: falseprepare: ...summarize: ...segment: ...dashboard: ...display: ...skimjoin: ...extensions: ...

Removed keys such as processor.*, summaries.*, visualizer.*, top-level dashboard_labels, and top-level run_colors now fail validation and name the canonical replacement. Unknown keys also fail instead of being silently ignored.

The minimum useful config is usually:

root: artifacts/summary_cachepipeline:
steps:
- summarize
- dashboarddashboard_mode: liveruns:
- dir: path\to\run1label: Base
- dir: path\to\run2label: Buildskimjoin:
distance_skim:
file: path\to\skims.omxmatrix: SOV_DIST__MDzones:
use_maz: falsemaz_col: zone_idtaz_col: TAZfiles:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsjoint_tour_participants: final_joint_tour_participantsland_use: final_land_use

If runs use different raw filenames, keep files: as the default mapping and override only the differences inside runs[*].file_map:

files:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsruns:
- dir: path\to\run1label: Basefile_map:
households: final_hhtrips: trip_linked
- dir: path\to\run2label: Buildfile_map:
households: householdpersons: persontours: tourtrips: trip

If a run should skip raw prepare and use externally managed canonical prepared tables instead, point it at those files with runs[*].prepared_table_map:

runs:
- dir: path\to\raw_runlabel: Raw Run
- label: Custom Prepared Runprepared_table_map:
households: path\to\custom\households.parquetpersons: path\to\custom\persons.csvtours: path\to\custom\tours.parquettrips: path\to\custom\trips.csvjoint_tour_participants: path\to\custom\joint_tour_participants.parquetland_use: path\to\custom\land_use.csv

prepared_table_map is intended for canonical prepared tables that were already skimjoined and then optionally filtered or otherwise post-processed outside this repo. When a run uses prepared_table_map, the workflow loads those prepared tables directly and does not rerun raw prepare or integrated skimjoin for that run.

If a run already has dashboard-ready summary tables, point directly at those files with runs[*].summary_table_map:

runs:
- label: Summary Only Demosummary_table_map:
population_totals: path\to\summaries\population_totals.csvtraffic_count_comparisons: path\to\summaries\traffic_count_comparisons.parquet

summary_table_map uses registered summary IDs as keys, accepts explicit .csv or .parquet paths, and resolves relative paths from the config file directory. Mapped summaries are expected to already use the dashboard's canonical columns. During summarize they override the listed generated summaries; missing summaries can still be generated from raw/prepared inputs when those inputs exist. Some registered summary IDs are external/demo-only and are not generated by default for raw/prepared runs, which avoids writing __empty__ cache CSVs just to make those IDs available to summary_table_map.

Integrated skim enrichment can now be selected per run without forcing one shared skimjoin config for every skim structure. Keep the explicit skimjoin YAML logic in separate files, then choose the file and optional project-input overrides per run:

skimjoin:
defaults:
config_path: configs/skimjoin_default.yamlruns:
- dir: path\to\run_alabel: Run Askimjoin:
config_path: configs/skimjoin_odot_series15.yamlskim_files:
- path\to\run_a\skims\*.omx
- path\to\run_a\skims\maz_stop_walk.csvnetwork_los_file: path\to\run_a\network_los.yaml
- dir: path\to\run_blabel: Run Bskimjoin:
config_path: configs/skimjoin_combined_walk.yamlskim_files:
- path\to\run_b\skims\*.omx

Skimjoin override rules:

  • runs[*].skimjoin.config_path overrides global skimjoin.config_path.
  • runs[*].skimjoin.skim_files overrides the selected skimjoin config's project.skim_files.
  • runs[*].skimjoin.network_los_file overrides the selected skimjoin config's project.network_los_file.
  • skimjoin.failure_policy defaults to record; use error when skimjoin failures must stop a validation or batch run.
  • If a run omits runs[*].skimjoin, it uses the global skimjoin settings exactly as before.

Recommended rule of thumb:

  • If runs differ only by skim file locations, share one skimjoin config and override runs[*].skimjoin.skim_files.
  • If runs differ only by period definitions, share one skimjoin config and override runs[*].skimjoin.network_los_file.
  • If runs differ by lookup logic, fallback behavior, combined vs split components, or directional semantics, use different skimjoin config files.

VOT bin preparation stays in prepare.vot_bins and remains run-aware by run label.

Skimjoin dimensions are now standardized under dimensions, while activitysim only carries the structural trip/tour fields. The recommended integrated-runtime pattern is:

activitysim:
trip_mode_column: trip_modetrip_id_column: trip_idtour_mode_column: tour_modetour_id_column: tour_idoutbound_column: outbounddimensions:
PERIOD:
source_columns:
trip_source_column: depart_houroutbound_tour_source_column: start_hourinbound_tour_source_column: first_inbound_trip_departvalues_from_network_los: truevalues:
8: AM17: PMVOT:
source_columns:
trip_source_column: vot_binoutbound_tour_source_column: vot_bininbound_tour_source_column: vot_binvalues:
L: LM: MH: H

Period behavior is directional by design:

  • trips use dimensions.PERIOD.source_columns.trip_source_column
  • outbound tours use dimensions.PERIOD.source_columns.outbound_tour_source_column
  • inbound tours use dimensions.PERIOD.source_columns.inbound_tour_source_column

In the standard prepare workflow, first_inbound_trip_depart is derived from the first inbound trip on each tour before integrated skimjoin runs.

Prepared endpoint columns are also standardized before skimjoin runs:

  • prepared trips and tours always include OTAZ and DTAZ
  • when zones.use_maz: true, prepare also materializes o_maz and d_maz
  • inbound tour lookups reuse those same column names, while skimjoin swaps their logical direction in the inbound tour context

The normal prepare step can also write prepared caches as CSV when needed:

prepare:
output:
file_format: csvvalidation:
relationship_checks: warn

Important path rules:

  • root is resolved relative to the config file if you give a relative path.
  • The prepared cache is created automatically next to root as prepared_cache/.
  • runs[*].dir should point at an ActivitySim output directory.
  • prepare.distance_skim.file may be absolute, or relative to each run directory.
  • File entries under files can be bare stems like final_trips or explicit filenames like final_trips.csv.
  • runs[*].file_map uses the same filename rules as files, but applies only to that run.
  • runs[*].prepared_table_map must use explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • runs[*].summary_table_map must use registered summary IDs with explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • prepare.output.file_format controls how standard prepared caches are written; supported values are parquet and csv, with parquet as the default.
  • prepare.validation.relationship_checks controls prepared-table foreign-key validation. Use warn to log inconsistencies and continue, error to fail the run, or off to skip the checks.
  • dashboard.export.output_path, when relative, is resolved from root.

Config Reference

These are the sections most people need to touch:

SectionPurpose
rootWhere summary caches are stored
pipelineDefault workflow steps, dashboard mode, and overwrite behavior
runsRun directories, display labels, and optional per-run skim, raw file-map, custom prepared-table map, custom summary-table map, and weight overrides
prepare.distance_skimDefault distance skim file and matrix name used by summaries
zonesMAZ/TAZ settings for skim joins and zone normalization
filesDefault ActivitySim output file stems or filenames used unless a run overrides them
columnsColumn aliases when outputs use non-default names
prepare.output.file_formatOn-disk format for prepared caches written by the normal prepare workflow
prepare.validation.relationship_checksWhether cross-table prepared-key validation is disabled, warns, or errors
prepare.student_typesOptional school/university enrollment definitions for shadow pricing pages
dashboard.titleTitle used in the live dashboard and HTML export
dashboard.include_notesShow per-plot and per-table calculation notes in the live dashboard and HTML export (default: true)
dashboard.live.pagesOrdered list of live pages/groups to show
dashboard.exportExport-only output path, page selection, and selector-state controls
display.run_colorsPlot colors by run
display.labelsPresentation-only labels and ordering for dashboard/export
weighting.modesNamed weighting alternatives backed by household, person, and/or trip columns
extensionsAdvanced importable weighting calculations and their summary-affecting settings
summarize.weighting_modesOrdered built-in, declarative, or custom weighting-mode IDs to build
summarize.failure_policyrecord keeps failed summaries visible as diagnostics; error stops immediately on a builder exception
summarize.geographyOptional configured district/county/zone mappings
summarize.pnr_tour_modesWhich tour modes count as park-and-ride in summary builders
summarize.group_*_tour_purposesSummary-time purpose regrouping switches
summarize.category_normalizationSummary-affecting category normalization/regrouping
modesOptional mode ordering and grouped mode display
display.labels.person_typeOptional display labels for ptype values

Weighting rules:

  • If a run sets hh_weight_col, person_weight_col, or trip_weight_col, those are used.
  • Otherwise, if a sample_rate column is available, weights are derived from it.
  • Otherwise, weights default to 1.
  • weighting.modes can select additional prepared household, person, and trip columns as named alternatives without replacing the primary weighted mode.

Geography summary notes:

  • Summaries may emit all_geographies total rows independently of the geography config.
  • Native prepared geographies such as home_taz, home_county, and home_mpo may appear whenever those columns are available in prepared data, even when summarize.geography.enabled: false.
  • summarize.geography controls additional mapped geography aggregations, such as home_geo__school_district, work_geo__county, or land_use_geo__district.

Removed config notes:

  • Prefer the canonical top-level schema: root, pipeline, dashboard, display, summarize, segment, and skimjoin.
  • Older keys such as processor.root, summaries.weighting_modes, visualizer.dashboard_pages, top-level run_colors, top-level summary_categories, and top-level student_types are rejected with their canonical replacement.

Geography note:

  • summarize.geography.enabled: false disables mapped geography aggregation columns. Set it to true for aggregation-based geography summaries.

Category config note:

  • Use summarize.category_normalization when a mapping changes summary values, grouping membership, or canonical category values.
  • Use display.labels when a change is cosmetic and should only affect dashboard/export labels or ordering.

Live Pages And Export Pages

dashboard.live.pages controls the live dashboard only. dashboard.export controls what goes into the standalone HTML export.

Current top-level page ids are:

  • overview
  • long_term_choices
  • daily_travel
  • joint_travel
  • tour_summaries
  • trip_summaries
  • validation
  • raw_trip_demo

Grouped page ids support either the whole group or specific child pages. For example:

dashboard:
# Set to false to omit all per-plot and per-table calculation notes.include_notes: truelive:
pages:
- overview
- long_term_choices:
- individual_choices
- mandatory_location_choice
- shadow_pricing
- daily_travel: default
- tour_summaries: all
- trip_summaries:
- trip_mode
- trip_stop_time

Notes:

  • default means "the group's default enabled children".
  • all means every child page in the group.
  • A plain group id like tour_summaries behaves like the group's default selection.
  • raw_trip_demo is disabled by default and requests prepared trip tables, so keep it out unless you explicitly want that behavior.

For HTML export, start with the live page set and override selector states or parts as needed:

dashboard:
export:
dashboard:
weighting: [unweighted]values: [percent]exclude_groups: [validation]pages:
long_term_choices:
shadow_pricing:
geography_level: [all]student_type: [all]parts:
workplace_table:
enabled: falseschool_table:
enabled: false

Rules worth remembering:

  • If dashboard.live.pages is omitted, the app uses its built-in default page set.
  • Export always starts from the live page set. Entries under dashboard.export.pages modify matching pages; they are not an allow-list.
  • Export selector requests accept default, all, or a list of explicit values.
  • Set a page override's enabled to false, or use dashboard.export.exclude_pages / exclude_groups, to remove pages from export without changing the live dashboard.

Run Modes

The CLI exposes three workflow steps:

  1. prepare
  2. summarize
  3. dashboard

Common commands:

CommandWhat it does
python run.py --config local_config.yamlReuse or build summaries, then start the live dashboard
python run.py --config local_config.yaml --prepare-onlyBuild prepared caches and exit
python run.py --config local_config.yaml --summarizeReuse or build summary caches and exit
python run.py --config local_config.yaml --summarize --dashboardExplicit form of the default live workflow
python run.py --config local_config.yaml --dashboardStart the dashboard from existing summary caches for the configured runs
python run.py --config local_config.yaml --prepare --summarize --dashboardForce the full prepare -> summarize -> dashboard chain in one run
python run.py --config local_config.yaml --from-csvsStart the dashboard from existing summary caches only
python run.py --config local_config.yaml --from-csvs --export-html output.htmlBuild a standalone HTML export from existing summary caches
python run.py --config local_config.yaml --summarize --write-csvsRebuild summaries and write fresh cache files
python run.py --config local_config.yaml --summarize --skip-summary-cache-writeBuild summaries for this run without writing cache updates
python run.py --config local_config.yaml --summarize --refresh-summary-cacheDelete and rebuild summary caches for the selected runs
python run.py --config local_config.yaml --summarize --refresh-prepared-cacheRebuild summaries from freshly prepared tables instead of prepared-cache hits
python run.py --config local_config.yaml --prepare --summarize --refresh-cachesDelete and rebuild both prepared and summary caches for the selected runs

Behavior details:

  • --from-csvs is cache-only: it reads visualizer summary-cache directories with manifests, not loose summary CSVs.
  • --from-csvs path\to\cache1 path\to\cache2 lets you point directly at specific summary cache directories.
  • Use runs[*].summary_table_map when you have loose dashboard-ready summary files instead of visualizer cache directories.
  • --dashboard by itself is valid when summary caches already exist for the configured runs.
  • During summarize, the app will reuse prepared cache when possible and rebuild from raw outputs only when needed.
  • --refresh-prepared-cache deletes the selected runs' prepared-cache directories first, then disables prepared-cache reuse for that invocation.
  • --refresh-summary-cache deletes the selected runs' summary-cache directories first, then disables summary-cache reuse for that invocation.
  • --refresh-caches is shorthand for both refresh flags together.

Cache Layout

Prepared caches are written automatically next to the summary cache root:

<summary_root_parent>/
prepared_cache/
<run_key>/
manifest.json
households.parquet|csv
persons.parquet|csv
tours.parquet|csv
trips.parquet|csv
joint_tour_participants.parquet|csv
land_use.parquet|csv

Summary caches are written under root:

<summary_root>/
<run_key>/
manifest.json
weighted/
unweighted/

Both cache layers validate manifests before reuse. Cache invalidation is driven by:

  • the run inputs
  • the prepare and summary config digests
  • the prepared-manifest identity used to build summary caches
  • per-summary summary digests inside the summary-cache manifest

That means presentation-only config changes usually do not force summary rebuilds, and adding a newly requested summary can backfill just that table instead of rebuilding the entire summary bundle.

CLI Overrides

You can override runs on the command line instead of putting them in the config:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build"

Optional per-run skim overrides can be supplied in the same order:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build" ^
--run-skim C:\path\to\base_skims.omx C:\path\to\build_skims.omx

Use null, None, or an empty string in --run-skim to fall back to the configured prepare.distance_skim.file.

Codebase Map

activitysim_visualizer/
|-- run.py
|-- runtime/
| |-- workflows/
|-- runtime/
| `-- config/
|-- processor/
| |-- prepare/
| |-- summarize/
| `-- models.py
|-- dashboard/
| |-- app.py
| |-- export/
| |-- page_base.py
| |-- page_declarations.py
| |-- page_diagnostics.py
| |-- page_features.py
| |-- page_lifecycle.py
| |-- page_navigation.py
| |-- page_definitions.py
| |-- page_registry.py
| |-- state.py
| `-- pages/
`-- tests/

Documentation

The main user and contributor documentation lives in the wiki/ chapter set. Start with:

The wiki is the sole documentation source. Add or revise a wiki chapter instead of creating a parallel documentation tree.

Documentation Maintenance Checklist

When behavior changes, update docs in the same change:

  • New config key or config behavior: update chapters 11 and 13.
  • New summary declaration or contract: update chapter 23 and regenerate catalogs.
  • New page, selector, or plotting behavior: update chapters 31 through 33 and regenerate catalogs.
  • New export payload/runtime behavior: update chapter 34.
  • Architecture or runtime-flow changes: update chapters 12, 20, and 30 as applicable.

Tests

See Developer Workflows for the normal test loop and Testing for the fast/full split and offline-export boundary.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, '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 - OrMSC/activitysim_visualizer · GitHub
Skip to content

Repository files navigation

ActivitySim Visualizer

activitysim_visualizer is a Panel-based dashboard for exploring and comparing ActivitySim outputs. It can:

  • compare multiple model runs side by side
  • build and reuse prepared and summary caches
  • serve a live local dashboard
  • export a standalone HTML version for offline sharing

Quick Start

Install dependencies with uv:

uv sync --locked

Notebook tooling is optional; install it only when working with the repository's notebooks:

uv sync --locked --group notebooks

If uv sync fails because of a hardlink issue, retry with:

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

Create a project-specific config:

Copy-Item config.yaml local_config.yaml

Edit local_config.yaml, then run the app with that config:

uv run activitysim-viz --config local_config.yaml

By default, activitysim-viz follows pipeline.steps from the loaded config when no explicit step flags are supplied. The shipped example config defaults to summarize + dashboard, so a normal run will reuse summary caches when possible, rebuild them when needed, and then start the live dashboard on http://localhost:5006.

Dashboard Pages

Dashboard pages now use one shared authoring model:

  • page classes use @dashboard_page(...) and subclass DashboardPage
  • dropdowns use select(...); custom widgets use selector(...)
  • dynamic selectors declare an option provider and default policy
  • refreshable regions are registered with section(...)
  • large pages compose related selectors and sections with feature(...)
  • repeated chart transforms use query(...) without page-authored cache keys
  • live refresh and export metadata both derive from those registrations

The main shared page-helper modules live under dashboard/helpers/:

  • category_helpers.py
  • geography_helpers.py
  • person_type_helpers.py
  • time_distance_helpers.py
  • comparison_helpers.py

If you are adding or refactoring a page, start with the dashboard page recipes and figures/widgets guide. The dashboard extension cookbook covers the complete contributor path.

Config Setup

The repo ships with config.yaml as a template. In practice, most people should:

  1. Copy config.yaml to local_config.yaml or another machine-specific file.
  2. Update the runs section to point at real ActivitySim output folders.
  3. Update prepare.distance_skim, zones, and files if your model layout differs from the defaults.
  4. Run with --config your_file.yaml.

The canonical config layout is organized around a few top-level sections:

root: artifacts/log_level: INFOpipeline:
steps: [summarize, dashboard]dashboard_mode: liveoverwrite: falseprepare: ...summarize: ...segment: ...dashboard: ...display: ...skimjoin: ...extensions: ...

Removed keys such as processor.*, summaries.*, visualizer.*, top-level dashboard_labels, and top-level run_colors now fail validation and name the canonical replacement. Unknown keys also fail instead of being silently ignored.

The minimum useful config is usually:

root: artifacts/summary_cachepipeline:
steps:
- summarize
- dashboarddashboard_mode: liveruns:
- dir: path\to\run1label: Base
- dir: path\to\run2label: Buildskimjoin:
distance_skim:
file: path\to\skims.omxmatrix: SOV_DIST__MDzones:
use_maz: falsemaz_col: zone_idtaz_col: TAZfiles:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsjoint_tour_participants: final_joint_tour_participantsland_use: final_land_use

If runs use different raw filenames, keep files: as the default mapping and override only the differences inside runs[*].file_map:

files:
households: final_householdspersons: final_personstours: final_tourstrips: final_tripsruns:
- dir: path\to\run1label: Basefile_map:
households: final_hhtrips: trip_linked
- dir: path\to\run2label: Buildfile_map:
households: householdpersons: persontours: tourtrips: trip

If a run should skip raw prepare and use externally managed canonical prepared tables instead, point it at those files with runs[*].prepared_table_map:

runs:
- dir: path\to\raw_runlabel: Raw Run
- label: Custom Prepared Runprepared_table_map:
households: path\to\custom\households.parquetpersons: path\to\custom\persons.csvtours: path\to\custom\tours.parquettrips: path\to\custom\trips.csvjoint_tour_participants: path\to\custom\joint_tour_participants.parquetland_use: path\to\custom\land_use.csv

prepared_table_map is intended for canonical prepared tables that were already skimjoined and then optionally filtered or otherwise post-processed outside this repo. When a run uses prepared_table_map, the workflow loads those prepared tables directly and does not rerun raw prepare or integrated skimjoin for that run.

If a run already has dashboard-ready summary tables, point directly at those files with runs[*].summary_table_map:

runs:
- label: Summary Only Demosummary_table_map:
population_totals: path\to\summaries\population_totals.csvtraffic_count_comparisons: path\to\summaries\traffic_count_comparisons.parquet

summary_table_map uses registered summary IDs as keys, accepts explicit .csv or .parquet paths, and resolves relative paths from the config file directory. Mapped summaries are expected to already use the dashboard's canonical columns. During summarize they override the listed generated summaries; missing summaries can still be generated from raw/prepared inputs when those inputs exist. Some registered summary IDs are external/demo-only and are not generated by default for raw/prepared runs, which avoids writing __empty__ cache CSVs just to make those IDs available to summary_table_map.

Integrated skim enrichment can now be selected per run without forcing one shared skimjoin config for every skim structure. Keep the explicit skimjoin YAML logic in separate files, then choose the file and optional project-input overrides per run:

skimjoin:
defaults:
config_path: configs/skimjoin_default.yamlruns:
- dir: path\to\run_alabel: Run Askimjoin:
config_path: configs/skimjoin_odot_series15.yamlskim_files:
- path\to\run_a\skims\*.omx
- path\to\run_a\skims\maz_stop_walk.csvnetwork_los_file: path\to\run_a\network_los.yaml
- dir: path\to\run_blabel: Run Bskimjoin:
config_path: configs/skimjoin_combined_walk.yamlskim_files:
- path\to\run_b\skims\*.omx

Skimjoin override rules:

  • runs[*].skimjoin.config_path overrides global skimjoin.config_path.
  • runs[*].skimjoin.skim_files overrides the selected skimjoin config's project.skim_files.
  • runs[*].skimjoin.network_los_file overrides the selected skimjoin config's project.network_los_file.
  • skimjoin.failure_policy defaults to record; use error when skimjoin failures must stop a validation or batch run.
  • If a run omits runs[*].skimjoin, it uses the global skimjoin settings exactly as before.

Recommended rule of thumb:

  • If runs differ only by skim file locations, share one skimjoin config and override runs[*].skimjoin.skim_files.
  • If runs differ only by period definitions, share one skimjoin config and override runs[*].skimjoin.network_los_file.
  • If runs differ by lookup logic, fallback behavior, combined vs split components, or directional semantics, use different skimjoin config files.

VOT bin preparation stays in prepare.vot_bins and remains run-aware by run label.

Skimjoin dimensions are now standardized under dimensions, while activitysim only carries the structural trip/tour fields. The recommended integrated-runtime pattern is:

activitysim:
trip_mode_column: trip_modetrip_id_column: trip_idtour_mode_column: tour_modetour_id_column: tour_idoutbound_column: outbounddimensions:
PERIOD:
source_columns:
trip_source_column: depart_houroutbound_tour_source_column: start_hourinbound_tour_source_column: first_inbound_trip_departvalues_from_network_los: truevalues:
8: AM17: PMVOT:
source_columns:
trip_source_column: vot_binoutbound_tour_source_column: vot_bininbound_tour_source_column: vot_binvalues:
L: LM: MH: H

Period behavior is directional by design:

  • trips use dimensions.PERIOD.source_columns.trip_source_column
  • outbound tours use dimensions.PERIOD.source_columns.outbound_tour_source_column
  • inbound tours use dimensions.PERIOD.source_columns.inbound_tour_source_column

In the standard prepare workflow, first_inbound_trip_depart is derived from the first inbound trip on each tour before integrated skimjoin runs.

Prepared endpoint columns are also standardized before skimjoin runs:

  • prepared trips and tours always include OTAZ and DTAZ
  • when zones.use_maz: true, prepare also materializes o_maz and d_maz
  • inbound tour lookups reuse those same column names, while skimjoin swaps their logical direction in the inbound tour context

The normal prepare step can also write prepared caches as CSV when needed:

prepare:
output:
file_format: csvvalidation:
relationship_checks: warn

Important path rules:

  • root is resolved relative to the config file if you give a relative path.
  • The prepared cache is created automatically next to root as prepared_cache/.
  • runs[*].dir should point at an ActivitySim output directory.
  • prepare.distance_skim.file may be absolute, or relative to each run directory.
  • File entries under files can be bare stems like final_trips or explicit filenames like final_trips.csv.
  • runs[*].file_map uses the same filename rules as files, but applies only to that run.
  • runs[*].prepared_table_map must use explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • runs[*].summary_table_map must use registered summary IDs with explicit .parquet or .csv paths and resolves relative paths from the config file directory.
  • prepare.output.file_format controls how standard prepared caches are written; supported values are parquet and csv, with parquet as the default.
  • prepare.validation.relationship_checks controls prepared-table foreign-key validation. Use warn to log inconsistencies and continue, error to fail the run, or off to skip the checks.
  • dashboard.export.output_path, when relative, is resolved from root.

Config Reference

These are the sections most people need to touch:

SectionPurpose
rootWhere summary caches are stored
pipelineDefault workflow steps, dashboard mode, and overwrite behavior
runsRun directories, display labels, and optional per-run skim, raw file-map, custom prepared-table map, custom summary-table map, and weight overrides
prepare.distance_skimDefault distance skim file and matrix name used by summaries
zonesMAZ/TAZ settings for skim joins and zone normalization
filesDefault ActivitySim output file stems or filenames used unless a run overrides them
columnsColumn aliases when outputs use non-default names
prepare.output.file_formatOn-disk format for prepared caches written by the normal prepare workflow
prepare.validation.relationship_checksWhether cross-table prepared-key validation is disabled, warns, or errors
prepare.student_typesOptional school/university enrollment definitions for shadow pricing pages
dashboard.titleTitle used in the live dashboard and HTML export
dashboard.include_notesShow per-plot and per-table calculation notes in the live dashboard and HTML export (default: true)
dashboard.live.pagesOrdered list of live pages/groups to show
dashboard.exportExport-only output path, page selection, and selector-state controls
display.run_colorsPlot colors by run
display.labelsPresentation-only labels and ordering for dashboard/export
weighting.modesNamed weighting alternatives backed by household, person, and/or trip columns
extensionsAdvanced importable weighting calculations and their summary-affecting settings
summarize.weighting_modesOrdered built-in, declarative, or custom weighting-mode IDs to build
summarize.failure_policyrecord keeps failed summaries visible as diagnostics; error stops immediately on a builder exception
summarize.geographyOptional configured district/county/zone mappings
summarize.pnr_tour_modesWhich tour modes count as park-and-ride in summary builders
summarize.group_*_tour_purposesSummary-time purpose regrouping switches
summarize.category_normalizationSummary-affecting category normalization/regrouping
modesOptional mode ordering and grouped mode display
display.labels.person_typeOptional display labels for ptype values

Weighting rules:

  • If a run sets hh_weight_col, person_weight_col, or trip_weight_col, those are used.
  • Otherwise, if a sample_rate column is available, weights are derived from it.
  • Otherwise, weights default to 1.
  • weighting.modes can select additional prepared household, person, and trip columns as named alternatives without replacing the primary weighted mode.

Geography summary notes:

  • Summaries may emit all_geographies total rows independently of the geography config.
  • Native prepared geographies such as home_taz, home_county, and home_mpo may appear whenever those columns are available in prepared data, even when summarize.geography.enabled: false.
  • summarize.geography controls additional mapped geography aggregations, such as home_geo__school_district, work_geo__county, or land_use_geo__district.

Removed config notes:

  • Prefer the canonical top-level schema: root, pipeline, dashboard, display, summarize, segment, and skimjoin.
  • Older keys such as processor.root, summaries.weighting_modes, visualizer.dashboard_pages, top-level run_colors, top-level summary_categories, and top-level student_types are rejected with their canonical replacement.

Geography note:

  • summarize.geography.enabled: false disables mapped geography aggregation columns. Set it to true for aggregation-based geography summaries.

Category config note:

  • Use summarize.category_normalization when a mapping changes summary values, grouping membership, or canonical category values.
  • Use display.labels when a change is cosmetic and should only affect dashboard/export labels or ordering.

Live Pages And Export Pages

dashboard.live.pages controls the live dashboard only. dashboard.export controls what goes into the standalone HTML export.

Current top-level page ids are:

  • overview
  • long_term_choices
  • daily_travel
  • joint_travel
  • tour_summaries
  • trip_summaries
  • validation
  • raw_trip_demo

Grouped page ids support either the whole group or specific child pages. For example:

dashboard:
# Set to false to omit all per-plot and per-table calculation notes.include_notes: truelive:
pages:
- overview
- long_term_choices:
- individual_choices
- mandatory_location_choice
- shadow_pricing
- daily_travel: default
- tour_summaries: all
- trip_summaries:
- trip_mode
- trip_stop_time

Notes:

  • default means "the group's default enabled children".
  • all means every child page in the group.
  • A plain group id like tour_summaries behaves like the group's default selection.
  • raw_trip_demo is disabled by default and requests prepared trip tables, so keep it out unless you explicitly want that behavior.

For HTML export, start with the live page set and override selector states or parts as needed:

dashboard:
export:
dashboard:
weighting: [unweighted]values: [percent]exclude_groups: [validation]pages:
long_term_choices:
shadow_pricing:
geography_level: [all]student_type: [all]parts:
workplace_table:
enabled: falseschool_table:
enabled: false

Rules worth remembering:

  • If dashboard.live.pages is omitted, the app uses its built-in default page set.
  • Export always starts from the live page set. Entries under dashboard.export.pages modify matching pages; they are not an allow-list.
  • Export selector requests accept default, all, or a list of explicit values.
  • Set a page override's enabled to false, or use dashboard.export.exclude_pages / exclude_groups, to remove pages from export without changing the live dashboard.

Run Modes

The CLI exposes three workflow steps:

  1. prepare
  2. summarize
  3. dashboard

Common commands:

CommandWhat it does
python run.py --config local_config.yamlReuse or build summaries, then start the live dashboard
python run.py --config local_config.yaml --prepare-onlyBuild prepared caches and exit
python run.py --config local_config.yaml --summarizeReuse or build summary caches and exit
python run.py --config local_config.yaml --summarize --dashboardExplicit form of the default live workflow
python run.py --config local_config.yaml --dashboardStart the dashboard from existing summary caches for the configured runs
python run.py --config local_config.yaml --prepare --summarize --dashboardForce the full prepare -> summarize -> dashboard chain in one run
python run.py --config local_config.yaml --from-csvsStart the dashboard from existing summary caches only
python run.py --config local_config.yaml --from-csvs --export-html output.htmlBuild a standalone HTML export from existing summary caches
python run.py --config local_config.yaml --summarize --write-csvsRebuild summaries and write fresh cache files
python run.py --config local_config.yaml --summarize --skip-summary-cache-writeBuild summaries for this run without writing cache updates
python run.py --config local_config.yaml --summarize --refresh-summary-cacheDelete and rebuild summary caches for the selected runs
python run.py --config local_config.yaml --summarize --refresh-prepared-cacheRebuild summaries from freshly prepared tables instead of prepared-cache hits
python run.py --config local_config.yaml --prepare --summarize --refresh-cachesDelete and rebuild both prepared and summary caches for the selected runs

Behavior details:

  • --from-csvs is cache-only: it reads visualizer summary-cache directories with manifests, not loose summary CSVs.
  • --from-csvs path\to\cache1 path\to\cache2 lets you point directly at specific summary cache directories.
  • Use runs[*].summary_table_map when you have loose dashboard-ready summary files instead of visualizer cache directories.
  • --dashboard by itself is valid when summary caches already exist for the configured runs.
  • During summarize, the app will reuse prepared cache when possible and rebuild from raw outputs only when needed.
  • --refresh-prepared-cache deletes the selected runs' prepared-cache directories first, then disables prepared-cache reuse for that invocation.
  • --refresh-summary-cache deletes the selected runs' summary-cache directories first, then disables summary-cache reuse for that invocation.
  • --refresh-caches is shorthand for both refresh flags together.

Cache Layout

Prepared caches are written automatically next to the summary cache root:

<summary_root_parent>/
prepared_cache/
<run_key>/
manifest.json
households.parquet|csv
persons.parquet|csv
tours.parquet|csv
trips.parquet|csv
joint_tour_participants.parquet|csv
land_use.parquet|csv

Summary caches are written under root:

<summary_root>/
<run_key>/
manifest.json
weighted/
unweighted/

Both cache layers validate manifests before reuse. Cache invalidation is driven by:

  • the run inputs
  • the prepare and summary config digests
  • the prepared-manifest identity used to build summary caches
  • per-summary summary digests inside the summary-cache manifest

That means presentation-only config changes usually do not force summary rebuilds, and adding a newly requested summary can backfill just that table instead of rebuilding the entire summary bundle.

CLI Overrides

You can override runs on the command line instead of putting them in the config:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build"

Optional per-run skim overrides can be supplied in the same order:

python run.py --config local_config.yaml ^
--run C:\path\to\run1 "Base" ^
--run C:\path\to\run2 "Build" ^
--run-skim C:\path\to\base_skims.omx C:\path\to\build_skims.omx

Use null, None, or an empty string in --run-skim to fall back to the configured prepare.distance_skim.file.

Codebase Map

activitysim_visualizer/
|-- run.py
|-- runtime/
| |-- workflows/
|-- runtime/
| `-- config/
|-- processor/
| |-- prepare/
| |-- summarize/
| `-- models.py
|-- dashboard/
| |-- app.py
| |-- export/
| |-- page_base.py
| |-- page_declarations.py
| |-- page_diagnostics.py
| |-- page_features.py
| |-- page_lifecycle.py
| |-- page_navigation.py
| |-- page_definitions.py
| |-- page_registry.py
| |-- state.py
| `-- pages/
`-- tests/

Documentation

The main user and contributor documentation lives in the wiki/ chapter set. Start with:

The wiki is the sole documentation source. Add or revise a wiki chapter instead of creating a parallel documentation tree.

Documentation Maintenance Checklist

When behavior changes, update docs in the same change:

  • New config key or config behavior: update chapters 11 and 13.
  • New summary declaration or contract: update chapter 23 and regenerate catalogs.
  • New page, selector, or plotting behavior: update chapters 31 through 33 and regenerate catalogs.
  • New export payload/runtime behavior: update chapter 34.
  • Architecture or runtime-flow changes: update chapters 12, 20, and 30 as applicable.

Tests

See Developer Workflows for the normal test loop and Testing for the fast/full split and offline-export boundary.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages