Skip to content

Commit

Permalink
reporting as steps
Browse files Browse the repository at this point in the history
  • Loading branch information
jpn-- committed Apr 1, 2022
1 parent 1185449 commit ea54b52
Show file tree
Hide file tree
Showing 12 changed files with 426 additions and 18 deletions.
3 changes: 3 additions & 0 deletions activitysim/standalone/skims.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import yaml
import glob
import os
import logging

logger = logging.getLogger(__name__)

def load_skims(
network_los_settings_filename,
Expand Down
22 changes: 22 additions & 0 deletions activitysim/standalone/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import os
from contextlib import contextmanager
from pathlib import Path

@contextmanager
def chdir(path: Path):
"""
Sets the cwd within the context
Args:
path (Path): The path to the cwd
Yields:
None
"""

cwd = Path().absolute()
try:
os.chdir(path)
yield
finally:
os.chdir(cwd)
88 changes: 72 additions & 16 deletions activitysim/workflows/example_runner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ steps:
fast: False
compile_n_households: 1000
main_n_households: 100000
config_dirs: configs
data_dir: data

- name: activitysim.workflows.steps.title
in:
Expand Down Expand Up @@ -64,13 +66,13 @@ steps:
cache_dir: cache

- description: Run activitysim to compile and test sharrow-enabled model
name: activitysim.workflows.steps.cmd
name: activitysim.workflows.steps.run
run: '{compile}'
in:
cmd:
run: "python -m activitysim run -c configs_sh_compile -o output-{tag}/output-compile {flags}"
cwd: "{workspace}/{example_name}"
label: "{example_name} -- sharrow compile"
pre_config_dirs: configs_sh_compile
output_dir: 'output-{tag}/output-compile'
cwd: "{workspace}/{example_name}"
label: "{example_name} -- sharrow compile"

- description: write configs_sh
name: pypyr.steps.filewriteyaml
Expand All @@ -85,13 +87,13 @@ steps:
households_sample_size: '{main_n_households}'

- description: Run activitysim to evaluate sharrow-enabled model
name: activitysim.workflows.steps.cmd
name: activitysim.workflows.steps.run
run: '{sharrow}'
in:
cmd:
run: "python -m activitysim run -c configs_sh -o output-{tag}/output-sharrow {flags}"
cwd: "{workspace}/{example_name}"
label: "{example_name} -- sharrow run"
pre_config_dirs: configs_sh
output_dir: 'output-{tag}/output-sharrow'
cwd: "{workspace}/{example_name}"
label: "{example_name} -- sharrow run"

- description: write.configs_sh
name: pypyr.steps.filewriteyaml
Expand All @@ -107,14 +109,68 @@ steps:
households_sample_size: '{main_n_households}'

- description: Run activitysim to evaluate legacy model
name: activitysim.workflows.steps.cmd
name: activitysim.workflows.steps.run
run: '{legacy}'
in:
cmd:
run: "python -m activitysim run -c configs_legacy -o output-{tag}/output-legacy {flags}"
cwd: "{workspace}/{example_name}"
label: "{example_name} -- legacy run"
pre_config_dirs: configs_legacy
output_dir: 'output-{tag}/output-output-legacy'
cwd: "{workspace}/{example_name}"
label: "{example_name} -- legacy run"

- activitysim.workflows.steps.composite_log
- activitysim.workflows.steps.contrast_report
#- activitysim.workflows.steps.contrast_report

- name: pypyr.steps.call
in:
call:
groups: reporting
success: report-save
failure: report-save


reporting:

- name: activitysim.workflows.steps.contrast.load_tables
in:
common_output_directory: "{workspace}/{example_name}/output-{tag}"
databases:
sharrow: "output-sharrow"
legacy: "output-legacy"
tables:
trips:
filename: final_trips.csv
index_col: trip_id
persons:
filename: final_persons.csv
index_col: person_id
land_use:
filename: final_land_use.csv
index_col: zone_id

- name: activitysim.workflows.steps.contrast.load_skims
in:
common_directory: "{workspace}/{example_name}"

- name: activitysim.workflows.steps.contrast.init_report
in:
title: "{example_name} report"
common_directory: "{workspace}/{example_name}"

- name: activitysim.workflows.steps.contrast.runtime
in:
common_output_directory: "{workspace}/{example_name}/output-{tag}"

- name: activitysim.workflows.steps.contrast.trip_mode_choice
in:
title: Trip Mode Choice by Primary Purpose
grouping: primary_purpose

- name: activitysim.workflows.steps.contrast.trip_mode_choice
in:
title: Trip Mode Choice by Departure Time
grouping: depart

report-save:
- name: activitysim.workflows.steps.contrast.save_report
in:
html_filename: "{workspace}/{example_name}/output-{tag}/report-{tag}.html"
Empty file.
8 changes: 8 additions & 0 deletions activitysim/workflows/steps/contrast/init_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from pypyr.context import Context
from xmle import Reporter, NumberedCaption


def run_step(context: Context) -> None:
title = context.get_formatted('title')
context['report'] = Reporter(title=title)
context['fig'] = NumberedCaption("Figure", level=2, anchor=True)
36 changes: 36 additions & 0 deletions activitysim/workflows/steps/contrast/load_skims.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import os
from pypyr.context import Context
from ..progression import reset_progress_step
from ..error_handler import error_logging
from pathlib import Path
from activitysim.standalone.skims import load_skims
from activitysim.standalone.utils import chdir
import logging

logger = logging.getLogger(__name__)

@error_logging
def run_step(context: Context) -> None:
context.assert_key_has_value(key='common_directory', caller=__name__)
common_directory = context.get_formatted('common_directory')
config_dirs = context.get_formatted('config_dirs')
if isinstance(config_dirs, str):
config_dirs = [config_dirs]
data_dir = context.get_formatted('data_dir')
with chdir(common_directory):
network_los_file = None
for config_dir in config_dirs:
network_los_file = os.path.join(config_dir, 'network_los.yaml')
if os.path.exists(network_los_file):
break
if network_los_file is None:
raise FileNotFoundError("<<config_dir>>/network_los.yaml")
if isinstance(data_dir, (str, Path)) and isinstance(network_los_file, (str, Path)):
skims = load_skims(network_los_file, data_dir)
else:
skims = {}
for k in data_dir.keys():
skims[k] = load_skims(network_los_file, data_dir[k])
# TODO: allow for different network_los_file

context['skims'] = skims
51 changes: 51 additions & 0 deletions activitysim/workflows/steps/contrast/load_tables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import os
from pypyr.context import Context
from ..progression import reset_progress_step
from ..error_handler import error_logging
from pathlib import Path
from activitysim.standalone.compare import load_final_tables
from activitysim.standalone.utils import chdir

@error_logging
def run_step(context: Context) -> None:

context.assert_key_has_value(key='common_output_directory', caller=__name__)
common_output_directory = context.get_formatted('common_output_directory')

databases = context.get_formatted('databases')
# the various different output directories to process, for example:
# {
# "sharrow": "output-sharrow",
# "legacy": "output-legacy",
# }

tables = context.get_formatted('tables')
# the various tables in the output directories to read, for example:
# trips:
# filename: final_trips.csv
# index_col: trip_id
# persons:
# filename: final_persons.csv
# index_col: person_id
# land_use:
# filename: final_land_use.csv
# index_col: zone_id

tablefiles = {}
index_cols = {}
for t, v in tables.items():
if isinstance(v, str):
tablefiles[t] = v
else:
tablefiles[t] = v.get("filename")
index_cols[t] = v.get("index_col", None)

with chdir(common_output_directory):
contrast_data = load_final_tables(
databases,
tablefiles,
index_cols,
)

context['contrast_data'] = contrast_data

58 changes: 58 additions & 0 deletions activitysim/workflows/steps/contrast/runtime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import logging
import pandas as pd
import altair as alt
from pypyr.context import Context
from ....standalone.utils import chdir

logger = logging.getLogger(__name__)

def run_step(context: Context) -> None:

context.assert_key_has_value(key='common_output_directory', caller=__name__)
common_output_directory = context.get_formatted('common_output_directory')

context.assert_key_has_value(key='report', caller=__name__)
report = context.get('report')
fig = context.get('fig')
tag = context.get('tag')
timing_log = f"combined_timing_log-{tag}.csv"

with report:
with chdir(common_output_directory):

report << fig("Model Runtime")

logger.info(f"building runtime report from {common_output_directory}/{timing_log}")

df = pd.read_csv(timing_log, index_col='model_name')
df1 = df[['sharrow', 'legacy']].rename_axis(columns="source").unstack().rename('seconds').reset_index()
c = alt.Chart(df1, height={"step": 20}, )

result = c.mark_bar(
yOffset=-3,
size=6,
).transform_filter(
(alt.datum.source == 'legacy')
).encode(
x=alt.X('seconds:Q', stack=None),
y=alt.Y('model_name', type='nominal', sort=None),
color="source",
tooltip=['source', 'model_name', 'seconds']
) + c.mark_bar(
yOffset=4,
size=6,
).transform_filter(
(alt.datum.source == 'sharrow')
).encode(
x=alt.X('seconds:Q', stack=None),
y=alt.Y('model_name', type='nominal', sort=None),
color="source",
tooltip=['source', 'model_name', 'seconds']
) | alt.Chart(df1).mark_bar().encode(
color='source',
x='source',
y='sum(seconds)',
tooltip=['source', 'sum(seconds)']
)

report << result
68 changes: 68 additions & 0 deletions activitysim/workflows/steps/contrast/save_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import logging
import os
from pypyr.context import Context
from .... import __version__

def run_step(context: Context) -> None:

context.assert_key_has_value(key='report', caller=__name__)
report = context.get('report')
html_filename = context.get_formatted('html_filename')
if 'toc_color' in context:
toc_color = context.get_formatted('toc_color')
else:
toc_color = 'forest'

bootstrap_font_family = (
'font-family: -apple-system, "system-ui", "Segoe UI",'
' "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji",'
' "Segoe UI Emoji", "Segoe UI Symbol";'
)
toc_width = 200
signature_font = 'font-size:70%; font-weight:200;'
signature_name_font = 'font-weight:400; font-style:normal;'

css = """
html { """ + bootstrap_font_family + """ }
div.xmle_title { font-weight:700; font-size: 2em; color: rgb(35, 144, 98);}
body { margin-left: """ + str(toc_width) + """px; }
div.xmle_html_report { padding-left: 5px; }
.table_of_contents_frame { width: """ + str(
toc_width - 13) + """px; position: fixed; margin-left: -""" + str(toc_width) + """px; top:0; padding-top:10px; z-index:2000;}
.table_of_contents { width: """ + str(toc_width - 13) + """px; position: fixed; margin-left: -""" + str(
toc_width) + """px; font-size:85%;}
.table_of_contents_head { font-weight:700; padding-left:25px; }
.table_of_contents ul { padding-left:25px; }
.table_of_contents ul ul { font-size:75%; padding-left:15px; }
.xmle_signature {""" + signature_font + """ width: """ + str(toc_width - 30) + """px; position: fixed; left: 0px; bottom: 0px; padding-left:20px; padding-bottom:2px; background-color:rgba(255,255,255,0.9);}
.xmle_name_signature {""" + signature_name_font + """}
a.parameter_reference {font-style: italic; text-decoration: none}
.strut2 {min-width:2in}
.histogram_cell { padding-top:1; padding-bottom:1; vertical-align:center; }
table.floatinghead thead {background-color:#FFF;}
table.dataframe thead {background-color:#FFF;}
@media print {
body { color: #000; background: #fff; width: 100%; margin: 0; padding: 0;}
/*.table_of_contents { display: none; }*/
@page {
margin: 1in;
}
h1, h2, h3 { page-break-after: avoid; }
img { max-width: 100% !important; }
ul, img, table { page-break-inside: avoid; }
.xmle_signature {""" + signature_font + """ padding:0; background-color:#fff; position: fixed; bottom: 0;}
.xmle_name_signature {""" + signature_name_font + """}
.xmle_signature img {display:none;}
.xmle_signature .noprint {display:none;}
}
"""

logging.critical(f"SAVING REPORT TO {(html_filename)}")
report.save(
html_filename,
overwrite=True,
css=css,
toc_font=bootstrap_font_family,
toc_color=toc_color,
branding=f"ActivitySim {__version__}",
)

0 comments on commit ea54b52

Please sign in to comment.