├── .nojekyll ├── syspy ├── __init__.py ├── io │ ├── __init__.py │ ├── pandasdbf │ │ ├── __init__.py │ │ ├── exceltodbf_qc.py │ │ └── pandasdbf.py │ ├── pandasshp │ │ ├── __init__.py │ │ ├── Thumbs.db │ │ └── gis_resources │ │ │ └── projections │ │ │ ├── epsg4326.prj │ │ │ ├── epsg32614.prj │ │ │ └── epsg2154.prj │ └── geojson_utils.py ├── operations │ ├── __init__.py │ └── rollingstock_model.py ├── pycube │ ├── __init__.py │ ├── project.py │ ├── network.py │ ├── dijkstra.py │ └── application.py ├── surveys │ ├── __init__.py │ ├── array_example.py │ └── discrete_choice.py ├── syspy_utils │ ├── __init__.py │ ├── test.py │ ├── gis_resources │ │ └── projections │ │ │ ├── epsg4326.prj │ │ │ ├── epsg32614.prj │ │ │ └── epsg2154.prj │ ├── assignment.py │ ├── daycount.py │ ├── documentation_jupyter.py │ ├── pandas_utils.py │ ├── mca_utils.py │ └── gtfs_utils.py ├── clients │ ├── linedraft_client │ │ └── __init__.py │ └── __init__.py ├── distribution │ ├── description.txt │ └── __init__.py ├── routing │ ├── __init__.py │ ├── frequency │ │ └── __init__.py │ ├── timetable │ │ ├── __init__.py │ │ └── csa.py │ └── networkx_wrapper.py ├── skims │ └── __init__.py ├── spatial │ ├── __init__.py │ ├── graph │ │ └── __init__.py │ ├── utils.py │ └── geometry_smoothing.py ├── assignment │ └── __init__.py ├── transitfeed │ ├── __init__.py │ └── feed_links.py ├── .vscode │ └── .ropeproject │ │ └── objectdb ├── paths.py ├── logit │ ├── multinomial_logit.py │ └── nested_logit.py ├── renumber │ └── renumber.py └── graph │ └── nearest_path.py ├── quetzal ├── io │ ├── __init__.py │ ├── gtfs_reader │ │ ├── __init__.py │ │ └── patterns.py │ ├── md.py │ ├── cube │ │ └── cube.py │ ├── EMMEporter.py │ └── hdf_io.py ├── analysis │ ├── __init__.py │ ├── on_demand.py │ └── cost_benefit_analysis.py ├── engine │ ├── __init__.py │ ├── combinatorial_pathfinder.py │ ├── subprocesses │ │ ├── filepaths.py │ │ └── subprocess_path_and_duration_from_graph_json.py │ ├── msa_trackers │ │ ├── tracker.py │ │ └── test_tracker.py │ ├── parallelization.py │ ├── screenlines.py │ ├── park_and_ride_pathfinder.py │ ├── optimal_strategy.py │ ├── vdf.py │ ├── elevation.py │ └── graph_utils.py ├── launcher │ ├── __init__.py │ └── launcher_utils.py ├── model │ ├── __init__.py │ └── docmodel.py ├── .python-version ├── __init__.py ├── index.txt └── description.txt ├── tests ├── .gitignore ├── readme.txt ├── __init__.py ├── data │ └── jsons │ │ ├── jsons.json │ │ ├── nodes.geojson │ │ ├── centroids.geojson │ │ ├── checkpoint_nodes.geojson │ │ └── loaded_nodes.geojson └── old_test_engine_od_volume_from_zones.py ├── _config.yml ├── docs ├── quetzal_icon.ico ├── build │ ├── objects.inv │ ├── _static │ │ ├── file.png │ │ ├── minus.png │ │ ├── plus.png │ │ └── css │ │ │ └── badge_only.css │ ├── .doctrees │ │ ├── index.doctree │ │ ├── LICENSE.doctree │ │ ├── quetzal.doctree │ │ ├── environment.pickle │ │ ├── quetzal.io.doctree │ │ ├── quetzal.engine.doctree │ │ ├── quetzal.model.doctree │ │ ├── quetzal.analysis.doctree │ │ ├── quetzal.io.export.doctree │ │ ├── quetzal.io.display.doctree │ │ ├── quetzal.io.importer.doctree │ │ ├── quetzal.model.model.doctree │ │ ├── quetzal.engine.engine.doctree │ │ ├── quetzal.model.docmodel.doctree │ │ ├── quetzal.analysis.analysis.doctree │ │ ├── quetzal.engine.pathfinder.doctree │ │ ├── quetzal.io.export_utils.doctree │ │ ├── quetzal.io.gtfs_importer.doctree │ │ ├── quetzal.model.cubemodel.doctree │ │ ├── quetzal.model.stepmodel.doctree │ │ ├── quetzal.analysis.on_demand.doctree │ │ ├── quetzal.engine.add_network.doctree │ │ ├── quetzal.engine.connectivity.doctree │ │ ├── quetzal.engine.screenlines.doctree │ │ ├── quetzal.model.analysismodel.doctree │ │ ├── quetzal.model.integritymodel.doctree │ │ ├── quetzal.model.preparationmodel.doctree │ │ ├── quetzal.model.transportmodel.doctree │ │ ├── quetzal.engine.linearsolver_utils.doctree │ │ └── quetzal.analysis.cost_benefit_analysis.doctree │ └── .buildinfo ├── source │ ├── _images │ │ ├── Thumbs.db │ │ ├── paris.png │ │ ├── paris.pgw │ │ └── favicon_package_v0.16 │ │ │ ├── favicon.ico │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── mstile-150x150.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── browserconfig.xml │ │ │ └── site.webmanifest │ ├── nstatic │ │ ├── Thumbs.db │ │ └── gtfs_mexico.png │ ├── _build │ │ ├── html │ │ │ ├── objects.inv │ │ │ ├── _static │ │ │ │ ├── up.png │ │ │ │ ├── Thumbs.db │ │ │ │ ├── down.png │ │ │ │ ├── file.png │ │ │ │ ├── minus.png │ │ │ │ ├── plus.png │ │ │ │ ├── comment.png │ │ │ │ ├── up-pressed.png │ │ │ │ ├── ajax-loader.gif │ │ │ │ ├── comment-close.png │ │ │ │ ├── down-pressed.png │ │ │ │ ├── comment-bright.png │ │ │ │ ├── fonts │ │ │ │ │ ├── Lato-Bold.ttf │ │ │ │ │ ├── Lato-Regular.ttf │ │ │ │ │ ├── Inconsolata-Bold.ttf │ │ │ │ │ ├── RobotoSlab-Bold.ttf │ │ │ │ │ ├── Inconsolata-Regular.ttf │ │ │ │ │ ├── RobotoSlab-Regular.ttf │ │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ │ └── fontawesome-webfont.woff │ │ │ │ └── css │ │ │ │ │ └── badge_only.css │ │ │ ├── _sources │ │ │ │ ├── quetzal.io.display.txt │ │ │ │ ├── quetzal.io.export.txt │ │ │ │ ├── quetzal.io.importer.txt │ │ │ │ ├── quetzal.model.model.txt │ │ │ │ ├── quetzal.engine.engine.txt │ │ │ │ ├── quetzal.io.export_utils.txt │ │ │ │ ├── quetzal.model.cubemodel.txt │ │ │ │ ├── quetzal.model.docmodel.txt │ │ │ │ ├── quetzal.model.stepmodel.txt │ │ │ │ ├── quetzal.io.gtfs_importer.txt │ │ │ │ ├── quetzal.analysis.analysis.txt │ │ │ │ ├── quetzal.engine.pathfinder.txt │ │ │ │ ├── quetzal.analysis.on_demand.txt │ │ │ │ ├── quetzal.engine.add_network.txt │ │ │ │ ├── quetzal.engine.screenlines.txt │ │ │ │ ├── quetzal.analysis.txt │ │ │ │ ├── quetzal.engine.connectivity.txt │ │ │ │ ├── quetzal.model.analysismodel.txt │ │ │ │ ├── quetzal.model.integritymodel.txt │ │ │ │ ├── quetzal.model.transportmodel.txt │ │ │ │ ├── quetzal.model.preparationmodel.txt │ │ │ │ ├── quetzal.engine.linearsolver_utils.txt │ │ │ │ ├── quetzal.analysis.cost_benefit_analysis.txt │ │ │ │ ├── quetzal.txt │ │ │ │ ├── quetzal.io.txt │ │ │ │ ├── index.txt │ │ │ │ ├── quetzal.engine.txt │ │ │ │ └── quetzal.model.txt │ │ │ ├── .buildinfo │ │ │ └── searchindex.js │ │ └── doctrees │ │ │ ├── index.doctree │ │ │ ├── quetzal.doctree │ │ │ ├── environment.pickle │ │ │ ├── quetzal.io.doctree │ │ │ ├── quetzal.model.doctree │ │ │ ├── quetzal.engine.doctree │ │ │ ├── quetzal.analysis.doctree │ │ │ ├── quetzal.io.display.doctree │ │ │ ├── quetzal.io.export.doctree │ │ │ ├── quetzal.io.importer.doctree │ │ │ ├── quetzal.model.model.doctree │ │ │ ├── quetzal.engine.engine.doctree │ │ │ ├── quetzal.io.export_utils.doctree │ │ │ ├── quetzal.model.cubemodel.doctree │ │ │ ├── quetzal.model.docmodel.doctree │ │ │ ├── quetzal.model.stepmodel.doctree │ │ │ ├── quetzal.analysis.analysis.doctree │ │ │ ├── quetzal.engine.pathfinder.doctree │ │ │ ├── quetzal.io.gtfs_importer.doctree │ │ │ ├── quetzal.analysis.on_demand.doctree │ │ │ ├── quetzal.engine.add_network.doctree │ │ │ ├── quetzal.engine.connectivity.doctree │ │ │ ├── quetzal.engine.screenlines.doctree │ │ │ ├── quetzal.model.analysismodel.doctree │ │ │ ├── quetzal.model.integritymodel.doctree │ │ │ ├── quetzal.model.transportmodel.doctree │ │ │ ├── quetzal.model.preparationmodel.doctree │ │ │ ├── quetzal.engine.linearsolver_utils.doctree │ │ │ └── quetzal.analysis.cost_benefit_analysis.doctree │ ├── quetzal.io.osm.rst │ ├── quetzal.io.road.rst │ ├── quetzal.io.excel.rst │ ├── quetzal.io.export.rst │ ├── quetzal.io.hdf_io.rst │ ├── quetzal.engine.csa.rst │ ├── quetzal.io.display.rst │ ├── quetzal.io.importer.rst │ ├── quetzal.model.model.rst │ ├── quetzal.engine.engine.rst │ ├── quetzal.model.docmodel.rst │ ├── quetzal.io.export_utils.rst │ ├── quetzal.model.cubemodel.rst │ ├── quetzal.model.plotmodel.rst │ ├── quetzal.model.stepmodel.rst │ ├── quetzal.engine.msa_utils.rst │ ├── quetzal.io.gtfs_importer.rst │ ├── quetzal.analysis.analysis.rst │ ├── quetzal.engine.gps_tracks.rst │ ├── quetzal.engine.graph_utils.rst │ ├── quetzal.engine.pathfinder.rst │ ├── quetzal.model.optimalmodel.rst │ ├── quetzal.model.summarymodel.rst │ ├── quetzal.analysis.on_demand.rst │ ├── quetzal.engine.add_network.rst │ ├── quetzal.engine.connectivity.rst │ ├── quetzal.engine.nested_logit.rst │ ├── quetzal.engine.screenlines.rst │ ├── quetzal.model.analysismodel.rst │ ├── quetzal.model.parkridemodel.rst │ ├── quetzal.model.integritymodel.rst │ ├── quetzal.model.transportmodel.rst │ ├── quetzal.analysis.accessibility.rst │ ├── quetzal.engine.parallelization.rst │ ├── quetzal.engine.optimal_strategy.rst │ ├── quetzal.engine.pathfinder_utils.rst │ ├── quetzal.engine.road_pathfinder.rst │ ├── quetzal.io.gtfs_reader.importer.rst │ ├── quetzal.io.gtfs_reader.patterns.rst │ ├── quetzal.io.gtfs_reader.services.rst │ ├── quetzal.launcher.launcher_utils.rst │ ├── quetzal.model.preparationmodel.rst │ ├── quetzal.model.timeexpandedmodel.rst │ ├── quetzal.io.gtfs_reader.filtering.rst │ ├── quetzal.engine.linearsolver_utils.rst │ ├── quetzal.engine.optimization_utils.rst │ ├── quetzal.io.gtfs_reader.directions.rst │ ├── quetzal.io.gtfs_reader.feed_gtfsk.rst │ ├── quetzal.model.connectionscanmodel.rst │ ├── quetzal.engine.time_expanded_utils.rst │ ├── quetzal.io.gtfs_reader.frequencies.rst │ ├── quetzal.io.gtfs_reader.gtfs_importer.rst │ ├── quetzal.analysis.cost_benefit_analysis.rst │ ├── quetzal.engine.add_network_mapmatching.rst │ ├── quetzal.engine.combinatorial_pathfinder.rst │ ├── quetzal.engine.park_and_ride_pathfinder.rst │ ├── quetzal.launcher.rst │ ├── quetzal.rst │ ├── quetzal.analysis.rst │ ├── quetzal.io.rst │ ├── quetzal.engine.rst │ ├── quetzal.io.gtfs_reader.rst │ └── quetzal.model.rst ├── index.html └── makedoc.py ├── .vscode ├── .ropeproject │ ├── objectdb │ └── config.py └── settings.json ├── index.html ├── ruff.toml ├── api └── ML_MatrixRoadCaster │ ├── Dockerfile.dockerignore │ ├── Dockerfile │ ├── requirements.txt │ ├── README.md │ ├── update-lambda.sh │ ├── update-lambda-dev.sh │ └── s3_utils.py ├── desktop.ini ├── .gitignore ├── setup.cfg ├── requirements_win.txt ├── windows-install.bat ├── pyproject.toml └── README.md /.nojekyll: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /syspy/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quetzal/io/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syspy/io/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quetzal/analysis/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quetzal/engine/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quetzal/launcher/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quetzal/model/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syspy/operations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syspy/pycube/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syspy/surveys/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | out/* 2 | -------------------------------------------------------------------------------- /syspy/syspy_utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /quetzal/io/gtfs_reader/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quetzal/.python-version: -------------------------------------------------------------------------------- 1 | quetzal_env 2 | -------------------------------------------------------------------------------- /quetzal/engine/combinatorial_pathfinder.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quetzal/engine/subprocesses/filepaths.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syspy/clients/linedraft_client/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syspy/distribution/description.txt: -------------------------------------------------------------------------------- 1 | tralalala 2 | -------------------------------------------------------------------------------- /syspy/io/pandasdbf/__init__.py: -------------------------------------------------------------------------------- 1 | from . import * -------------------------------------------------------------------------------- /syspy/clients/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /syspy/routing/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /syspy/skims/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /syspy/spatial/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /syspy/assignment/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /syspy/distribution/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /syspy/io/pandasshp/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /syspy/syspy_utils/test.py: -------------------------------------------------------------------------------- 1 | def sum(): 2 | print('vroom') 3 | -------------------------------------------------------------------------------- /syspy/transitfeed/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /syspy/routing/frequency/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /syspy/routing/timetable/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | -------------------------------------------------------------------------------- /tests/readme.txt: -------------------------------------------------------------------------------- 1 | to_run tests: 2 | python -m pytest syspy/tests/ 3 | -------------------------------------------------------------------------------- /docs/quetzal_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/quetzal_icon.ico -------------------------------------------------------------------------------- /docs/build/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/objects.inv -------------------------------------------------------------------------------- /.vscode/.ropeproject/objectdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/.vscode/.ropeproject/objectdb -------------------------------------------------------------------------------- /docs/build/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/_static/file.png -------------------------------------------------------------------------------- /docs/build/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/_static/minus.png -------------------------------------------------------------------------------- /docs/build/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/_static/plus.png -------------------------------------------------------------------------------- /docs/source/_images/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_images/Thumbs.db -------------------------------------------------------------------------------- /docs/source/_images/paris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_images/paris.png -------------------------------------------------------------------------------- /docs/source/nstatic/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/nstatic/Thumbs.db -------------------------------------------------------------------------------- /syspy/io/pandasshp/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/syspy/io/pandasshp/Thumbs.db -------------------------------------------------------------------------------- /docs/build/.doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/index.doctree -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/build/.doctrees/LICENSE.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/LICENSE.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/objects.inv -------------------------------------------------------------------------------- /docs/source/nstatic/gtfs_mexico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/nstatic/gtfs_mexico.png -------------------------------------------------------------------------------- /syspy/.vscode/.ropeproject/objectdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/syspy/.vscode/.ropeproject/objectdb -------------------------------------------------------------------------------- /docs/build/.doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.io.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.io.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/up.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/source/_build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/Thumbs.db -------------------------------------------------------------------------------- /docs/source/_build/html/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/down.png -------------------------------------------------------------------------------- /docs/source/_build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/file.png -------------------------------------------------------------------------------- /docs/source/_build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/minus.png -------------------------------------------------------------------------------- /docs/source/_build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/plus.png -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.engine.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.engine.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.model.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.model.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/comment.png -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.analysis.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.analysis.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.io.export.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.io.export.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.io.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.io.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/up-pressed.png -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.io.display.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.io.display.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.io.importer.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.io.importer.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.model.model.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.model.model.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.model.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.model.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/ajax-loader.gif -------------------------------------------------------------------------------- /docs/source/_build/html/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/comment-close.png -------------------------------------------------------------------------------- /docs/source/_build/html/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/down-pressed.png -------------------------------------------------------------------------------- /docs/source/_images/paris.pgw: -------------------------------------------------------------------------------- 1 | 10.65141178318930315 2 | 0 3 | 0 4 | -10.65141178318930315 5 | 644592.60360589157789946 6 | 6867101.39765243511646986 7 | -------------------------------------------------------------------------------- /syspy/paths.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | r_path = os.path.dirname(os.path.realpath(__file__)) 4 | gis_resources = r_path + r'/io/pandasshp/gis_resources/' 5 | -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.engine.engine.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.engine.engine.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.model.docmodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.model.docmodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.engine.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.engine.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/comment-bright.png -------------------------------------------------------------------------------- /docs/source/_build/html/_static/fonts/Lato-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/fonts/Lato-Bold.ttf -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.analysis.analysis.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.analysis.analysis.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.engine.pathfinder.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.engine.pathfinder.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.io.export_utils.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.io.export_utils.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.io.gtfs_importer.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.io.gtfs_importer.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.model.cubemodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.model.cubemodel.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.model.stepmodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.model.stepmodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.analysis.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.analysis.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.io.display.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.io.display.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.io.export.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.io.export.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/fonts/Lato-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/fonts/Lato-Regular.ttf -------------------------------------------------------------------------------- /docs/source/_images/favicon_package_v0.16/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_images/favicon_package_v0.16/favicon.ico -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.analysis.on_demand.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.analysis.on_demand.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.engine.add_network.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.engine.add_network.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.engine.connectivity.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.engine.connectivity.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.engine.screenlines.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.engine.screenlines.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.model.analysismodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.model.analysismodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.io.importer.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.io.importer.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.model.model.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.model.model.doctree -------------------------------------------------------------------------------- /ruff.toml: -------------------------------------------------------------------------------- 1 | line-length = 120 2 | 3 | [format] 4 | quote-style = "single" 5 | indent-style = "space" 6 | docstring-code-format = true 7 | skip-magic-trailing-comma = true -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.model.integritymodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.model.integritymodel.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.model.preparationmodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.model.preparationmodel.doctree -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.model.transportmodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.model.transportmodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.engine.engine.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.engine.engine.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.io.export_utils.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.io.export_utils.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.model.cubemodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.model.cubemodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.model.docmodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.model.docmodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.model.stepmodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.model.stepmodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/fonts/Inconsolata-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/fonts/Inconsolata-Bold.ttf -------------------------------------------------------------------------------- /docs/source/_build/html/_static/fonts/RobotoSlab-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/fonts/RobotoSlab-Bold.ttf -------------------------------------------------------------------------------- /docs/source/_images/favicon_package_v0.16/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_images/favicon_package_v0.16/favicon-16x16.png -------------------------------------------------------------------------------- /docs/source/_images/favicon_package_v0.16/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_images/favicon_package_v0.16/favicon-32x32.png -------------------------------------------------------------------------------- /api/ML_MatrixRoadCaster/Dockerfile.dockerignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.ipynb_checkpoints 3 | *.python-version 4 | *.md 5 | *.env 6 | api/ML_MatrixRoadCaster/notebook 7 | syspy/surveys -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.analysis.analysis.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.analysis.analysis.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.engine.pathfinder.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.engine.pathfinder.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.io.gtfs_importer.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.io.gtfs_importer.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/fonts/Inconsolata-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/fonts/Inconsolata-Regular.ttf -------------------------------------------------------------------------------- /docs/source/_build/html/_static/fonts/RobotoSlab-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/fonts/RobotoSlab-Regular.ttf -------------------------------------------------------------------------------- /docs/source/_build/html/_static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/source/_build/html/_static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/source/_images/favicon_package_v0.16/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_images/favicon_package_v0.16/mstile-150x150.png -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.engine.linearsolver_utils.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.engine.linearsolver_utils.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.analysis.on_demand.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.analysis.on_demand.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.engine.add_network.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.engine.add_network.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.engine.connectivity.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.engine.connectivity.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.engine.screenlines.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.engine.screenlines.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.model.analysismodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.model.analysismodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.model.integritymodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.model.integritymodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.model.transportmodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.model.transportmodel.doctree -------------------------------------------------------------------------------- /docs/source/_build/html/_static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/html/_static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/source/_images/favicon_package_v0.16/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_images/favicon_package_v0.16/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.model.preparationmodel.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.model.preparationmodel.doctree -------------------------------------------------------------------------------- /docs/source/quetzal.io.osm.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.osm module 2 | ===================== 3 | 4 | .. automodule:: quetzal.io.osm 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/build/.doctrees/quetzal.analysis.cost_benefit_analysis.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/build/.doctrees/quetzal.analysis.cost_benefit_analysis.doctree -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.engine.linearsolver_utils.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.engine.linearsolver_utils.doctree -------------------------------------------------------------------------------- /docs/source/_images/favicon_package_v0.16/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_images/favicon_package_v0.16/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/source/_images/favicon_package_v0.16/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_images/favicon_package_v0.16/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/source/quetzal.io.road.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.road module 2 | ====================== 3 | 4 | .. automodule:: quetzal.io.road 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.excel.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.excel module 2 | ======================= 3 | 4 | .. automodule:: quetzal.io.excel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /desktop.ini: -------------------------------------------------------------------------------- 1 | [.ShellClassInfo] 2 | IconResource=C:\Users\qchasserieau\OneDrive - SystraGroup\Images\favicon_package_v0.16 (2)\favicon.ico,0 3 | [ViewState] 4 | Mode= 5 | Vid= 6 | FolderType=Generic 7 | -------------------------------------------------------------------------------- /docs/source/_build/doctrees/quetzal.analysis.cost_benefit_analysis.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/systragroup/quetzal/HEAD/docs/source/_build/doctrees/quetzal.analysis.cost_benefit_analysis.doctree -------------------------------------------------------------------------------- /docs/source/quetzal.io.export.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.export module 2 | ======================== 3 | 4 | .. automodule:: quetzal.io.export 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.hdf_io.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.hdf\_io module 2 | ========================= 3 | 4 | .. automodule:: quetzal.io.hdf_io 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /syspy/io/pandasshp/gis_resources/projections/epsg4326.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /syspy/syspy_utils/gis_resources/projections/epsg4326.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /docs/source/quetzal.engine.csa.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.csa module 2 | ========================= 3 | 4 | .. automodule:: quetzal.engine.csa 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.display.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.display module 2 | ========================= 3 | 4 | .. automodule:: quetzal.io.display 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.importer.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.importer module 2 | ========================== 3 | 4 | .. automodule:: quetzal.io.importer 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.model.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.model module 2 | ========================== 3 | 4 | .. automodule:: quetzal.model.model 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /quetzal/__init__.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | import sys 3 | if sys.version_info.major != 3 or sys.version_info.minor < 12: 4 | warnings.warn(f'Quetzal was updated to python 3.12. Please refer to README to update.') -------------------------------------------------------------------------------- /docs/source/quetzal.engine.engine.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.engine module 2 | ============================ 3 | 4 | .. automodule:: quetzal.engine.engine 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.docmodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.docmodel module 2 | ============================= 3 | 4 | .. automodule:: quetzal.model.docmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.io.display.txt: -------------------------------------------------------------------------------- 1 | quetzal.io.display module 2 | ========================= 3 | 4 | .. automodule:: quetzal.io.display 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.io.export.txt: -------------------------------------------------------------------------------- 1 | quetzal.io.export module 2 | ======================== 3 | 4 | .. automodule:: quetzal.io.export 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.export_utils.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.export_utils module 2 | ============================== 3 | 4 | .. automodule:: quetzal.io.export_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.cubemodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.cubemodel module 2 | ============================== 3 | 4 | .. automodule:: quetzal.model.cubemodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.plotmodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.plotmodel module 2 | ============================== 3 | 4 | .. automodule:: quetzal.model.plotmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.stepmodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.stepmodel module 2 | ============================== 3 | 4 | .. automodule:: quetzal.model.stepmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.io.importer.txt: -------------------------------------------------------------------------------- 1 | quetzal.io.importer module 2 | ========================== 3 | 4 | .. automodule:: quetzal.io.importer 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.model.model.txt: -------------------------------------------------------------------------------- 1 | quetzal.model.model module 2 | ========================== 3 | 4 | .. automodule:: quetzal.model.model 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.msa_utils.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.msa\_utils module 2 | ================================ 3 | 4 | .. automodule:: quetzal.engine.msa_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_importer.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs_importer module 2 | =============================== 3 | 4 | .. automodule:: quetzal.io.gtfs_importer 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.analysis.analysis.rst: -------------------------------------------------------------------------------- 1 | quetzal.analysis.analysis module 2 | ================================ 3 | 4 | .. automodule:: quetzal.analysis.analysis 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.gps_tracks.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.gps\_tracks module 2 | ================================= 3 | 4 | .. automodule:: quetzal.engine.gps_tracks 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.graph_utils.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.graph\_utils module 2 | ================================== 3 | 4 | .. automodule:: quetzal.engine.graph_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.pathfinder.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.pathfinder module 2 | ================================ 3 | 4 | .. automodule:: quetzal.engine.pathfinder 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.optimalmodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.optimalmodel module 2 | ================================= 3 | 4 | .. automodule:: quetzal.model.optimalmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.summarymodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.summarymodel module 2 | ================================= 3 | 4 | .. automodule:: quetzal.model.summarymodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.engine.engine.txt: -------------------------------------------------------------------------------- 1 | quetzal.engine.engine module 2 | ============================ 3 | 4 | .. automodule:: quetzal.engine.engine 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.analysis.on_demand.rst: -------------------------------------------------------------------------------- 1 | quetzal.analysis.on_demand module 2 | ================================= 3 | 4 | .. automodule:: quetzal.analysis.on_demand 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.add_network.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.add_network module 2 | ================================= 3 | 4 | .. automodule:: quetzal.engine.add_network 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.connectivity.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.connectivity module 2 | ================================== 3 | 4 | .. automodule:: quetzal.engine.connectivity 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.nested_logit.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.nested\_logit module 2 | =================================== 3 | 4 | .. automodule:: quetzal.engine.nested_logit 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.screenlines.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.screenlines module 2 | ================================= 3 | 4 | .. automodule:: quetzal.engine.screenlines 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.analysismodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.analysismodel module 2 | ================================== 3 | 4 | .. automodule:: quetzal.model.analysismodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.parkridemodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.parkridemodel module 2 | ================================== 3 | 4 | .. automodule:: quetzal.model.parkridemodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.io.export_utils.txt: -------------------------------------------------------------------------------- 1 | quetzal.io.export_utils module 2 | ============================== 3 | 4 | .. automodule:: quetzal.io.export_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.model.cubemodel.txt: -------------------------------------------------------------------------------- 1 | quetzal.model.cubemodel module 2 | ============================== 3 | 4 | .. automodule:: quetzal.model.cubemodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.model.docmodel.txt: -------------------------------------------------------------------------------- 1 | quetzal.model.docmodel module 2 | ============================= 3 | 4 | .. automodule:: quetzal.model.docmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.model.stepmodel.txt: -------------------------------------------------------------------------------- 1 | quetzal.model.stepmodel module 2 | ============================== 3 | 4 | .. automodule:: quetzal.model.stepmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.integritymodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.integritymodel module 2 | =================================== 3 | 4 | .. automodule:: quetzal.model.integritymodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.transportmodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.transportmodel module 2 | =================================== 3 | 4 | .. automodule:: quetzal.model.transportmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.io.gtfs_importer.txt: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs_importer module 2 | =============================== 3 | 4 | .. automodule:: quetzal.io.gtfs_importer 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.analysis.accessibility.rst: -------------------------------------------------------------------------------- 1 | quetzal.analysis.accessibility module 2 | ===================================== 3 | 4 | .. automodule:: quetzal.analysis.accessibility 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.parallelization.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.parallelization module 2 | ===================================== 3 | 4 | .. automodule:: quetzal.engine.parallelization 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.analysis.analysis.txt: -------------------------------------------------------------------------------- 1 | quetzal.analysis.analysis module 2 | ================================ 3 | 4 | .. automodule:: quetzal.analysis.analysis 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.engine.pathfinder.txt: -------------------------------------------------------------------------------- 1 | quetzal.engine.pathfinder module 2 | ================================ 3 | 4 | .. automodule:: quetzal.engine.pathfinder 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.optimal_strategy.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.optimal\_strategy module 2 | ======================================= 3 | 4 | .. automodule:: quetzal.engine.optimal_strategy 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.pathfinder_utils.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.pathfinder\_utils module 2 | ======================================= 3 | 4 | .. automodule:: quetzal.engine.pathfinder_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.road_pathfinder.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.road\_pathfinder module 2 | ====================================== 3 | 4 | .. automodule:: quetzal.engine.road_pathfinder 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_reader.importer.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs\_reader.importer module 2 | ======================================= 3 | 4 | .. automodule:: quetzal.io.gtfs_reader.importer 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_reader.patterns.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs\_reader.patterns module 2 | ======================================= 3 | 4 | .. automodule:: quetzal.io.gtfs_reader.patterns 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_reader.services.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs\_reader.services module 2 | ======================================= 3 | 4 | .. automodule:: quetzal.io.gtfs_reader.services 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.launcher.launcher_utils.rst: -------------------------------------------------------------------------------- 1 | quetzal.launcher.launcher\_utils module 2 | ======================================= 3 | 4 | .. automodule:: quetzal.launcher.launcher_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.preparationmodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.preparationmodel module 2 | ===================================== 3 | 4 | .. automodule:: quetzal.model.preparationmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.timeexpandedmodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.timeexpandedmodel module 2 | ====================================== 3 | 4 | .. automodule:: quetzal.model.timeexpandedmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.analysis.on_demand.txt: -------------------------------------------------------------------------------- 1 | quetzal.analysis.on_demand module 2 | ================================= 3 | 4 | .. automodule:: quetzal.analysis.on_demand 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.engine.add_network.txt: -------------------------------------------------------------------------------- 1 | quetzal.engine.add_network module 2 | ================================= 3 | 4 | .. automodule:: quetzal.engine.add_network 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.engine.screenlines.txt: -------------------------------------------------------------------------------- 1 | quetzal.engine.screenlines module 2 | ================================= 3 | 4 | .. automodule:: quetzal.engine.screenlines 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_reader.filtering.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs\_reader.filtering module 2 | ======================================== 3 | 4 | .. automodule:: quetzal.io.gtfs_reader.filtering 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/build/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 60f528c778e046ba175bf6b491097794 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.analysis.txt: -------------------------------------------------------------------------------- 1 | quetzal.analysis package 2 | ======================== 3 | 4 | 5 | 6 | .. toctree:: 7 | 8 | quetzal.analysis.analysis 9 | quetzal.analysis.cost_benefit_analysis 10 | quetzal.analysis.on_demand -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.engine.connectivity.txt: -------------------------------------------------------------------------------- 1 | quetzal.engine.connectivity module 2 | ================================== 3 | 4 | .. automodule:: quetzal.engine.connectivity 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.model.analysismodel.txt: -------------------------------------------------------------------------------- 1 | quetzal.model.analysismodel module 2 | ================================== 3 | 4 | .. automodule:: quetzal.model.analysismodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.model.integritymodel.txt: -------------------------------------------------------------------------------- 1 | quetzal.model.integritymodel module 2 | =================================== 3 | 4 | .. automodule:: quetzal.model.integritymodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.model.transportmodel.txt: -------------------------------------------------------------------------------- 1 | quetzal.model.transportmodel module 2 | =================================== 3 | 4 | .. automodule:: quetzal.model.transportmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.linearsolver_utils.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.linearsolver_utils module 2 | ======================================== 3 | 4 | .. automodule:: quetzal.engine.linearsolver_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.optimization_utils.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.optimization\_utils module 2 | ========================================= 3 | 4 | .. automodule:: quetzal.engine.optimization_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_reader.directions.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs\_reader.directions module 2 | ========================================= 3 | 4 | .. automodule:: quetzal.io.gtfs_reader.directions 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_reader.feed_gtfsk.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs\_reader.feed\_gtfsk module 2 | ========================================== 3 | 4 | .. automodule:: quetzal.io.gtfs_reader.feed_gtfsk 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.connectionscanmodel.rst: -------------------------------------------------------------------------------- 1 | quetzal.model.connectionscanmodel module 2 | ======================================== 3 | 4 | .. automodule:: quetzal.model.connectionscanmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.time_expanded_utils.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.time\_expanded\_utils module 2 | =========================================== 3 | 4 | .. automodule:: quetzal.engine.time_expanded_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_reader.frequencies.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs\_reader.frequencies module 2 | ========================================== 3 | 4 | .. automodule:: quetzal.io.gtfs_reader.frequencies 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /syspy/spatial/graph/__init__.py: -------------------------------------------------------------------------------- 1 | # module level doc-string 2 | __doc__ = """ 3 | This module provides tools for network processing. 4 | It processes geometries more than abstract graphs. 5 | network contains the tools 6 | graphbuilder contains the wrapper 7 | """ 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.model.preparationmodel.txt: -------------------------------------------------------------------------------- 1 | quetzal.model.preparationmodel module 2 | ===================================== 3 | 4 | .. automodule:: quetzal.model.preparationmodel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: d3e45443eb1522752c325181ab085454 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_reader.gtfs_importer.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs\_reader.gtfs\_importer module 2 | ============================================= 3 | 4 | .. automodule:: quetzal.io.gtfs_reader.gtfs_importer 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.engine.linearsolver_utils.txt: -------------------------------------------------------------------------------- 1 | quetzal.engine.linearsolver_utils module 2 | ======================================== 3 | 4 | .. automodule:: quetzal.engine.linearsolver_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.analysis.cost_benefit_analysis.rst: -------------------------------------------------------------------------------- 1 | quetzal.analysis.cost_benefit_analysis module 2 | ============================================= 3 | 4 | .. automodule:: quetzal.analysis.cost_benefit_analysis 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.add_network_mapmatching.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.add\_network\_mapmatching module 2 | =============================================== 3 | 4 | .. automodule:: quetzal.engine.add_network_mapmatching 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.combinatorial_pathfinder.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.combinatorial\_pathfinder module 2 | =============================================== 3 | 4 | .. automodule:: quetzal.engine.combinatorial_pathfinder 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.park_and_ride_pathfinder.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine.park\_and\_ride\_pathfinder module 2 | ================================================= 3 | 4 | .. automodule:: quetzal.engine.park_and_ride_pathfinder 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.analysis.cost_benefit_analysis.txt: -------------------------------------------------------------------------------- 1 | quetzal.analysis.cost_benefit_analysis module 2 | ============================================= 3 | 4 | .. automodule:: quetzal.analysis.cost_benefit_analysis 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /quetzal/index.txt: -------------------------------------------------------------------------------- 1 | quetzal package 2 | ===================== 3 | 4 | .. include:: ../syspy/quetzal/description.txt 5 | 6 | Subpackages 7 | ----------- 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | 12 | quetzal.analysis 13 | quetzal.engine 14 | quetzal.io 15 | quetzal.stories 16 | -------------------------------------------------------------------------------- /docs/source/_images/favicon_package_v0.16/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /api/ML_MatrixRoadCaster/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.12 2 | COPY api/ML_MatrixRoadCaster/requirements.txt ./requirements.txt 3 | RUN pip install -r ./requirements.txt 4 | 5 | COPY api/ML_MatrixRoadCaster/ ./ 6 | #COPY quetzal/engine/road_model.py ./road_model.py 7 | COPY quetzal ./quetzal 8 | COPY syspy ./syspy 9 | 10 | CMD ["main.handler"] -------------------------------------------------------------------------------- /docs/source/quetzal.launcher.rst: -------------------------------------------------------------------------------- 1 | quetzal.launcher package 2 | ======================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | quetzal.launcher.launcher_utils 11 | 12 | Module contents 13 | --------------- 14 | 15 | .. automodule:: quetzal.launcher 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | -------------------------------------------------------------------------------- /docs/source/quetzal.rst: -------------------------------------------------------------------------------- 1 | quetzal package 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | quetzal.analysis 10 | quetzal.engine 11 | quetzal.io 12 | quetzal.model 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: quetzal 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.txt: -------------------------------------------------------------------------------- 1 | quetzal package 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | quetzal.analysis 10 | quetzal.engine 11 | quetzal.io 12 | quetzal.model 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: quetzal 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **__pycache__** 2 | *.pyc 3 | doc/ 4 | **.cache** 5 | **.ipynb_checkpoints 6 | quetzal/tests/data/out/ 7 | tests/data/out/ 8 | .eggs/ 9 | *.egg-info/ 10 | .venv/ 11 | .idea/ 12 | .python-version 13 | .vscode/ 14 | 15 | build/ 16 | *.env 17 | !docker/templates/.env 18 | 19 | # Local .terraform directories 20 | **/.terraform/* 21 | docker/infra/.terraform/* 22 | *.tfstate 23 | *.tfstate.* 24 | 25 | -------------------------------------------------------------------------------- /docs/makedoc.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath('../..')) 5 | 6 | os.system('rmdir /s /q build') 7 | project_options = '-H quetzal -A Systra' 8 | make_options = '-o source ../quetzal -s rst' 9 | make_options_1 = '--full --separate' 10 | 11 | os.system(f'sphinx-apidoc {make_options} {make_options_1} {project_options}') 12 | os.system('sphinx-build -b html source build') 13 | -------------------------------------------------------------------------------- /docs/source/quetzal.analysis.rst: -------------------------------------------------------------------------------- 1 | quetzal.analysis package 2 | ======================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | quetzal.analysis.analysis 10 | quetzal.analysis.cost_benefit_analysis 11 | quetzal.analysis.on_demand 12 | 13 | Module contents 14 | --------------- 15 | 16 | .. automodule:: quetzal.analysis 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | -------------------------------------------------------------------------------- /docs/source/quetzal.io.rst: -------------------------------------------------------------------------------- 1 | quetzal.io package 2 | ================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | quetzal.io.display 10 | quetzal.io.export 11 | quetzal.io.export_utils 12 | quetzal.io.gtfs_importer 13 | quetzal.io.importer 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: quetzal.io 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /syspy/io/pandasshp/gis_resources/projections/epsg32614.prj: -------------------------------------------------------------------------------- 1 | PROJCS["WGS_1984_UTM_Zone_14N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-99],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]] -------------------------------------------------------------------------------- /syspy/syspy_utils/gis_resources/projections/epsg32614.prj: -------------------------------------------------------------------------------- 1 | PROJCS["WGS_1984_UTM_Zone_14N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-99],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]] -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.io.txt: -------------------------------------------------------------------------------- 1 | quetzal.io package 2 | ================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | quetzal.io.display 10 | quetzal.io.export 11 | quetzal.io.export_utils 12 | quetzal.io.gtfs_importer 13 | quetzal.io.importer 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: quetzal.io 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /quetzal/engine/subprocesses/subprocess_path_and_duration_from_graph_json.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | from pathlib import Path 4 | 5 | from quetzal.engine.pathfinder import path_and_duration_from_graph_json 6 | 7 | path = Path(__file__) 8 | libdir = str(path.parent.parent.parent.parent) 9 | print(libdir) 10 | 11 | sys.path.insert(0, libdir) 12 | 13 | io_string = sys.argv[1] 14 | kwargs = json.loads(io_string) 15 | path_and_duration_from_graph_json(**kwargs) 16 | -------------------------------------------------------------------------------- /syspy/syspy_utils/gis_resources/projections/epsg2154.prj: -------------------------------------------------------------------------------- 1 | PROJCS["RGF93_Lambert_93",GEOGCS["GCS_RGF93",DATUM["D_RGF_1993",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["standard_parallel_1",49],PARAMETER["standard_parallel_2",44],PARAMETER["latitude_of_origin",46.5],PARAMETER["central_meridian",3],PARAMETER["false_easting",700000],PARAMETER["false_northing",6600000],UNIT["Meter",1]] -------------------------------------------------------------------------------- /syspy/io/pandasshp/gis_resources/projections/epsg2154.prj: -------------------------------------------------------------------------------- 1 | PROJCS["RGF93_Lambert_93",GEOGCS["GCS_RGF93",DATUM["D_RGF_1993",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["standard_parallel_1",49],PARAMETER["standard_parallel_2",44],PARAMETER["latitude_of_origin",46.5],PARAMETER["central_meridian",3],PARAMETER["false_easting",700000],PARAMETER["false_northing",6600000],UNIT["Meter",1]] -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/index.txt: -------------------------------------------------------------------------------- 1 | Quetzal Overview 2 | ================ 3 | quetzal is a Python package providing flexible models for transport planning and traffic forecasting. 4 | 5 | Packages 6 | ======== 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | quetzal.engine 12 | quetzal.model 13 | quetzal.io 14 | quetzal.analysis 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | 23 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | 4 | class MyTest(TestCase): 5 | # basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) + '\\data' 6 | # uri = ':memory:' 7 | # #uri = os.path.join(basedir, 'app.db') 8 | # SQLALCHEMY_DATABASE_URI = "sqlite:///" + uri 9 | # TESTING = True 10 | 11 | def setUp(self): 12 | pass 13 | 14 | def tearDown(self): 15 | pass 16 | # db.session.remove() 17 | # db.drop_all() 18 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | # If set to 1, this flag says that the code is written to work on both Python 2 3 | # and Python 3. If at all possible, it is good practice to do this. If you 4 | # cannot, you will need to generate wheels for each Python version that you 5 | # support. 6 | universal=0 7 | 8 | # alieas created for automated testing at setup 9 | # http://doc.pytest.org/en/latest/goodpractices.html#integrating-with-setuptools-python-setup-py-test-pytest-runner 10 | [aliases] 11 | test=pytest 12 | -------------------------------------------------------------------------------- /docs/source/quetzal.engine.rst: -------------------------------------------------------------------------------- 1 | quetzal.engine package 2 | ====================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | quetzal.engine.add_network 10 | quetzal.engine.connectivity 11 | quetzal.engine.engine 12 | quetzal.engine.linearsolver_utils 13 | quetzal.engine.pathfinder 14 | quetzal.engine.screenlines 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: quetzal.engine 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.engine.txt: -------------------------------------------------------------------------------- 1 | quetzal.engine package 2 | ====================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | quetzal.engine.add_network 10 | quetzal.engine.connectivity 11 | quetzal.engine.engine 12 | quetzal.engine.linearsolver_utils 13 | quetzal.engine.pathfinder 14 | quetzal.engine.screenlines 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: quetzal.engine 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/source/_images/favicon_package_v0.16/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /docs/source/_build/html/_sources/quetzal.model.txt: -------------------------------------------------------------------------------- 1 | quetzal.model package 2 | ===================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | quetzal.model.analysismodel 10 | quetzal.model.cubemodel 11 | quetzal.model.docmodel 12 | quetzal.model.integritymodel 13 | quetzal.model.model 14 | quetzal.model.preparationmodel 15 | quetzal.model.stepmodel 16 | quetzal.model.transportmodel 17 | 18 | Module contents 19 | --------------- 20 | 21 | .. automodule:: quetzal.model 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | -------------------------------------------------------------------------------- /syspy/logit/multinomial_logit.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def nest_probabilities(utilities, phi=1): 5 | exponential_df = np.exp(np.multiply(utilities, 1 / phi)) 6 | exponential_s = exponential_df.T.sum() 7 | probability_df = exponential_df.apply(lambda s: s / exponential_s) 8 | return probability_df.T 9 | 10 | 11 | def nest_utility(utilities, phi=1): 12 | exponential_df = np.exp(np.multiply(utilities, 1 / phi)) 13 | exponential_s = exponential_df.T.sum() 14 | emu = np.log(exponential_s) 15 | composite_utility = phi * emu 16 | return composite_utility 17 | -------------------------------------------------------------------------------- /syspy/routing/networkx_wrapper.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | from tqdm import tqdm 3 | 4 | 5 | def pairwise_function(single_source_function, sources, targets, **kwargs): 6 | resp_dict = {} 7 | for source in tqdm(sources): 8 | try: 9 | to_all_targets = single_source_function(source=source, **kwargs) 10 | filtered = { 11 | key: value for key, value in to_all_targets.items() 12 | if key in targets 13 | } 14 | resp_dict[source] = filtered 15 | except KeyError: 16 | print(source) 17 | return resp_dict 18 | -------------------------------------------------------------------------------- /api/ML_MatrixRoadCaster/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3==1.34.131 2 | fiona==1.9.6 3 | fqdn==1.5.1 4 | fastapi==0.111.0 5 | geopy==2.4.1 6 | gtfs-kit==6.1.0 7 | httptools==0.6.1 8 | ipywidgets==8.1.3 9 | isoduration==20.11.0 10 | jsonpointer==3.0.0 11 | networkx==3.3 12 | notebook==6.5.7 13 | numba==0.60.0 14 | openmatrix==0.3.5.0 15 | openpyxl==3.1.5 16 | python-dotenv==1.0.1 17 | rasterio==1.3.10 18 | s3fs==2024.6.1 19 | scikit-learn==1.5.1 20 | seaborn==0.13.2 21 | tqdm==4.66.4 22 | uri-template==1.3.0 23 | uvloop==0.19.0 24 | watchfiles==0.22.0 25 | webcolors==24.6.0 26 | websockets==12.0 27 | xlrd==2.0.1 28 | zstandard==0.23.0 29 | -------------------------------------------------------------------------------- /requirements_win.txt: -------------------------------------------------------------------------------- 1 | boto3==1.34.144 2 | fastapi==0.111.1 3 | fiona==1.9.6 4 | fqdn==1.5.1 5 | geopy==2.4.1 6 | gevent==24.2.1 7 | gtfs-kit==6.1.0 8 | httptools==0.6.1 9 | ipywidgets==8.1.3 10 | isoduration==20.11.0 11 | jsonpointer==3.0.0 12 | networkx==3.3 13 | notebook==6.5.7 14 | numba==0.60.0 15 | openmatrix==0.3.5.0 16 | openpyxl==3.1.5 17 | orjson==3.10.6 18 | pip-chill==1.0.3 19 | python-dotenv==1.0.1 20 | rasterio==1.3.10 21 | s3fs==0.4.2 22 | scikit-learn==1.5.1 23 | seaborn==0.13.2 24 | tqdm==4.66.4 25 | ujson==5.10.0 26 | uri-template==1.3.0 27 | watchfiles==0.22.0 28 | webcolors==24.6.0 29 | websockets==12.0 30 | xlrd==2.0.1 31 | zstandard==0.23.0 -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | // "python.pythonPath": "${workspaceFolder}/.venv/bin/python3.8", 4 | "python.pythonPath": "${QUETZAL_ENV}/python.exe", 5 | "python.venvPath": "${QUETZAL_ENV}", 6 | "python.jediEnabled": true, 7 | "python.workspaceSymbols.tagFilePath": "${workspaceFolder}/.vscode/tags", 8 | "python.workspaceSymbols.enabled": true, 9 | "python.linting.pylintEnabled": false, 10 | "python.linting.flake8Enabled": true, 11 | "python.linting.mypyArgs": [ 12 | "--ignore-missing-imports", 13 | "--follow-imports=silent", 14 | "--disable=W503" 15 | ], 16 | "python.linting.enabled": true, 17 | } -------------------------------------------------------------------------------- /docs/source/quetzal.io.gtfs_reader.rst: -------------------------------------------------------------------------------- 1 | quetzal.io.gtfs\_reader package 2 | =============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | quetzal.io.gtfs_reader.directions 11 | quetzal.io.gtfs_reader.feed_gtfsk 12 | quetzal.io.gtfs_reader.filtering 13 | quetzal.io.gtfs_reader.frequencies 14 | quetzal.io.gtfs_reader.gtfs_importer 15 | quetzal.io.gtfs_reader.importer 16 | quetzal.io.gtfs_reader.patterns 17 | quetzal.io.gtfs_reader.services 18 | 19 | Module contents 20 | --------------- 21 | 22 | .. automodule:: quetzal.io.gtfs_reader 23 | :members: 24 | :undoc-members: 25 | :show-inheritance: 26 | -------------------------------------------------------------------------------- /docs/source/quetzal.model.rst: -------------------------------------------------------------------------------- 1 | quetzal.model package 2 | ===================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | quetzal.model.analysismodel 10 | quetzal.model.cubemodel 11 | quetzal.model.docmodel 12 | quetzal.model.integritymodel 13 | quetzal.model.model 14 | quetzal.model.preparationmodel 15 | quetzal.model.stepmodel 16 | quetzal.model.transportmodel 17 | quetzal.model.connectionscanmodel 18 | quetzal.model.timeexpandedmodel 19 | quetzal.model.parkridemodel 20 | 21 | Module contents 22 | --------------- 23 | 24 | .. automodule:: quetzal.model 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | -------------------------------------------------------------------------------- /quetzal/engine/msa_trackers/tracker.py: -------------------------------------------------------------------------------- 1 | import abc 2 | from typing import List 3 | 4 | 5 | # abstract class to create trackers 6 | class Tracker(abc.ABC): 7 | @abc.abstractmethod 8 | def __init__(self, track_links_list: List): 9 | pass 10 | 11 | @abc.abstractmethod 12 | def init(self, links_sparse_index, links_to_sparse): 13 | pass 14 | 15 | @abc.abstractmethod 16 | def __call__(self) -> bool: 17 | pass 18 | 19 | @abc.abstractmethod 20 | def assign(self, ab_volumes, odv, pred, seg, it): 21 | pass 22 | 23 | @abc.abstractmethod 24 | def add_weights(self, phi, beta, relgap, it): 25 | pass 26 | 27 | @abc.abstractmethod 28 | def merge(self): 29 | pass 30 | -------------------------------------------------------------------------------- /windows-install.bat: -------------------------------------------------------------------------------- 1 | @echo on 2 | cd "%~dp0" 3 | 4 | call set SSL_NO_VERIFY=1 5 | call conda config --set ssl_verify false 6 | 7 | SET /P env_name=enter an environment name (default = quetzal_env): 8 | IF NOT DEFINED env_name SET "env_name=quetzal_env" 9 | 10 | if not "X%CONDA_DEFAULT_ENV%" == "X%env_name%" ( 11 | conda info -e | findstr %env_name% > NUL 12 | if errorlevel 1 ( 13 | call conda create -n %env_name% -y python=3.12 14 | timeout 3 /nobreak > NUL 15 | ) 16 | call activate %env_name% 17 | ) 18 | 19 | @echo on 20 | echo Installing... 21 | call python -m pip install -e . -r requirements_win.txt --trusted-host pypi.org --trusted-host files.pythonhosted.org 22 | 23 | call python -m ipykernel install --user --name=%env_name% 24 | 25 | echo Done! 26 | @pause -------------------------------------------------------------------------------- /quetzal/description.txt: -------------------------------------------------------------------------------- 1 | Quetzal est une librairie python développée au sein de SYSTRA permettant 2 | la réalisation intégrale d’un modèle multimodal à 4 étapes, l’analyse des 3 | lignes de désir, la génération automatique d’indicateurs d’offre 4 | et de demande (fréquentation des lignes et des stations, 5 | report modal au niveau du zonage du modèle, comparaison des temps VP et TC) 6 | ainsi que la réalisation d’une analyse coût-bénéfice. Cette librairie Python, 7 | compatible avec nos outils Linedraft et ITSIM, 8 | est également adossé à un logiciel libre de SIG pour la visualisation 9 | des différents indicateurs.  10 | 11 | 12 | .. figure:: ./pictures/quetzal/graphviz.png 13 | :width: 100% 14 | :alt: alternate text 15 | :figclass: align-center 16 | 17 | quetzal 18 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "quetzal" 3 | version = "1.0.0" 4 | description = "modeling library for transport planning" 5 | authors = ["Quentin Chasserieau = nodes if nodes else True 13 | bool_links = row['pt_path'] >= links if links else True 14 | return bool_nodes & bool_links 15 | 16 | 17 | def checkpoint_demand( 18 | od_stack, 19 | link_checkpoints, 20 | node_checkpoints, 21 | volume_columns=['volume'], 22 | suffixe='' 23 | ): 24 | df = od_stack.copy() 25 | df['select_bool'] = df.apply( 26 | lambda r: select(r, link_checkpoints, node_checkpoints), 27 | axis=1 28 | ) 29 | for column in volume_columns: 30 | df[column + suffixe] = df[column] * df['select_bool'] 31 | return df 32 | -------------------------------------------------------------------------------- /tests/data/jsons/jsons.json: -------------------------------------------------------------------------------- 1 | {"index":{"0":"broken_sequences","1":"circular_lines","2":"debug","3":"parameters","4":"walk_on_road"},"json":{"0":"[\"AAMV_bis\"]","1":"[\"AAMV\"]","2":"true","3":"{\"step_distribution\": {\"args\": [], \"kwargs\": {}}, \"step_ntlegs\": {\"args\": [], \"kwargs\": {\"n_ntlegs\": 5, \"short_leg_speed\": 2, \"long_leg_speed\": 10, \"threshold\": 1000, \"max_ntleg_length\": 100000}}, \"step_footpaths\": {\"args\": [], \"kwargs\": {\"speed\": 1}}, \"step_pathfinder\": {\"args\": [], \"kwargs\": {}}, \"step_assignment\": {\"args\": [], \"kwargs\": {\"volume_column\": \"volume_pt\", \"boardings\": true, \"alightings\": true, \"transfers\": true}}, \"checkpoints\": {\"args\": [], \"kwargs\": {\"link_checkpoints\": [], \"node_checkpoints\": [\"BULLFROG\"], \"volume_column\": \"volume_pt\"}}, \"to_hdf\": {\"args\": [\"..\/..\/quetzal\/inputs\/sample-feed\/hdf\/quetzal.hdf\"], \"kwargs\": {}}, \"to_json\": {\"args\": [\"..\/..\/quetzal\/inputs\/sample-feed\/jsons\"], \"kwargs\": {}}}","4":"false"}} -------------------------------------------------------------------------------- /quetzal/io/md.py: -------------------------------------------------------------------------------- 1 | class MDFILE(): 2 | def __init__(self): 3 | self.content='''''' 4 | def __repr__(self): 5 | return self.content 6 | 7 | def newline(self, n:int=1): 8 | self.content += n*'\n' 9 | 10 | def add_text(self, string:str): 11 | self.newline() 12 | self.content += string 13 | 14 | def add_header(self, string:str, level:int=1): 15 | self.newline() 16 | formated_string = level*'#' + ' '+ string 17 | self.content += formated_string 18 | 19 | def add_image(self, path:str, text:str='alt text'): 20 | self.newline(2) 21 | self.content += f'![{text}]({path})' 22 | 23 | def load(self, file_path:str='sample.md'): 24 | with open(file_path, 'r') as mdfile: 25 | self.content = mdfile.read() 26 | 27 | def write(self, file_path:str='sample.md'): 28 | # Write the string to the markdown file 29 | with open(file_path, 'w') as mdfile: 30 | mdfile.write(self.content) -------------------------------------------------------------------------------- /syspy/io/geojson_utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | import geopandas as gpd 5 | 6 | default_crs_string = "urn:ogc:def:crs:EPSG::2154" 7 | default_prj_file = "../syspy_utils/gis_resources/epsg2154.prj" 8 | 9 | 10 | def set_geojson_crs(file, crs_string=default_crs_string, encoding='utf-8'): 11 | with open(file, 'r', encoding=encoding) as infile: 12 | data = json.load(infile) 13 | infile.close() 14 | with open(file, 'w', encoding=encoding) as outfile: 15 | data['crs'] = {"type": "name", "properties": {"name": crs_string}} 16 | json.dump(data, outfile) 17 | 18 | 19 | def set_shp_crs(file, prj_file=default_prj_file): 20 | file_without_extension = file.split('.shp')[0] 21 | copyfile(prj_file, file_without_extension + r'.prj') 22 | 23 | 24 | def gdf_to_geojson(gdf, filename, crs_string=default_crs_string, encoding='utf-8'): 25 | try: 26 | os.remove(filename) 27 | except OSError: 28 | pass 29 | gdf.to_file(filename, driver='GeoJSON', encoding=encoding) 30 | set_geojson_crs(filename, crs_string, encoding=encoding) 31 | -------------------------------------------------------------------------------- /quetzal/io/cube/cube.py: -------------------------------------------------------------------------------- 1 | def head_string(links, trip_id): 2 | return 'LINE NAME="%s", ONEWAY=T, ' % trip_id 3 | 4 | 5 | def stop_and_node_string(links, trip_id): 6 | line = links.loc[links['trip_id'] == trip_id] 7 | 8 | dicts = [] 9 | for nodes in list(line['road_node_list']): 10 | dicts.append({'nodes': nodes[1:-1], 'stop': nodes[-1]}) 11 | 12 | s = 'N=%s' % (str(line['road_a'].iloc[0])) 13 | for chunk in dicts: 14 | for node in chunk['nodes']: 15 | s += ', ' + '-' + str(node) 16 | s += ', ' + str(chunk['stop']) 17 | return s 18 | 19 | 20 | def lin_string(links, trip_id, custom_head=head_string): 21 | return custom_head(links, trip_id) + stop_and_node_string(links, trip_id) 22 | 23 | 24 | class cubeModel(): 25 | def __init__(self): 26 | pass 27 | 28 | 29 | def to_lin(self, path_or_buf): 30 | lines = set(self.links['trip_id']) 31 | lin = '' 32 | for trip_id in lines: 33 | lin += lin_string(self.links, trip_id) 34 | lin += ' \n' 35 | 36 | with open(path_or_buf, 'w') as file: 37 | file.write(lin) 38 | -------------------------------------------------------------------------------- /api/ML_MatrixRoadCaster/README.md: -------------------------------------------------------------------------------- 1 | 2 | # quetzal 3 | ## Copyright 4 | (c) SYSTRA 5 | ## License 6 | [CeCILL-B](LICENSE.md) 7 | ## Deploy 8 | ```bash 9 | ./update-lambda.sh 10 | ``` 11 | ## TEST 12 | 13 | 1) create a test.env file at the root of this folder (with the DockerFile) 14 | ```bash 15 | AWS_ACCESS_KEY_ID=[your access key] 16 | AWS_SECRET_ACCESS_KEY=[your secret key] 17 | AWS_REGION=ca-central 18 | BUCKET_NAME=quetzal-api-bucket 19 | AWS_LAMBDA_FUNCTION_MEMORY_SIZE=3000 20 | ``` 21 | 2) Buld the Docker from quetzal root directory (not this one) 22 | ```bash 23 | docker build -f api/ML_MatrixRoadCaster/Dockerfile -t ml_matrixroadcaster:latest . 24 | ``` 25 | 3) run the docker with the environment variable 26 | ```bash 27 | docker run -p 9000:8080 --env-file 'api/ML_MatrixRoadCaster/test.env' ml_matrixroadcaster 28 | ``` 29 | 4) from another terminal window: 30 | ```bash 31 | curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"callID":"test"}' 32 | ``` 33 | CallId correspond to a folder on the s3 Bucket matrixroadcaster. you need to add road_links.geojson and road_nodes.geojson first. if there is no here_OD.csv. the here api will be call and you need to provide your apikey il the XPOST payload (ex: {"callID":"test","hereApiKey":"THIS-IS-AN-API-KEY"}) -------------------------------------------------------------------------------- /syspy/syspy_utils/assignment.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | 3 | import itertools 4 | 5 | import pandas as pd 6 | 7 | 8 | def nested_list(volume_array, paths): 9 | return [[volume_array[i]] * len(paths[i]) for i in range(len(volume_array))] 10 | 11 | 12 | def assign(volume_array, paths): 13 | nested_row_indices = [[i] * len(paths[i]) for i in range(len(volume_array))] 14 | row_indices = list(itertools.chain.from_iterable(nested_row_indices)) 15 | column_indices = list(itertools.chain.from_iterable(paths)) 16 | nested_volumes = nested_list(volume_array, paths) 17 | volumes = list(itertools.chain.from_iterable(nested_volumes)) 18 | try: 19 | test = volumes[0][0] # volumes_array is an ndarray 20 | sparse = pd.concat( 21 | ( 22 | pd.DataFrame( 23 | { 24 | 'od': row_indices, 25 | 'link': column_indices 26 | } 27 | ), 28 | pd.DataFrame(volumes) 29 | ), 30 | axis=1 31 | ) 32 | except IndexError: # volume_array is actually a 1d vector 33 | sparse = (pd.DataFrame({'od': row_indices, 'link': column_indices, 'volume': volumes})) 34 | return sparse.drop('od', axis=1).groupby('link').sum() 35 | -------------------------------------------------------------------------------- /quetzal/engine/parallelization.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ProcessPoolExecutor 2 | 3 | from tqdm import tqdm 4 | 5 | 6 | def map_kwargs(func, iterables=[], show_progress=False, **kwargs): 7 | return [ 8 | func(arg, **kwargs) 9 | for arg in (tqdm(iterables) if show_progress else iterables) 10 | ] 11 | 12 | 13 | def parallel_map_kwargs(func, iterables, workers=1, **kwargs): 14 | if workers == 1: 15 | return map_kwargs(func, iterables, **kwargs) 16 | 17 | chunk_size = len(iterables) // workers 18 | if len(iterables) % workers > 0: 19 | chunk_size += 1 20 | 21 | results = [] 22 | with ProcessPoolExecutor(max_workers=workers) as executor: 23 | for i in range(workers): 24 | results.append( 25 | executor.submit( 26 | map_kwargs, 27 | func, 28 | iterables[i * chunk_size:(i + 1) * chunk_size], 29 | **kwargs 30 | ) 31 | ) 32 | 33 | to_return = [] 34 | for i in range(len(results)): 35 | r = results.pop(0) 36 | try: 37 | to_return += r.result() 38 | except TypeError: # 'NoneType' object is not subscriptable 39 | print('error') 40 | pass 41 | del r 42 | return to_return 43 | -------------------------------------------------------------------------------- /syspy/syspy_utils/daycount.py: -------------------------------------------------------------------------------- 1 | def count_by_weekday(start_date, end_date): 2 | """ 3 | returns a list of length 7 with the number of occurrences of each day over a given period 4 | 5 | :param start_date: first day of the period 6 | :type start_date: datetime.datetime 7 | :param end_date: first day after the period 8 | :type end_date: datetime.datetime 9 | :return: inner_count_by_weekday 10 | :rtype: list 11 | """ 12 | delta = end_date - start_date 13 | inner_count_by_weekday = [delta.days // 7] * 7 14 | 15 | for i in range(delta.days % 7): 16 | inner_count_by_weekday[(start_date.weekday() + i) % 7] += 1 17 | return inner_count_by_weekday 18 | 19 | 20 | def count_from_mask(start_date, end_date, mask=(1, 1, 1, 1, 1, 1, 1)): 21 | """ 22 | returns the number of days in a period that are consistent with the provided mask 23 | 24 | :param start_date: first day of the period 25 | :type start_date: datetime.datetime 26 | :param end_date: first day after the period 27 | :type end_date: datetime.datetime 28 | :param mask: boolean list of length 7 that states wich weekday should be taken into account 29 | :type mask: list 30 | :return: count 31 | :rtype: int 32 | """ 33 | inner_count_by_weekday = count_by_weekday(start_date, end_date) 34 | count = 0 35 | for i in range(7): 36 | count += mask[i] * inner_count_by_weekday[i] 37 | return count 38 | -------------------------------------------------------------------------------- /syspy/spatial/utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | def haversine(coord1: object, coord2: object)->float: 3 | # Coordinates in decimal degrees (e.g. 2.89078, 12.79797) 4 | lat1, lon1 = coord1 5 | lat2, lon2 = coord2 6 | 7 | R = 6371000 # radius of Earth in meters 8 | phi_1 = math.radians(lat1) 9 | phi_2 = math.radians(lat2) 10 | 11 | delta_phi = math.radians(lat2 - lat1) 12 | delta_lambda = math.radians(lon2 - lon1) 13 | 14 | a = math.sin(delta_phi / 2.0) ** 2 + math.cos(phi_1) * math.cos(phi_2) * math.sin(delta_lambda / 2.0) ** 2 15 | 16 | c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) 17 | 18 | meters = R * c # output distance in meters 19 | 20 | return meters 21 | 22 | def get_acf_distance(x:list,reverse:bool=False)->list: 23 | # return dist in meters between 2 points in CRS 4326 (degs) 24 | # inputs : [(lat,lon), (lat,lon)]. or [(y,x),(y,x)] 25 | # if reverse : [(lon,lat), (lon,lat)]. or [(x,y),(x,y)] 26 | # ex: df['geometry'].apply(lambda x: get_acf_distance([x.coords[0],x.coords[-1]],True)) 27 | if reverse: 28 | return haversine(x[0][::-1],x[1][::-1]) 29 | else: 30 | return haversine(x[0],x[1]) 31 | 32 | 33 | def get_epsg(lat: float, lon: float) -> int: 34 | ''' 35 | lat, lon or y, x 36 | return EPSG in meter for a given (lat,lon) 37 | lat is north south 38 | lon is est west 39 | ''' 40 | return int(32700 - round((45 + lat) / 90, 0) * 100 + round((183 + lon) / 6, 0)) -------------------------------------------------------------------------------- /syspy/io/pandasdbf/exceltodbf_qc.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | 3 | import xlrd 4 | from syspy.io.pandasdbf import dbf_qc as dbf 5 | 6 | _encoding = 'cp850' 7 | 8 | 9 | def convert_value(value, encoding=_encoding): 10 | if isinstance(value, str): 11 | return value.encode(_encoding, 'replace') 12 | elif isinstance(value, float) and value % 1 == 0: 13 | return int(value) 14 | else: 15 | return value 16 | 17 | 18 | class exceltodbf: 19 | def __init__(self, infile, outfile, encoding=_encoding): 20 | import tkinter as Tkinter 21 | self.infile = infile 22 | self.wb = xlrd.open_workbook(infile) 23 | self.sheet_names = self.wb.sheet_names() 24 | self.mainWin = Tkinter.Tk() 25 | self.selectedSheet = Tkinter.StringVar(self.mainWin) 26 | self.selectedSheet.set(self.sheet_names[0]) 27 | self.encoding = encoding 28 | self.convert(outfile) 29 | 30 | def convert(self, outfile, event=None): 31 | if os.path.isfile(outfile): 32 | os.remove(outfile) 33 | 34 | sheet = self.wb.sheet_by_name(self.selectedSheet.get()) 35 | fieldnames = [str(sheet.cell_value(0, col)) for col in range(sheet.ncols)] 36 | data = [[convert_value(sheet.cell_value(row, col), self.encoding) for col in range(sheet.ncols)] for row in range(1, sheet.nrows)] 37 | dbf.dbfwriter(outfile, fieldnames, data) 38 | self.exit() 39 | 40 | def exit(self): 41 | self.mainWin.destroy() 42 | -------------------------------------------------------------------------------- /quetzal/engine/screenlines.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from syspy.spatial import spatial 3 | from syspy.spatial.geometries import b_crosses_a_to_the_left 4 | 5 | 6 | def direct(row): 7 | direct = b_crosses_a_to_the_left( 8 | row['geometry_screen'], 9 | row['geometry_link'] 10 | ) 11 | return direct 12 | 13 | 14 | def intersection_flows(screens, links, flow_column, **nearest_geometry_kwargs): 15 | screens = screens[['geometry']].copy() 16 | links = links[['geometry', flow_column]].copy() 17 | 18 | cross = spatial.nearest_geometry(screens, links, **nearest_geometry_kwargs) 19 | cross = cross[cross['actual_distance'] == 0].copy() 20 | 21 | cross = pd.merge(cross, screens, left_on='ix_one', right_index=True) 22 | cross = pd.merge(cross, links, left_on='ix_many', 23 | right_index=True, suffixes=['_screen', '_link']) 24 | 25 | cross['direct'] = cross.apply(direct, axis=1) 26 | cross = cross.loc[cross['direct'] is True] 27 | cross.rename(columns={'ix_one': 'screen', 'ix_many': 'link'}, inplace=True) 28 | return cross[['screen', 'link', flow_column]] 29 | 30 | 31 | def intersection_flow(screens, links, flow_column, **kwargs): 32 | flows = intersection_flows(screens, links, flow_column, **kwargs) 33 | flow = pd.merge( 34 | flows.groupby('screen')[[flow_column]].sum(), 35 | screens[[flow_column]], 36 | left_index=True, 37 | right_index=True, 38 | suffixes=['_link', '_screen'] 39 | ) 40 | flow['screen'] = flow.index 41 | return flow 42 | -------------------------------------------------------------------------------- /api/ML_MatrixRoadCaster/update-lambda.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | declare AWS_ECR_REPO_NAME=quetzal-matrixroadcaster-api 5 | declare AWS_LAMBDA_FUNCTION_NAME=quetzal-matrixroadcaster-api 6 | declare FOLDER_NAME=ML_MatrixRoadCaster 7 | declare QUETZAL_ROOT=../.. 8 | 9 | 10 | # Prompt user for a tag 11 | last_tag=$(aws ecr describe-images --repository-name $AWS_ECR_REPO_NAME \ 12 | --query 'sort_by(imageDetails,& imagePushedAt)[-1].imageTags[0]') 13 | 14 | echo "Enter a docker TAG (last: $last_tag)": 15 | read TAG 16 | 17 | cd $QUETZAL_ROOT 18 | # Build docker image 19 | docker build -f api/$FOLDER_NAME/Dockerfile -t $AWS_ECR_REPO_NAME:$TAG . 20 | 21 | # Connect to AWS ECR 22 | aws_account=$(aws sts get-caller-identity | jq '.Account' | sed 's/"//g') 23 | aws_region=$(aws configure get region) 24 | 25 | aws ecr get-login-password --region $aws_region | docker login --username AWS --password-stdin \ 26 | $aws_account.dkr.ecr.$aws_region.amazonaws.com 27 | 28 | #Tag docker 29 | docker tag $AWS_ECR_REPO_NAME:$TAG $aws_account.dkr.ecr.$aws_region.amazonaws.com/$AWS_ECR_REPO_NAME:$TAG 30 | 31 | #Push docker to aws 32 | docker push $aws_account.dkr.ecr.$aws_region.amazonaws.com/$AWS_ECR_REPO_NAME:$TAG 33 | 34 | #update Lambda 35 | aws lambda update-function-code --region $aws_region --function-name $AWS_LAMBDA_FUNCTION_NAME \ 36 | --image-uri $aws_account.dkr.ecr.$aws_region.amazonaws.com/$AWS_LAMBDA_FUNCTION_NAME:$TAG > /dev/null 37 | 38 | echo "updating lambda function ..." 39 | 40 | aws lambda wait function-updated --region $aws_region --function-name $AWS_LAMBDA_FUNCTION_NAME 41 | 42 | echo "success" -------------------------------------------------------------------------------- /api/ML_MatrixRoadCaster/update-lambda-dev.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | declare AWS_ECR_REPO_NAME=quetzal-matrixroadcaster-api-dev 5 | declare AWS_LAMBDA_FUNCTION_NAME=quetzal-matrixroadcaster-api-dev 6 | declare FOLDER_NAME=ML_MatrixRoadCaster 7 | declare QUETZAL_ROOT=../.. 8 | 9 | 10 | # Prompt user for a tag 11 | last_tag=$(aws ecr describe-images --repository-name $AWS_ECR_REPO_NAME \ 12 | --query 'sort_by(imageDetails,& imagePushedAt)[-1].imageTags[0]') 13 | 14 | echo "Enter a docker TAG (last: $last_tag)": 15 | read TAG 16 | 17 | cd $QUETZAL_ROOT 18 | # Build docker image 19 | docker build -f api/$FOLDER_NAME/Dockerfile -t $AWS_ECR_REPO_NAME:$TAG . 20 | 21 | # Connect to AWS ECR 22 | aws_account=$(aws sts get-caller-identity | jq '.Account' | sed 's/"//g') 23 | aws_region=$(aws configure get region) 24 | 25 | aws ecr get-login-password --region $aws_region | docker login --username AWS --password-stdin \ 26 | $aws_account.dkr.ecr.$aws_region.amazonaws.com 27 | 28 | #Tag docker 29 | docker tag $AWS_ECR_REPO_NAME:$TAG $aws_account.dkr.ecr.$aws_region.amazonaws.com/$AWS_ECR_REPO_NAME:$TAG 30 | 31 | #Push docker to aws 32 | docker push $aws_account.dkr.ecr.$aws_region.amazonaws.com/$AWS_ECR_REPO_NAME:$TAG 33 | 34 | #update Lambda 35 | aws lambda update-function-code --region $aws_region --function-name $AWS_LAMBDA_FUNCTION_NAME \ 36 | --image-uri $aws_account.dkr.ecr.$aws_region.amazonaws.com/$AWS_LAMBDA_FUNCTION_NAME:$TAG > /dev/null 37 | 38 | echo "updating lambda function ..." 39 | 40 | aws lambda wait function-updated --region $aws_region --function-name $AWS_LAMBDA_FUNCTION_NAME 41 | 42 | echo "success" -------------------------------------------------------------------------------- /quetzal/engine/msa_trackers/test_tracker.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict, Union 2 | from quetzal.engine.msa_trackers.tracker import Tracker 3 | from collections import namedtuple 4 | 5 | # need to name the class the same as the namedTuple name for pickle. 6 | TrackedAssign = namedtuple('TrackedAssign', 'ab_volumes odv pred seg it') 7 | TrackedWeight = namedtuple('TrackedWeight', 'iteration phi beta relgap') 8 | 9 | 10 | class TestTracker(Tracker): 11 | def __init__(self, track_links_list: List[str] = []): 12 | self.track_links_list = track_links_list 13 | self.weights = [] 14 | self.tracked_mat: List[TrackedAssign] = [] 15 | 16 | def init( 17 | self, 18 | links_sparse_index: Union[List[int], List[tuple[int, int]]], 19 | links_to_sparse: Union[Dict[str, int], Dict[str, tuple[int, int]]], 20 | ): 21 | self.links_sparse_index = links_sparse_index 22 | self.links_to_sparse = links_to_sparse 23 | self.sparse_links_list = [*map(links_to_sparse.get, self.track_links_list)] 24 | self.sparse_to_links = {v: k for k, v in links_to_sparse.items()} 25 | 26 | def __call__(self) -> bool: # when calling the instance. check if we track links or no. 27 | return True 28 | 29 | def assign(self, ab_volumes, odv, pred, seg, it): 30 | # just save everything. 31 | self.tracked_mat.append(TrackedAssign(ab_volumes, odv, pred, seg, it)) 32 | 33 | def add_weights(self, phi, beta, relgap, it): 34 | self.weights.append(TrackedWeight(iteration=it, phi=phi, beta=beta, relgap=relgap)) 35 | 36 | def merge(self): 37 | pass 38 | -------------------------------------------------------------------------------- /quetzal/engine/park_and_ride_pathfinder.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from quetzal.engine import engine 4 | from quetzal.engine.pathfinder_utils import path_and_duration_from_graph 5 | 6 | 7 | class ParkRidePathFinder: 8 | def __init__(self, model, walk_on_road=False): 9 | self.zones = model.zones.copy() 10 | self.links = engine.graph_links(model.links.copy()) 11 | self.road_links = model.road_links 12 | self.pr_nodes = set(model.nodes.loc[model.nodes['parking_spots'].astype(bool)].index) 13 | self.road_to_transit = model.road_to_transit.loc[ 14 | model.road_to_transit['b'].isin(self.pr_nodes)] 15 | self.zone_to_road = model.zone_to_road.loc[ 16 | model.zone_to_road['direction'] == 'access'] 17 | self.transit_to_zone = model.zone_to_transit.loc[ 18 | model.zone_to_transit['direction'] != 'access'] 19 | self.footpaths = model.footpaths 20 | 21 | def build_graph(self, **kwargs): 22 | self.nx_graph = engine.multimodal_graph( 23 | self.links, 24 | ntlegs=pd.concat([self.zone_to_road, self.transit_to_zone]), 25 | footpaths=pd.concat([self.footpaths, self.road_to_transit, self.road_links]), 26 | pole_set=set(self.zones.index), 27 | **kwargs 28 | ) 29 | 30 | def find_best_path(self, cutoff=np.inf, od_set=None, **kwargs): 31 | self.build_graph(**kwargs) 32 | pr_los = path_and_duration_from_graph( 33 | self.nx_graph, 34 | pole_set=set(self.zones.index), 35 | cutoff=cutoff, 36 | od_set=od_set 37 | ) 38 | 39 | pr_los['pathfinder_session'] = 'park_and_ride' 40 | pr_los['path'] = [tuple(p) for p in pr_los['path']] 41 | self.paths = pr_los 42 | -------------------------------------------------------------------------------- /quetzal/launcher/launcher_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | from subprocess import PIPE, Popen 4 | 5 | import pandas as pd 6 | 7 | 8 | def parallel_call_notebook( 9 | notebook, 10 | arg_list, 11 | stdout_path='log/out.txt', 12 | stderr_path='log/err.txt', 13 | workers=4, 14 | sleep=1, 15 | leave=False, 16 | errout_suffix=False 17 | ): 18 | os.system('jupyter nbconvert --to python %s' % notebook) 19 | file = notebook.replace('.ipynb', '.py') 20 | popens = {} 21 | 22 | for i in range(len(arg_list)): 23 | arg = arg_list[i] 24 | suffix = arg if errout_suffix else '' 25 | suffix += '_' + notebook.split('.')[0] 26 | mode = 'w' if errout_suffix else 'a+' 27 | print(i, arg) 28 | with open(stdout_path.replace('.txt', '_' + suffix + '.txt'), mode) as stdout: 29 | with open(stderr_path.replace('.txt', '_' + suffix + '.txt'), mode) as stderr: 30 | popens[i] = Popen( 31 | ['python', file, arg], 32 | stdout=stdout, 33 | stderr=stderr 34 | ) 35 | if (i + 1) % workers == 0 or (i + 1) == len(arg_list): 36 | # print('waiting') 37 | popens[i].wait() 38 | time.sleep(sleep) 39 | if not leave: 40 | os.remove(file) 41 | for i in range(len(arg_list)): 42 | arg = arg_list[i] 43 | suffix = arg if errout_suffix else '' 44 | suffix += '_' + notebook.split('.')[0] 45 | mode = 'r' 46 | with open(stderr_path.replace('.txt', '_' + suffix + '.txt'), mode) as stderr: 47 | content = stderr.read() 48 | if 'Error' in content and "end_of_notebook" not in content: 49 | print("subprocess **{} {}** terminated with an error.".format(i, arg)) 50 | -------------------------------------------------------------------------------- /tests/old_test_engine_od_volume_from_zones.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from unittest import TestCase, skipIf 3 | from unittest.mock import ANY, patch 4 | 5 | import numpy as np 6 | import pandas as pd 7 | from quetzal.engine.engine import od_volume_from_zones 8 | 9 | sys.path.append(r'../syspy') 10 | 11 | 12 | origin_power = np.power 13 | 14 | 15 | @patch('numpy.power') 16 | @patch('syspy.distribution.distribution.CalcDoublyConstrained', autospec=True) 17 | @patch('syspy.skims.skims.euclidean', autospec=True) 18 | @skipIf(True, 'want to skip') 19 | class Test(TestCase): 20 | def test_zones_only_intrazonal(self, skims_euclidean, distribution_CalcDoublyConstrained, spy_power): 21 | spy_power.side_effect = origin_power 22 | values = [[1, 2, 3], [1, 2, 4]] 23 | zones = pd.DataFrame(values, columns=['emission', 'attraction', 'geometry']) 24 | values = [[0.0, 0.0, 0.0], [1.0, 0.0, 157249.38127194397], [0.0, 1.0, 157249.38127194397], [1.0, 1.0, 0.0]] 25 | euclidean_df = pd.DataFrame(values, columns=['origin', 'destination', 'euclidean_distance']) 26 | skims_euclidean.return_value = euclidean_df 27 | 28 | values = [[0.9, 0.1], [0.1, 0.9]] 29 | volume_array = np.array(values) 30 | distribution_CalcDoublyConstrained.return_value = volume_array 31 | 32 | result = od_volume_from_zones(zones) 33 | 34 | expected = pd.DataFrame( 35 | [[0, 0, 0.9], [0, 1, 0.1], [1, 0, 0.1], [1, 1, 0.9]], columns=['origin', 'destination', 'volume'] 36 | ) 37 | 38 | pd.testing.assert_frame_equal(result, expected) 39 | skims_euclidean.assert_called_once_with(zones, intrazonal=False) 40 | distribution_CalcDoublyConstrained.assert_called_once_with( 41 | zones['emission'].values, zones['attraction'].values, ANY 42 | ) 43 | spy_power.assert_called_once_with(ANY, -2) 44 | -------------------------------------------------------------------------------- /syspy/syspy_utils/documentation_jupyter.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | 3 | import itertools 4 | import json 5 | import os 6 | 7 | 8 | def list_files(path, patterns): 9 | file_list = [os.path.join(path, file) for file in os.listdir(path) if file.split('.')[-1].lower() in patterns] 10 | subdirectories = [os.path.join(path, dir) for dir in os.listdir(path) if os.path.isdir(os.path.join(path, dir))] 11 | file_list += list(itertools.chain(*[list_files(subdirectory, patterns) for subdirectory in subdirectories])) 12 | return file_list 13 | 14 | 15 | def makedoc(folder=os.getcwd(), doc_file=os.getcwd() + r'/doc.ipynb', old=None): 16 | """ 17 | creates a .ipynb that gather all the documentation written in the firt cells of the notebooks of a given folder 18 | 19 | :param folder: the folder that contains the notebooks 20 | :type input_matrix: str 21 | :param doc_file: the file where the markdown cell of documentation will be included in 2nd position 22 | :type doc_file: str 23 | :param old: the classical folder name for old scripts that we do not want to include in the doc. 24 | :type old: str or None 25 | 26 | :return: None 27 | """ 28 | files = [f.replace(folder, '') for f in list_files(folder, ['ipynb']) if 'checkpoint' not in f] 29 | text = '' 30 | 31 | for file in files: 32 | if old is None or old not in file: 33 | with open(folder + file, 'r', encoding='utf-8') as n: 34 | j = json.loads(n.read()) 35 | 36 | text += '#### ' + file.replace('.ipynb', '') + '\n' 37 | try: 38 | if j['cells'][0]['cell_type'] == 'markdown': 39 | text += ''.join(j['cells'][0]['source']) 40 | text += '\n' 41 | else: 42 | text += '\n' 43 | except IndexError: 44 | print(j, file) 45 | 46 | with open(doc_file, 'r', encoding='utf-8') as d: 47 | jd = json.loads(d.read()) 48 | jd['cells'][1]['source'] = text 49 | 50 | with open(doc_file, 'w', encoding='utf-8') as d: 51 | d.write(json.dumps(jd)) 52 | -------------------------------------------------------------------------------- /tests/data/jsons/nodes.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { "type": "Feature", "properties": { "index": "FUR_CREEK_RES", "stop_name": "Furnace Creek Resort (Demo)", "stop_lat": 36.425288, "stop_lon": -117.133162 }, "geometry": { "type": "Point", "coordinates": [ -117.133162, 36.425288 ] } }, 5 | { "type": "Feature", "properties": { "index": "BEATTY_AIRPORT", "stop_name": "Nye County Airport (Demo)", "stop_lat": 36.868446, "stop_lon": -116.784582 }, "geometry": { "type": "Point", "coordinates": [ -116.784582, 36.868446 ] } }, 6 | { "type": "Feature", "properties": { "index": "BULLFROG", "stop_name": "Bullfrog (Demo)", "stop_lat": 36.88108, "stop_lon": -116.81797 }, "geometry": { "type": "Point", "coordinates": [ -116.81797, 36.88108 ] } }, 7 | { "type": "Feature", "properties": { "index": "STAGECOACH", "stop_name": "Stagecoach Hotel & Casino (Demo)", "stop_lat": 36.915682, "stop_lon": -116.751677 }, "geometry": { "type": "Point", "coordinates": [ -116.751677, 36.915682 ] } }, 8 | { "type": "Feature", "properties": { "index": "NADAV", "stop_name": "North Ave \/ D Ave N (Demo)", "stop_lat": 36.914893, "stop_lon": -116.76821 }, "geometry": { "type": "Point", "coordinates": [ -116.76821, 36.914893 ] } }, 9 | { "type": "Feature", "properties": { "index": "NANAA", "stop_name": "North Ave \/ N A Ave (Demo)", "stop_lat": 36.914944, "stop_lon": -116.761472 }, "geometry": { "type": "Point", "coordinates": [ -116.761472, 36.914944 ] } }, 10 | { "type": "Feature", "properties": { "index": "DADAN", "stop_name": "Doing Ave \/ D Ave N (Demo)", "stop_lat": 36.909489, "stop_lon": -116.768242 }, "geometry": { "type": "Point", "coordinates": [ -116.768242, 36.909489 ] } }, 11 | { "type": "Feature", "properties": { "index": "EMSI", "stop_name": "E Main St \/ S Irving St (Demo)", "stop_lat": 36.905697, "stop_lon": -116.76218 }, "geometry": { "type": "Point", "coordinates": [ -116.76218, 36.905697 ] } }, 12 | { "type": "Feature", "properties": { "index": "AMV", "stop_name": "Amargosa Valley (Demo)", "stop_lat": 36.641496, "stop_lon": -116.40094 }, "geometry": { "type": "Point", "coordinates": [ -116.40094, 36.641496 ] } } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /quetzal/analysis/cost_benefit_analysis.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | 5 | def od_weighted_time_delta(reference_od, scenario_od): 6 | columns = [ 7 | 'origin', 'destination', 'volume', 8 | 'volume_pt', 'volume_car', 'volume_walk', 9 | 'duration_car', 'duration_pt' 10 | ] 11 | 12 | ref = reference_od[columns].set_index(['origin', 'destination']) 13 | scen = scenario_od[columns].set_index(['origin', 'destination']) 14 | 15 | constant_pt = np.minimum(ref['volume_pt'], scen['volume_pt']) 16 | constant_car = np.minimum(ref['volume_car'], scen['volume_car']) 17 | 18 | duration_car_to_pt = scen['duration_pt'] - ref['duration_car'] 19 | duration_pt_to_car = scen['duration_car'] - ref['duration_pt'] 20 | volume_car_to_pt = np.maximum(ref['volume_car'] - scen['volume_car'], 0) 21 | volume_pt_to_car = np.maximum(scen['volume_car'] - ref['volume_car'], 0) 22 | 23 | delta = scen - ref 24 | 25 | weighted_time_delta = pd.DataFrame( 26 | { 27 | 'time_constant_pt': constant_pt * delta['duration_pt'], 28 | 'time_constant_car': constant_car * delta['duration_car'], 29 | 'time_car_to_pt': volume_car_to_pt * duration_car_to_pt, 30 | 'time_pt_to_car': volume_pt_to_car * duration_pt_to_car, 31 | 'volume_pt_to_car': volume_pt_to_car, 32 | 'volume_car_to_pt': volume_car_to_pt, 33 | 'duration_pt_to_car': duration_pt_to_car, 34 | 'duration_car_to_pt': duration_car_to_pt, 35 | 'volume_constant_pt': constant_pt, 36 | 'volume_constant_car': constant_car, 37 | 'duration_car': delta['duration_car'], 38 | 'duration_pt': delta['duration_pt'] 39 | } 40 | ) 41 | ordered_columns = [ 42 | 'volume_constant_pt', 'duration_pt', 'time_constant_pt', 43 | 'volume_constant_car', 'duration_car', 'time_constant_car', 44 | 'volume_car_to_pt', 'duration_car_to_pt', 'time_car_to_pt', 45 | 'volume_pt_to_car', 'duration_pt_to_car', 'time_pt_to_car' 46 | ] 47 | return weighted_time_delta[ordered_columns] 48 | -------------------------------------------------------------------------------- /syspy/operations/rollingstock_model.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | 4 | def distribute_load(load, total_capacity_aw2, seating_capacity): 5 | standing_capacity_aw2 = total_capacity_aw2 - seating_capacity 6 | seating = min(load, seating_capacity) 7 | standing = load - seating 8 | standing_density = standing / standing_capacity_aw2 * 4 9 | return pd.Series({'seating': seating, 'standing_density': standing_density}) 10 | 11 | 12 | def get_dwell_time(boardings, alightings, door_time, pax_flow_per_sec, min_dwell_time): 13 | pax_time = (boardings + alightings) / pax_flow_per_sec 14 | return max(pax_time + door_time, min_dwell_time) 15 | 16 | 17 | def compute_capacity(n_seats, aw2_capacity, target_density): 18 | """ 19 | Compute RS capacity for target density 20 | """ 21 | return (aw2_capacity - n_seats) * target_density / 4 + n_seats 22 | 23 | 24 | class RollingStockUnit(): 25 | def __init__( 26 | self, length, weight, max_speed, 27 | n_doors, door_width, door_time, pax_flow, 28 | seats, capacity 29 | ): 30 | self.length, self.weight, self.max_speed = length, weight, max_speed 31 | self.n_doors, self.door_width, self.door_time = n_doors, door_width, door_time 32 | self.pax_flow = pax_flow 33 | self.seats, self.capacity = seats, capacity 34 | 35 | def distribute_load(self, load): 36 | return distribute_load(load, self.capacity, self.seats) 37 | 38 | def get_dwell_time(self, boardings_per_headway, alightings_per_headway, min_dwell_time): 39 | flow = self.n_doors * self.door_width * self.pax_flow 40 | return get_dwell_time( 41 | boardings_per_headway, alightings_per_headway, 42 | self.door_time, flow, min_dwell_time 43 | ) 44 | 45 | def compute_capacity(self, target_density): 46 | return compute_capacity(self.seats, self.capacity, target_density) 47 | 48 | 49 | class RollingStock(RollingStockUnit): 50 | def __init__(self, RSUnit, n_units): 51 | super().__init__(**RSUnit.__dict__) 52 | self.n_units = n_units 53 | self.length *= n_units 54 | self.weight *= n_units 55 | self.n_doors *= n_units 56 | self.seats *= n_units 57 | self.capacity *= n_units 58 | -------------------------------------------------------------------------------- /tests/data/jsons/centroids.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { "type": "Feature", "properties": { "index": "zone_0", "emp": 1, "pop": 1, "emission": 1, "attraction": 1.0, "emission_rate": 0.5, "weight": 2.0 }, "geometry": { "type": "Point", "coordinates": [ -117.008219410085161, 36.520732061318995 ] } }, 5 | { "type": "Feature", "properties": { "index": "zone_1", "emp": 1, "pop": 1, "emission": 1, "attraction": 1.0, "emission_rate": 0.5, "weight": 2.0 }, "geometry": { "type": "Point", "coordinates": [ -116.502414125023435, 36.609377818527889 ] } }, 6 | { "type": "Feature", "properties": { "index": "zone_2", "emp": 1, "pop": 1, "emission": 1, "attraction": 1.0, "emission_rate": 0.5, "weight": 2.0 }, "geometry": { "type": "Point", "coordinates": [ -116.606318578467878, 36.900788120245544 ] } }, 7 | { "type": "Feature", "properties": { "index": "zone_3", "emp": 1, "pop": 1, "emission": 1, "attraction": 1.0, "emission_rate": 0.5, "weight": 2.0 }, "geometry": { "type": "Point", "coordinates": [ -116.991899369597547, 36.833465595595513 ] } }, 8 | { "type": "Feature", "properties": { "index": "zone_4", "emp": 1, "pop": 1, "emission": 1, "attraction": 1.0, "emission_rate": 0.5, "weight": 2.0 }, "geometry": { "type": "Point", "coordinates": [ -116.754424779437059, 36.694477962421857 ] } }, 9 | { "type": "Feature", "properties": { "index": "zone_5", "emp": 1, "pop": 1, "emission": 1, "attraction": 1.0, "emission_rate": 0.5, "weight": 2.0 }, "geometry": { "type": "Point", "coordinates": [ -116.782658429892734, 36.90350702201232 ] } }, 10 | { "type": "Feature", "properties": { "index": "zone_6", "emp": 1, "pop": 1, "emission": 1, "attraction": 1.0, "emission_rate": 0.5, "weight": 2.0 }, "geometry": { "type": "Point", "coordinates": [ -116.739823711156845, 36.878430187917687 ] } }, 11 | { "type": "Feature", "properties": { "index": "zone_7", "emp": 1, "pop": 1, "emission": 1, "attraction": 1.0, "emission_rate": 0.5, "weight": 2.0 }, "geometry": { "type": "Point", "coordinates": [ -116.761680016038881, 36.939212979303335 ] } }, 12 | { "type": "Feature", "properties": { "index": "zone_8", "emp": 1, "pop": 1, "emission": 1, "attraction": 1.0, "emission_rate": 0.5, "weight": 2.0 }, "geometry": { "type": "Point", "coordinates": [ -116.795984409301923, 36.947733090457625 ] } } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /syspy/surveys/array_example.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | import pandas as pd 5 | 6 | 7 | def build_json(): 8 | with open('orthogonal_arrays.txt') as file: 9 | text = file.read() 10 | chunks = text[1:].split('\n\n\n') 11 | 12 | arrays = [] 13 | 14 | for chunk in chunks: 15 | 16 | name = chunk.split('\n')[0] 17 | 18 | lines = chunk.split('\n')[1:] 19 | lines = [line.replace(' ', '') for line in lines if line] 20 | array = [[int(char) for char in line] for line in lines] 21 | 22 | exponents = name.split('n')[0] 23 | runs = int(name.split('n=')[-1]) 24 | 25 | array_dict = { 26 | 'array': json.dumps(array), 27 | 'runs': runs 28 | } 29 | exp_dict = {} 30 | 31 | for exp_group in exponents.split(' '): 32 | try: 33 | key, exp = exp_group.split('^') 34 | exp_dict[int(key)] = int(exp) 35 | except ValueError: # ValueError 36 | pass 37 | array_dict.update(exp_dict) 38 | array_dict['exponents'] = exp_dict 39 | arrays.append(array_dict) 40 | 41 | base = pd.DataFrame([pd.Series(array) for array in arrays]).fillna(0) 42 | int_columns = sorted([c for c in base.columns if type(c) is int]) 43 | string_columns = [c for c in base.columns if type(c) is str] 44 | base[int_columns] = base[int_columns].astype(int) 45 | 46 | base = base[string_columns + int_columns] 47 | 48 | base.sort_values(['runs'] + int_columns, inplace=True) 49 | base.reset_index(inplace=True, drop=True) 50 | base['len'] = base['array'].apply(lambda s: len(json.loads(s))) 51 | base['error'] = (base['len'] - base['runs']) 52 | 53 | with open('orthogonal_arrays.json', 'w') as file: 54 | file.write(base.to_json(orient='records')) 55 | 56 | 57 | def try_int(s): 58 | try: 59 | return int(s) 60 | except ValueError: 61 | return s 62 | 63 | 64 | def main(): 65 | dir_path = os.path.dirname(os.path.realpath(__file__)) 66 | global base 67 | with open(dir_path + r'/orthogonal_arrays.json', 'r') as file: 68 | base = pd.read_json(file.read()) 69 | 70 | base['exponents'] = base['exponents'].apply( 71 | lambda d: {int(k): v for k, v in d.items()} 72 | ) 73 | base.columns = [try_int(c) for c in base.columns] 74 | 75 | 76 | main() 77 | -------------------------------------------------------------------------------- /api/ML_MatrixRoadCaster/s3_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | from io import BytesIO, StringIO 3 | import json 4 | import numpy as np 5 | import pandas as pd 6 | import geopandas as gpd 7 | import boto3 8 | 9 | class NpEncoder(json.JSONEncoder): 10 | def default(self, obj): 11 | if isinstance(obj, np.integer): 12 | return int(obj) 13 | if isinstance(obj, np.floating): 14 | return float(obj) 15 | if isinstance(obj, np.ndarray): 16 | return obj.tolist() 17 | if isinstance(obj, np.nan): 18 | return None 19 | return super(NpEncoder, self).default(obj) 20 | 21 | 22 | class DataBase: 23 | def __init__(self): 24 | print('init db') 25 | self.BUCKET = os.environ['BUCKET_NAME'] 26 | self.s3_resource = boto3.resource('s3') 27 | self.s3 = boto3.client('s3') 28 | 29 | def read_geojson(self, uuid, name): 30 | path = uuid + '/' + name 31 | result = self.s3.get_object(Bucket=self.BUCKET, Key=path) 32 | dict = json.load(result["Body"]) 33 | return gpd.read_file(json.dumps(dict)) 34 | 35 | 36 | 37 | def read_csv(self, uuid, name): 38 | path = uuid + '/' + name 39 | obj = self.s3.get_object(Bucket=self.BUCKET, Key=path) 40 | return pd.read_csv(BytesIO(obj['Body'].read())) 41 | 42 | def save_csv(self, uuid, name, payload): 43 | ''' 44 | parameters 45 | ---------- 46 | payload: pandas df to send to s3 as csv. 47 | name: name of the file (with .csv at the end) 48 | returns 49 | ---------- 50 | ''' 51 | csv_buffer = StringIO() 52 | payload.to_csv(csv_buffer) 53 | 54 | filename = uuid + '/' + name 55 | self.s3_resource.Object(self.BUCKET, filename).put(Body=csv_buffer.getvalue()) 56 | 57 | def save_image(self, uuid, name, img_buffer): 58 | ''' 59 | parameters 60 | ---------- 61 | payload: pandas df to send to s3 as csv. 62 | name: name of the file (with .csv at the end) 63 | returns 64 | ---------- 65 | ''' 66 | img_buffer.seek(0) 67 | bucket = self.s3_resource.Bucket(self.BUCKET) 68 | filename = uuid + '/' + name 69 | bucket.put_object(Body=img_buffer, ContentType='image/png', Key=filename) 70 | 71 | -------------------------------------------------------------------------------- /quetzal/engine/optimal_strategy.py: -------------------------------------------------------------------------------- 1 | import bisect 2 | import heapq 3 | 4 | 5 | def find_optimal_strategy(edges, destination, inf=1e9): 6 | zero = 1 / inf 7 | 8 | # set of all nodes 9 | nodes = set.union(*[{i, j} for ix, i, j, f, c in edges]) 10 | 11 | # create index in order to access edges by j 12 | j_edges = {node: [] for node in nodes} 13 | for e in edges: 14 | ix, i, j, f, c = e 15 | j_edges[j].append(e) 16 | 17 | # initialization 18 | j = r = destination 19 | u = {r: 0} # node distance 20 | f = {node: zero for node in nodes} 21 | strategy = list() 22 | 23 | edge_data = {ix: (i, j, fa, ca) for ix, i, j, fa, ca in edges} 24 | heap = [(u[j] + ca, ix) for ix, i, j, fa, ca in j_edges[destination]] 25 | heapq.heapify(heap) 26 | seen = set() 27 | 28 | def get_next_link(): 29 | # get first tuple of (distance, ix) tuples 30 | # if ix has not been visited yet 31 | while True: 32 | try: 33 | ix = heapq.heappop(heap)[1] 34 | if ix not in seen: 35 | seen.add(ix) 36 | return ix 37 | except IndexError: 38 | return 39 | 40 | while(len(heap)): 41 | ix = get_next_link() 42 | if ix is None: 43 | break 44 | i, j, fa, ca = edge_data[ix] 45 | 46 | # Update node label 47 | if u.get(i, inf) >= u[j] + ca: 48 | u[i] = (f[i] * u.get(i, inf) + fa * (u[j] + ca)) / (f[i] + fa) 49 | f[i] = f[i] + fa 50 | strategy.append(ix) 51 | for ixa, i, j, fa, ca in j_edges[i]: 52 | heapq.heappush(heap, (u[j] + ca, ixa)) 53 | return strategy, u, f 54 | 55 | 56 | def assign_optimal_strategy(sources, edges, u, f): 57 | distance = { 58 | (ix, i, j, fa, ca): u[j] + ca 59 | for ix, i, j, fa, ca in edges 60 | } 61 | 62 | nodes = set.union(*[{i, j} for ix, i, j, f, c in edges]) 63 | 64 | node_v = {node: 0 for node in nodes} 65 | node_v.update(sources) 66 | edge_v = {} 67 | 68 | # do for every link a in A, in decreasing order of u[j] + ca 69 | relevant = list(distance.items()) 70 | relevant.sort(key=lambda x: x[1]) 71 | 72 | while len(relevant): 73 | ix, i, j, fa, ca = relevant.pop()[0] 74 | if node_v[i] > 0: 75 | edge_v[ix] = (fa / f[i]) * node_v[i] 76 | node_v[j] = node_v[j] + edge_v[ix] 77 | return node_v, edge_v 78 | -------------------------------------------------------------------------------- /syspy/syspy_utils/pandas_utils.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import pandas as pd 3 | 4 | 5 | def df_explode(df, column_to_explode): 6 | """ 7 | Take a column with iterable elements, and flatten the iterable to one element 8 | per observation in the output table. 9 | Slow and therefore not adapted to huge df. 10 | 11 | :param df: A dataframe to explod 12 | :type df: pandas.DataFrame 13 | :param column_to_explode: 14 | :type column_to_explode: str 15 | :return: An exploded data frame 16 | :rtype: pandas.DataFrame 17 | """ 18 | # Create a list of new observations 19 | new_observations = list() 20 | 21 | # Iterate through existing observations 22 | for row in df.to_dict(orient='records'): 23 | # Take out the exploding iterable 24 | explode_values = row[column_to_explode] 25 | del row[column_to_explode] 26 | # Create a new observation for every entry in the exploding iterable & add all of the other columns 27 | for explode_value in explode_values: 28 | # Deep copy existing observation 29 | new_observation = copy.deepcopy(row) 30 | # Add one (newly flattened) value from exploding iterable 31 | new_observation[column_to_explode] = explode_value 32 | # Add to the list of new observations 33 | new_observations.append(new_observation) 34 | # Create a DataFrame 35 | return_df = pd.DataFrame(new_observations) 36 | # Return 37 | return return_df 38 | 39 | 40 | def groupby_weighted_average(df, groupby, columns, weight): 41 | """ 42 | perform a weighted average on specified columns 43 | during a groupby operation 44 | 45 | :param df: A dataframe to group 46 | :type df: pandas.DataFrame 47 | :param groupby: column(s) to groupby 48 | :type groupby: str or list 49 | :param columns: column(s) to average 50 | :type columns: str or list 51 | :param weight: column to use as weight 52 | :type weight: str 53 | :return: A grouped dataframe with averaged columns 54 | :rtype: pandas.DataFrame 55 | """ 56 | if not isinstance(columns, list): 57 | columns = [columns] 58 | new_columns = [(c, weight) for c in columns] 59 | df[new_columns] = pd.concat([df[c] * df[weight] for c in columns], axis=1) 60 | grouped = df.groupby(groupby)[new_columns].sum().div(df.groupby(groupby)[weight].sum(), axis=0) 61 | grouped = grouped.rename(columns={(c, w): c for c, w in grouped.columns}) 62 | return grouped 63 | -------------------------------------------------------------------------------- /syspy/syspy_utils/mca_utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | 5 | def classification(values, classes, ascending=True, bins=None, round_bins=None): 6 | """ 7 | Return the array of classes of the values, for the given classes 8 | Inputs: 9 | values: np.array of values to classify 10 | classes: ordered list of classe names 11 | ascending: bool 12 | bins: boundaries of each classes. Automatically computed with equal width if None 13 | round_bins: integer to round the inner boundaries. Not rounded if None 14 | 15 | Outputs: 16 | tuple (np.array of the classes of the values, np.array of bins bounds) 17 | 18 | Example: 19 | 20 | x = np.array([1,2,10]) 21 | classes = [1,2,3] 22 | classification(x,classes) 23 | ---- 24 | (array([1, 1, 3]), array([ 1. , 4. , 7. , 10.1])) 25 | """ 26 | n_classes = len(classes) 27 | if bins is None: 28 | bins = n_classes 29 | 30 | # Create bins 31 | _, bins_bounds = np.histogram(values, bins=bins) 32 | # Force max value in interval 33 | bins_bounds[-1] = bins_bounds[-1] * 1.01 34 | 35 | # Round bins: all but first and last 36 | if round_bins is not None: 37 | temp = np.round(bins_bounds[1:-1], round_bins) 38 | temp = np.append(np.array([bins_bounds[0], bins_bounds[-1]]), temp) 39 | bins_bounds = np.sort(temp) 40 | 41 | # Get values index 42 | if ascending: 43 | index = np.digitize(values, bins_bounds) 44 | # print('index:', index) 45 | return np.array([classes[i - 1] for i in index]), bins_bounds 46 | else: 47 | index = np.digitize(values, bins_bounds) 48 | # print('index:', index) 49 | return np.array([classes[n_classes - i] for i in index]), bins_bounds 50 | 51 | 52 | def basic_scoring(x, classes=[1, 2, 3, 4, 5], methods={}): 53 | """ 54 | To apply to a dataframe to get a basic ascending scoring from 1 to 5 with equal intervals. 55 | """ 56 | classes, bounds = classification(x, classes) 57 | result_dict = {x.index[i]: classes[i] for i in range(len(classes))} 58 | result_dict.update({'bounds': bounds}) 59 | return pd.Series(result_dict) 60 | 61 | 62 | def background_colormap(val): 63 | """ 64 | Basic 1 to 5 background colormap for nice dataframe printing or excel export purposes. 65 | 66 | Example: 67 | df.style.applymap(background_colormap) 68 | """ 69 | color = ['#FB676D', '#FBA977', '#FEE987', '#B1D584', '#62C073'] 70 | return 'background-color: %s' % color[val - 1] 71 | -------------------------------------------------------------------------------- /quetzal/engine/vdf.py: -------------------------------------------------------------------------------- 1 | from numba import jit 2 | import numpy as np 3 | 4 | 5 | # vdf and vdfd (derivative) 6 | 7 | # Eval strings 8 | 9 | free_flow = 'time' 10 | 11 | default_bpr = 'time * (1 + {alpha} * (flow/capacity)**{beta})'.format(alpha=0.15, beta=4) 12 | 13 | # Python functions 14 | 15 | 16 | def limit_factory(expression: str, limit: float = None): 17 | # add a limit time*limit to an expression function. 18 | # if limit is None. use limit column. else: its a constant (df[time_col] * limit) 19 | def wrapped(df, flow_col, time_col): 20 | expr = expression.replace('flow', flow_col).replace('time', time_col) 21 | res = df.eval(expr) 22 | if limit == None: 23 | return res.clip(upper=df[time_col] * df['limit']) 24 | else: 25 | return res.clip(upper=df[time_col] * limit) 26 | 27 | return wrapped 28 | 29 | 30 | limited_bpr = limit_factory(default_bpr) 31 | 32 | 33 | # Numba functions 34 | 35 | 36 | @jit(nopython=True) 37 | def jit_limited_bpr(mat): 38 | # columns in mat : 'alpha','beta','limit','flow','time','penalty','capacity' 39 | # der return the first derivative (for the find beta...) 40 | jam_time = [] 41 | for i in range(mat.shape[0]): 42 | alpha = mat[i, 0] 43 | beta = mat[i, 1] 44 | limit = mat[i, 2] 45 | V = mat[i, 3] 46 | t0 = mat[i, 4] 47 | penalty = mat[i, 5] 48 | Q = mat[i, 6] 49 | res = t0 * (1 + alpha * np.power(V / Q, beta)) 50 | if res > t0 * limit: # we plateau the curve at limit. 51 | jam_time.append(t0 * limit + penalty) 52 | else: 53 | jam_time.append(res + penalty) 54 | return jam_time 55 | 56 | 57 | @jit(nopython=True) 58 | def jit_default_bpr(mat): 59 | # columns in mat : 'alpha','beta','limit','flow','time','penalty','capacity' 60 | # der return the first derivative (for the find beta...) 61 | jam_time = [] 62 | for i in range(mat.shape[0]): 63 | alpha = mat[i, 0] 64 | beta = mat[i, 1] 65 | V = mat[i, 3] 66 | t0 = mat[i, 4] 67 | penalty = mat[i, 5] 68 | Q = mat[i, 6] 69 | V0 = mat[i, 7] 70 | V += V0 71 | res = t0 * (1 + alpha * np.power(V / Q, beta)) 72 | jam_time.append(res + penalty) 73 | return jam_time 74 | 75 | 76 | @jit(nopython=True) 77 | def jit_free_flow(mat): 78 | # columns in mat : 'alpha','beta','limit','flow','time','penalty','capacity' 79 | # der return the derivative (for the find beta...) 80 | t0 = mat[:, 4] 81 | penalty = mat[:, 5] 82 | return t0 + penalty 83 | 84 | # columns in mat : 'alpha','beta','limit','flow','time','penalty','capacity' 85 | # der return the derivative (for the find beta...) 86 | t0 = mat[:, 4] 87 | return t0 * 0 88 | -------------------------------------------------------------------------------- /tests/data/jsons/checkpoint_nodes.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { "type": "Feature", "properties": { "index": "FUR_CREEK_RES", "stop_name": "Furnace Creek Resort (Demo)", "stop_desc": 0.0, "stop_lat": 36.425288, "stop_lon": -117.133162, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 1.846307147203984 }, "geometry": { "type": "Point", "coordinates": [ -117.133162, 36.425288 ] } }, 5 | { "type": "Feature", "properties": { "index": "BEATTY_AIRPORT", "stop_name": "Nye County Airport (Demo)", "stop_desc": 0.0, "stop_lat": 36.868446, "stop_lon": -116.784582, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.7469955008400182 }, "geometry": { "type": "Point", "coordinates": [ -116.784582, 36.868446 ] } }, 6 | { "type": "Feature", "properties": { "index": "BULLFROG", "stop_name": "Bullfrog (Demo)", "stop_desc": 0.0, "stop_lat": 36.88108, "stop_lon": -116.81797, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 2.1976134094415394 }, "geometry": { "type": "Point", "coordinates": [ -116.81797, 36.88108 ] } }, 7 | { "type": "Feature", "properties": { "index": "STAGECOACH", "stop_name": "Stagecoach Hotel & Casino (Demo)", "stop_desc": 0.0, "stop_lat": 36.915682, "stop_lon": -116.751677, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.15367788940941798 }, "geometry": { "type": "Point", "coordinates": [ -116.751677, 36.915682 ] } }, 8 | { "type": "Feature", "properties": { "index": "NADAV", "stop_name": "North Ave \/ D Ave N (Demo)", "stop_desc": 0.0, "stop_lat": 36.914893, "stop_lon": -116.76821, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.76821, 36.914893 ] } }, 9 | { "type": "Feature", "properties": { "index": "NANAA", "stop_name": "North Ave \/ N A Ave (Demo)", "stop_desc": 0.0, "stop_lat": 36.914944, "stop_lon": -116.761472, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.761472, 36.914944 ] } }, 10 | { "type": "Feature", "properties": { "index": "DADAN", "stop_name": "Doing Ave \/ D Ave N (Demo)", "stop_desc": 0.0, "stop_lat": 36.909489, "stop_lon": -116.768242, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.768242, 36.909489 ] } }, 11 | { "type": "Feature", "properties": { "index": "EMSI", "stop_name": "E Main St \/ S Irving St (Demo)", "stop_desc": 0.0, "stop_lat": 36.905697, "stop_lon": -116.76218, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.76218, 36.905697 ] } }, 12 | { "type": "Feature", "properties": { "index": "AMV", "stop_name": "Amargosa Valley (Demo)", "stop_desc": 0.0, "stop_lat": 36.641496, "stop_lon": -116.40094, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.40094, 36.641496 ] } } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /syspy/syspy_utils/gtfs_utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | This modules provides tools for manipulating gtfs files 3 | 4 | example:: 5 | 6 | """ 7 | 8 | __author__ = 'mjoly' 9 | 10 | import json 11 | 12 | import pandas as pd 13 | 14 | 15 | def get_patterns(gtfs_dir, direction=True, by_route=True): 16 | stop_times = pd.read_csv(gtfs_dir + 'stop_times.txt') 17 | trips = pd.read_csv(gtfs_dir + 'trips.txt').set_index('trip_id') 18 | 19 | trips_to_patterns = stop_times[['trip_id', 'stop_id']].groupby('trip_id').aggregate(lambda x: (tuple(x))) 20 | trips_to_patterns.rename(columns={'stop_id': 'geo_pattern_links'}, inplace=True) 21 | 22 | trips_to_patterns['reversed_geo_pattern_links'] = trips_to_patterns.apply(lambda r: tuple(reversed(r['geo_pattern_links'])), axis=1) 23 | trips_to_patterns['route_id'] = trips['route_id'] 24 | 25 | def pattern_choice(r): 26 | if r['geo_pattern_links'] < r['reversed_geo_pattern_links']: 27 | return r['geo_pattern_links'] 28 | else: 29 | return r['reversed_geo_pattern_links'] 30 | 31 | if not direction: 32 | trips_to_patterns['chosen_geo_pattern_links'] = trips_to_patterns.apply(lambda r: pattern_choice(r), axis=1) 33 | trips_to_patterns['direction'] = 0 34 | else: 35 | trips_to_patterns['chosen_geo_pattern_links'] = trips_to_patterns['geo_pattern_links'] 36 | trips_to_patterns['direction'] = trips_to_patterns.apply(lambda r: 1 + 1 * (r['geo_pattern_links'] < r['reversed_geo_pattern_links']), axis=1) 37 | trips_direction = trips_to_patterns.copy() 38 | 39 | if by_route: 40 | patterns = trips_to_patterns.groupby(['chosen_geo_pattern_links', 'route_id', 'direction']).count().reset_index() 41 | patterns = patterns[['chosen_geo_pattern_links', 'direction', 'route_id']] 42 | patterns.reset_index(inplace=True) 43 | patterns.rename(columns={'index': 'pattern_id'}, inplace=True) 44 | trips_to_patterns = trips_to_patterns.reset_index().merge(patterns, on=['chosen_geo_pattern_links', 'direction', 'route_id'])[['pattern_id', 'trip_id']] 45 | else: 46 | patterns = trips_to_patterns.groupby(['chosen_geo_pattern_links', 'direction']).count().reset_index() 47 | patterns = patterns[['chosen_geo_pattern_links', 'direction']] 48 | patterns.reset_index(inplace=True) 49 | patterns.rename(columns={'index': 'pattern_id'}, inplace=True) 50 | trips_to_patterns = trips_to_patterns.reset_index().merge(patterns, on=['chosen_geo_pattern_links', 'direction'])[['pattern_id', 'trip_id']] 51 | 52 | trips_to_patterns.set_index('trip_id', inplace=True) 53 | patterns.rename(columns={'chosen_geo_pattern_links': 'geo_pattern_links'}, inplace=True) 54 | patterns.set_index('pattern_id', inplace=True) 55 | return trips_to_patterns, patterns, trips_direction 56 | -------------------------------------------------------------------------------- /quetzal/model/docmodel.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | 3 | 4 | def io_from_doc(doc): 5 | try: 6 | if 'deprecated!' in doc: 7 | return [], [] 8 | except TypeError: # argument of type 'NoneType' is not iterable 9 | return [], [] 10 | 11 | doc = doc.replace(' ', ' ') # espace insécable 12 | 13 | try: 14 | requirements = doc.split('* requires: ')[1].split('\n')[0] 15 | requirements = [r.strip() for r in requirements.split(',')] 16 | except IndexError: 17 | requirements = [] 18 | try: 19 | products = doc.split('* builds: ')[1].split('\n')[0] 20 | products = [r.strip() for r in products.split(',')] 21 | except IndexError: 22 | products = [] 23 | return requirements, products 24 | 25 | 26 | def contain_pattern(s, patterns): 27 | for p in patterns: 28 | if p in s: 29 | return True 30 | return False 31 | 32 | 33 | class DocModel: 34 | def __init__(self): 35 | pass 36 | 37 | def io_from_method(self, name): 38 | method = self.__getattribute__(name) 39 | doc = method.__doc__ 40 | return io_from_doc(doc) 41 | 42 | def edges_from_method(self, name): 43 | inputs, outputs = self.io_from_method(name) 44 | return [(i, name) for i in inputs] + [(name, o) for o in outputs] 45 | 46 | def dot(self, patterns, header=None): 47 | 48 | header = """ 49 | ratio = fill; 50 | node [style=filled, fontname = "calibri", fontsize=24, color="#C8D2B3"]; 51 | edge[ fontname = "calibri", fontsize=24]; 52 | ranksep = "0.5"; 53 | rankdir="HR"; 54 | """ if header is None else header 55 | 56 | methods = [m for m in dir(self) if contain_pattern(m, patterns)] 57 | edges = [] 58 | for method in methods: 59 | edges += self.edges_from_method(method) 60 | 61 | g = nx.DiGraph() 62 | g.add_edges_from(edges) 63 | 64 | # colors 65 | color = "#AACDDA" 66 | input_color = "#EEC880" 67 | output_color = "#C8D2B3" 68 | 69 | reversed_g = g.reverse() 70 | 71 | for node in list(g.nodes): 72 | if not bool(list(g.predecessors(node))): 73 | g.nodes[node]['color'] = input_color 74 | elif not bool(list(reversed_g.predecessors(node))): 75 | g.nodes[node]['color'] = output_color 76 | else: 77 | g.nodes[node]['color'] = color 78 | 79 | for method in methods: 80 | try: 81 | g.nodes[method]['color'] = '#E89196' 82 | g.nodes[method]['shape'] = 'rectangle' 83 | except KeyError: 84 | pass 85 | 86 | dot = nx.nx_pydot.to_pydot(g) 87 | 88 | return dot.to_string().replace('{', '{' + header) 89 | -------------------------------------------------------------------------------- /syspy/routing/timetable/csa.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | 3 | from IPython.display import display 4 | from IPython.html.widgets import FloatProgress 5 | from syspy.syspy_utils import syscolors 6 | 7 | 8 | def csa(_links, start, infinity=999999, connection_time=False, origins=False): 9 | links = _links.copy() 10 | origin_set = set(links['origin']).intersection(set(origins)) if origins else set(links['origin']) 11 | stop_set = set(links['origin']).union(set(links['destination'])) 12 | 13 | progress = FloatProgress(min=0, max=len(origin_set), width=975, 14 | height=10, color=syscolors.rainbow_shades[1], margin=5) 15 | progress.value = 1 16 | display(progress) 17 | 18 | links['reachable'] = False 19 | csa_connections = links.to_dict(orient='records') 20 | 21 | earliest_arrival_time_dict = {} 22 | earliest_arrival_link_dict = {} 23 | reachable_connections_dict = {} 24 | reachable_trips_dict = {} 25 | 26 | connection_time = connection_time if connection_time else {s: 0 for s in stop_set} 27 | 28 | print(len(origin_set)) 29 | for origin in list(origin_set): 30 | progress.value += 1 31 | 32 | reachable_connections = {l: 0 for l in list(links['index'])} 33 | reachable_trips = {t: 0 for t in list(links['trip_id'])} 34 | 35 | earliest_arrival_time = {s: infinity for s in stop_set} 36 | earliest_arrival_time[origin] = start 37 | earliest_arrival_link = {} 38 | 39 | def is_reachable(label): 40 | r = reachable_trips[label['trip_id']] or \ 41 | earliest_arrival_time[label['origin']] + connection_time[label['destination']] \ 42 | <= label['departure_time'] 43 | return r 44 | 45 | def scan(label): 46 | reachable = is_reachable(label) 47 | reachable_trips[label['trip_id']], reachable_connections[label['index']] = reachable, reachable 48 | 49 | if reachable: 50 | if earliest_arrival_time[label['destination']] > label['arrival_time']: 51 | earliest_arrival_time[label['destination']] = label['arrival_time'] 52 | earliest_arrival_link[label['destination']] = label['index'] 53 | 54 | for connection in csa_connections: 55 | scan(connection) 56 | 57 | earliest_arrival_time_dict[origin] = earliest_arrival_time 58 | earliest_arrival_link_dict[origin] = earliest_arrival_link 59 | reachable_connections_dict[origin] = reachable_connections 60 | reachable_trips_dict[origin] = reachable_trips 61 | 62 | return{'earliest_arrival_time_dict': earliest_arrival_time_dict, 63 | 'earliest_arrival_link_dict': earliest_arrival_link_dict, 64 | 'reachable_connections_dict': reachable_connections_dict, 65 | 'reachable_trips_dict': reachable_trips} 66 | -------------------------------------------------------------------------------- /syspy/transitfeed/feed_links.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | 3 | import pandas as pd 4 | 5 | 6 | def link_from_stop_times( 7 | stop_times, 8 | max_shortcut=False, 9 | stop_id='stop_id', 10 | trip_id='trip_id', 11 | in_sequence='stop_sequence', 12 | out_sequence='link_sequence', 13 | stop_id_origin=False, 14 | stop_id_destination=False, 15 | keep_origin_columns=[], 16 | keep_destination_columns=[] 17 | ): 18 | """ 19 | From a set of trips, represented as a table of events (stop time for 20 | example), returns a table of links between these events, given two trips: 21 | a-b-c-d and f-g-h. we should return : ab, bc, cd, fg and gh. 22 | 23 | :param stop_times: DataFrame 24 | :param max_shortcut: 25 | :param stop_id: 26 | :param in_sequence: 27 | :param out_sequence: 28 | :param stop_id_origin: 29 | :param stop_id_destination: 30 | :param keep_origin_columns: 31 | :param keep_destination_columns: 32 | :return: 33 | """ 34 | origins = stop_times[[stop_id, trip_id, 35 | in_sequence] + keep_origin_columns].copy() 36 | destinations = stop_times[[stop_id, trip_id, 37 | in_sequence] + keep_destination_columns].copy() 38 | links = [] 39 | 40 | max_sequence = stop_times[in_sequence].max() 41 | assert max_sequence 42 | max_shortcut = max_shortcut if max_shortcut and max_shortcut < max_sequence else max_sequence 43 | for i in range(int(max_shortcut)): 44 | origins['next'] = origins[in_sequence] + 1 + i 45 | links.append(pd.merge(origins, destinations, 46 | left_on=[trip_id, 'next'], 47 | right_on=[trip_id, in_sequence], 48 | suffixes=['_origin', '_destination'] 49 | )) 50 | stop_id_origin = stop_id_origin if stop_id_origin else stop_id + '_origin' 51 | stop_id_destination = stop_id_destination if stop_id_destination else stop_id + '_destination' 52 | 53 | assert len(links), 'no link to concatenate' 54 | concat = pd.concat(links).rename( 55 | columns={ 56 | in_sequence + '_origin': out_sequence, 57 | stop_id + '_origin': stop_id_origin, 58 | stop_id + '_destination': stop_id_destination 59 | } 60 | ).drop([in_sequence + '_destination', 'next'], axis=1) 61 | return concat 62 | 63 | 64 | def clean_sequences(df, sequence='stop_sequence', group_id='trip_id'): 65 | """ Clean the sequence column, drop the index""" 66 | df = df.sort_values([group_id, sequence]).reset_index(drop=True) 67 | sequence_series = df.groupby(group_id).count()[sequence].sort_index() 68 | all_sequences = [] 69 | for group_sequences in list(sequence_series): 70 | for seq in range(group_sequences): 71 | all_sequences.append(seq + 1) 72 | df[sequence] = pd.Series(all_sequences) 73 | return df 74 | -------------------------------------------------------------------------------- /syspy/spatial/geometry_smoothing.py: -------------------------------------------------------------------------------- 1 | # Adapted and simplified from https://github.com/GeographicaGS/GeoSmoothing 2 | 3 | import numpy as np 4 | from scipy.interpolate import splev, splprep 5 | from shapely.geometry import LineString, Polygon 6 | 7 | 8 | class Splines(): 9 | def compSplineKnots(self, x, y, s, k, nest=-1): 10 | """ 11 | Computed with Scipy splprep. Find the B-spline representation of 12 | an N-dimensional curve. 13 | Spline parameters: 14 | :s - smoothness parameter 15 | :k - spline order 16 | :nest - estimate of number of knots needed (-1 = maximal) 17 | """ 18 | 19 | tck_u, fp, ier, msg = splprep([x, y], s=s, k=k, nest=nest, full_output=1) 20 | 21 | if ier > 0: 22 | print("{}. ier={}".format(msg, ier)) 23 | return(tck_u, fp) 24 | 25 | def compSplineEv(self, x, tck, zoom=10): 26 | """ 27 | Computed with Scipy splev. Given the knots and coefficients of 28 | a B-spline representation, evaluate the value of the smoothing 29 | polynomial and its derivatives 30 | Parameters: 31 | :tck - A tuple (t,c,k) containing the vector of knots, 32 | the B-spline coefficients, and the degree of the spline. 33 | """ 34 | n_coords = len(x) 35 | n_len = n_coords * zoom 36 | x_ip, y_ip = splev(np.linspace(0, 1, n_len), tck) 37 | 38 | return(x_ip, y_ip) 39 | 40 | 41 | class GeoSmoothing(): 42 | def __init__(self, spl_smpar=0, spl_order=2, verbose=True): 43 | """ 44 | spl_smpar: smoothness parameter 45 | spl_order: spline order 46 | """ 47 | self.spl_smpar = spl_smpar 48 | self.spl_order = spl_order 49 | self.verbose = verbose 50 | 51 | def get_coordinates(self, geom): 52 | """ 53 | Getting x,y coordinates from geometry... 54 | """ 55 | if isinstance(geom, LineString): 56 | x = np.array(geom.coords.xy[0]) 57 | y = np.array(geom.coords.xy[1]) 58 | 59 | elif isinstance(geom, Polygon): 60 | x = np.array(geom.exterior.coords.xy[0]) 61 | y = np.array(geom.exterior.coords.xy[1]) 62 | return(x, y) 63 | 64 | def geom_from_coords(self, coords_ip, geom): 65 | """ 66 | """ 67 | if isinstance(geom, LineString): 68 | geom_ip = LineString(coords_ip.T) 69 | 70 | elif isinstance(geom, Polygon): 71 | geom_ip = Polygon(coords_ip.T) 72 | return geom_ip 73 | 74 | def smooth_geom(self, geom): 75 | """ 76 | Run smoothing geometries 77 | """ 78 | x, y = self.get_coordinates(geom) 79 | 80 | spl = Splines() 81 | 82 | tck_u, fp = spl.compSplineKnots(x, y, self.spl_smpar, self.spl_order) 83 | x_ip, y_ip = spl.compSplineEv(x, tck_u[0]) 84 | 85 | coords_ip = np.array([x_ip, y_ip]) 86 | return self.geom_from_coords(coords_ip, geom) 87 | -------------------------------------------------------------------------------- /quetzal/engine/elevation.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | from osgeo import gdal 4 | from pathlib import Path 5 | import rasterio 6 | import scipy 7 | from hashlib import sha1 8 | 9 | 10 | def _query_raster_nearest(nodes, filepath, band=1): 11 | """ 12 | Query a raster for values at coordinates in a DataFrame's x/y columns. 13 | Parameters 14 | ---------- 15 | nodes : pandas.DataFrame 16 | DataFrame indexed by node ID and with two columns: x and y 17 | filepath : string or pathlib.Path 18 | path to the raster file or VRT to query 19 | band : int 20 | which raster band to query 21 | Returns 22 | ------- 23 | nodes_values : zip 24 | zipped node IDs and corresponding raster values 25 | """ 26 | # must open raster file here: cannot pickle it to pass in multiprocessing 27 | with rasterio.open(filepath) as raster: 28 | values = np.array(tuple(raster.sample(nodes.values, band)), dtype=float).squeeze() 29 | values[values == raster.nodata] = np.nan 30 | return zip(nodes.index, values) 31 | 32 | 33 | def _query_raster_interp(nodes, filepath, band=1, method='linear'): 34 | 35 | with rasterio.open(filepath) as src: 36 | band1 = src.read(band) 37 | height = band1.shape[0] 38 | width = band1.shape[1] 39 | cols, rows = np.meshgrid(np.arange(width), np.arange(height)) 40 | xs, ys = rasterio.transform.xy(src.transform, rows, cols) 41 | 42 | lons= np.array(xs) 43 | lats = np.array(ys) 44 | f = scipy.interpolate.interp2d( 45 | lons[0, :], 46 | lats[:, 0], 47 | band1, 48 | kind=method 49 | ) 50 | 51 | values = [f(r[0], r[1])[0] for r in nodes.values] 52 | # values = nodes.apply(lambda r: f(r.x, r.y)[0], 1) 53 | 54 | return list(zip(nodes.index, values)) 55 | 56 | 57 | def query_raster(nodes, filepath, band=1, method='nearest'): 58 | """ 59 | Query a raster for values at coordinates in a DataFrame's x/y columns. 60 | Parameters 61 | ---------- 62 | nodes : pandas.DataFrame 63 | DataFrame indexed by node ID and with two columns: x and y 64 | filepath : string or pathlib.Path 65 | path to the raster file or VRT to query 66 | band : int 67 | which raster band to query 68 | Returns 69 | ------- 70 | nodes_values : zip 71 | zipped node IDs and corresponding raster values 72 | """ 73 | if method=='nearest': 74 | return _query_raster_nearest(nodes, filepath, band) 75 | else: 76 | return _query_raster_interp(nodes, filepath, band, method) 77 | 78 | 79 | def merge_rasters_virtually(filepath): 80 | 81 | if not isinstance(filepath, (str, Path)): 82 | filepaths = [str(p) for p in filepath] 83 | sha = sha1(str(filepaths).encode("utf-8")).hexdigest() 84 | filepath = os.path.join(os.path.dirname(filepaths[0]), f".osmnx_{sha}.vrt") 85 | gdal.BuildVRT(filepath, filepaths).FlushCache() 86 | 87 | return filepath -------------------------------------------------------------------------------- /syspy/pycube/project.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import os 3 | 4 | from syspy.pycube.application import Application 5 | 6 | 7 | def multiple_replace(text, word_dict): 8 | for key in word_dict: 9 | text = text.replace(key, word_dict[key]) 10 | return text 11 | 12 | 13 | def list_files(path, patterns): 14 | files = [os.path.join(path, file) for file in os.listdir(path) if file.split('.')[-1].lower() in patterns] 15 | subdirectories = [os.path.join(path, dir) for dir in os.listdir(path) if os.path.isdir(os.path.join(path, dir))] 16 | files += list(itertools.chain(*[list_files(subdirectory, patterns) for subdirectory in subdirectories])) 17 | return files 18 | 19 | 20 | def list_apps(path): 21 | apps = [os.path.join(path, app) for app in os.listdir(path) if (app.endswith('.app') or app.endswith('.APP'))] 22 | subdirectories = [os.path.join(path, dir) for dir in os.listdir(path) if os.path.isdir(os.path.join(path, dir))] 23 | apps += list(itertools.chain(*[list_apps(subdirectory) for subdirectory in subdirectories])) 24 | return apps 25 | 26 | 27 | def replace_in_file(filename, old, new): 28 | with open(filename, 'r') as file: 29 | soup = file.read() 30 | count = soup.count(old) 31 | with open(filename, 'w') as file: 32 | file.write(soup.replace(old, new)) 33 | return count 34 | 35 | 36 | class Project: 37 | """ 38 | Object for processing text, scripts an apps in a cube project, based on top of pycube.application. 39 | """ 40 | def __init__(self, catalog_dir): 41 | self.catalog_dir = catalog_dir 42 | self.apps = [Application(app_file) for app_file in list_apps(self.catalog_dir)] 43 | self.cube_generated_text_like_files = list_files( 44 | self.catalog_dir, patterns=['app', 'txt', 's', 'vpr', 'cpl', 'py']) 45 | 46 | def change_catalog_dir(self, old_dir, new_dir='default'): 47 | 48 | """ 49 | :param old_dir: current path to the catalog directory as written in the scripts and apps 50 | :type old_dir: str 51 | :param new_dir: new path to the catalog directory to be written in the scripts and apps 52 | :type new_dir: str 53 | :return: None 54 | """ 55 | _new_dir = self.catalog_dir if new_dir == 'default' else new_dir 56 | occurrences = 0 57 | for filename in self.cube_generated_text_like_files: 58 | occurrences += replace_in_file(filename, old_dir, _new_dir) 59 | 60 | print(str(occurrences) + ' replacement have been performed ') 61 | 62 | def replace(self, old_string, new_string): 63 | 64 | """ 65 | :param old_string: string to replace 66 | :type old_dir: str 67 | :param new_string: new string 68 | :type new_dir: str 69 | :return: None 70 | """ 71 | occurrences = 0 72 | for filename in self.cube_generated_text_like_files: 73 | occurrences += replace_in_file(filename, old_string, new_string) 74 | 75 | print(str(occurrences) + ' change(s)') 76 | -------------------------------------------------------------------------------- /syspy/renumber/renumber.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | 3 | import pandas as pd 4 | import shapely 5 | from syspy.spatial import spatial 6 | 7 | 8 | def _join_geometry(link_row, one, many): 9 | return shapely.geometry.LineString( 10 | [one['geometry'].loc[link_row['ix_one']], many['geometry'].loc[link_row['ix_many']]]) 11 | 12 | 13 | def add_geometry_coordinates(df, columns=['x_geometry', 'y_geometry']): 14 | df[columns[0]] = df['geometry'].apply(lambda g: g.coords[0][0]) 15 | df[columns[1]] = df['geometry'].apply(lambda g: g.coords[0][1]) 16 | return df 17 | 18 | 19 | def renumber( 20 | zones, 21 | volume, 22 | n_clusters=10, 23 | cluster_column=None, 24 | volume_columns=['volume'] 25 | ): 26 | clusters, cluster_series = spatial.zone_clusters( 27 | zones, 28 | n_clusters=n_clusters, 29 | cluster_column=cluster_column 30 | ) 31 | grouped = renumber_volume( 32 | volume, 33 | cluster_series, 34 | volume_columns=volume_columns 35 | ) 36 | return clusters, grouped, cluster_series 37 | 38 | 39 | def renumber_quetzal( 40 | zones, 41 | volume, 42 | od_stack, 43 | n_clusters=10, 44 | cluster_column=None, 45 | volume_columns=['volume'], 46 | volume_od_columns=['volume_pt'], 47 | distance_columns=['euclidean_distance'] 48 | ): 49 | clusters, cluster_series = spatial.zone_clusters( 50 | zones, 51 | n_clusters=n_clusters, 52 | cluster_column=cluster_column 53 | ) 54 | grouped = renumber_volume( 55 | volume, 56 | cluster_series, 57 | volume_columns=volume_columns 58 | ) 59 | od_stack_grouped = renumber_od_stack( 60 | od_stack, 61 | cluster_series, 62 | volume_od_columns, 63 | distance_columns) 64 | return clusters, grouped, cluster_series, od_stack_grouped 65 | 66 | 67 | def renumber_volume(volume, cluster_series, volume_columns): 68 | proto = pd.merge(volume, pd.DataFrame(cluster_series), left_on='origin', right_index=True) 69 | proto = pd.merge(proto, pd.DataFrame(cluster_series), left_on='destination', 70 | right_index=True, suffixes=['_origin', '_destination']) 71 | grouped = proto.groupby(['cluster_origin', 'cluster_destination'])[volume_columns].sum() 72 | grouped.index.names = ['origin', 'destination'] 73 | grouped.reset_index(inplace=True) 74 | return grouped 75 | 76 | 77 | def renumber_od_stack(od_stack, cluster_series, volume_columns, distance_columns): 78 | proto = pd.merge(od_stack, pd.DataFrame(cluster_series), left_on='origin', right_index=True) 79 | proto = pd.merge(proto, pd.DataFrame(cluster_series), left_on='destination', 80 | right_index=True, suffixes=['_origin', '_destination']) 81 | f = {v: 'sum' for v in volume_columns} 82 | f.update({d: 'mean' for d in distance_columns}) 83 | grouped = proto.groupby(['cluster_origin', 'cluster_destination']).agg(f) 84 | grouped.index.names = ['origin', 'destination'] 85 | grouped = pd.DataFrame(grouped) 86 | grouped.reset_index(inplace=True) 87 | return grouped 88 | -------------------------------------------------------------------------------- /docs/build/_static/css/badge_only.css: -------------------------------------------------------------------------------- 1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} -------------------------------------------------------------------------------- /syspy/pycube/network.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | 3 | import pandas as pd 4 | import shapely 5 | from IPython.display import display 6 | from IPython.html.widgets import FloatProgress 7 | from syspy.spatial import spatial 8 | from syspy.syspy_utils import syscolors 9 | 10 | 11 | def zone_stops(zones, nodes, stop_list, leg_type='contains'): 12 | 13 | if leg_type == 'contains': 14 | progress = FloatProgress( 15 | min=0, max=len(list(zones.iterrows())), width=975, height=10, color=syscolors.rainbow_shades[1], margin=5) 16 | progress.value = 0 17 | display(progress) 18 | zone_stops = {} 19 | for zone_id, zone in zones.iterrows(): 20 | zone_stops[zone_id] = [] 21 | for stop_id, stop in nodes.loc[stop_list].iterrows(): 22 | if zone['geometry'].contains(stop['geometry']): 23 | zone_stops[zone_id].append(stop_id) 24 | progress.value += 1 25 | 26 | if leg_type == 'nearest': 27 | centroids = zones.copy() 28 | centroids['geometry'] = zones['geometry'].apply(lambda g: g.centroid) 29 | stops = nodes.loc[stop_list] 30 | 31 | links_a = spatial.nearest(stops, centroids).rename(columns={'ix_many': 'zone', 'ix_one': 'stop'}) 32 | links_b = spatial.nearest(centroids, stops).rename(columns={'ix_one': 'zone', 'ix_many': 'stop'}) 33 | links = pd.concat([links_a, links_b]).drop_duplicates() 34 | zone_stops = dict(links.groupby('zone')['stop'].agg(lambda s: list(s))) 35 | return zone_stops 36 | 37 | 38 | def nontransitleg_geometries(nontransitleg_list, zones, nodes): 39 | df_a = pd.DataFrame(nontransitleg_list, columns=['a', 'b']) 40 | 41 | def geometry(row): 42 | return shapely.geometry.LineString( 43 | [nodes.loc[row['a'], 'geometry'], zones.loc[row['b'], 'geometry'].centroid] 44 | ) 45 | 46 | df_a['geometry'] = df_a.apply(geometry, axis=1) 47 | df_b = df_a.rename(columns={'a': 'b', 'b': 'a'}) 48 | return pd.concat([df_a, df_b]) 49 | 50 | 51 | def nontransitleg_list(zone_stops): 52 | nontransitlegs = [] 53 | for zone in zone_stops.keys(): 54 | for stop in zone_stops[zone]: 55 | nontransitlegs.append((stop, zone)) 56 | 57 | return list(set(nontransitlegs)) 58 | 59 | 60 | def nontransitlegs(zones, nodes, stop_list, leg_type='contains'): 61 | _zone_stops = zone_stops(zones, nodes, stop_list, leg_type) 62 | _list = nontransitleg_list(_zone_stops) 63 | return nontransitleg_geometries(_list, zones, nodes) 64 | 65 | 66 | def reindex_nodes(links, nodes, start_from=0, reindex_node=None): 67 | if reindex_node is None: 68 | nodes = nodes.copy() 69 | links = links.copy() 70 | 71 | index = nodes.index 72 | rename_dict = {} 73 | current = start_from 74 | for n in index: 75 | rename_dict[n] = str(current) 76 | current += 1 77 | 78 | def reindex_node(node): 79 | return rename_dict[node] 80 | 81 | nodes.index = [reindex_node(n) for n in nodes.index] 82 | links['a'] = links['a'].apply(reindex_node) 83 | links['b'] = links['b'].apply(reindex_node) 84 | return links, nodes 85 | -------------------------------------------------------------------------------- /quetzal/io/EMMEporter.py: -------------------------------------------------------------------------------- 1 | import geopandas as gpd 2 | import pandas as pd 3 | import json 4 | from syspy.spatial.geometries import line_list_to_polyline 5 | 6 | def shorter_links(links,original_links = False, add_dict = {} ): 7 | ''' 8 | script to shorten the links of Emme that are keeping on the node to have Quetzal links with only alighting or boardings 9 | if original_links == True, we keep the emme links in liste in the new table' 10 | Geometric_node_columns is the field that permit to filter geometric nodes that have buged pickup_type using other columns 11 | you will need to pass a list of two columns, first boarding then alighting 12 | 13 | ''' 14 | crs = links.crs 15 | links = links.copy() 16 | # Safeguard: Ensure key columns are present 17 | required_cols = ['pickup_type', 'drop_off_type', 'a', 'b','geometry','trip_id','link_sequence','length','speed','time'] 18 | missing_cols = [col for col in required_cols if col not in links.columns] 19 | if missing_cols: 20 | raise ValueError(f"Missing columns: {missing_cols}") 21 | links = links.sort_values(['trip_id', 'link_sequence']) 22 | first_last = links.reset_index().groupby('trip_id')['index'].agg(['first', 'last']) 23 | links['stop'] = True 24 | links['next_pickup'] = links['pickup_type'].shift(-1).fillna(0).astype(int) 25 | links['prev_drop_off'] = links['drop_off_type'].shift(+1).fillna(0).astype(int) 26 | links.loc[(links['pickup_type'] != 0) & (links['prev_drop_off'] != 0), 'stop'] = False 27 | #if the one before is false it means that you can 28 | links.loc[first_last['first'], 'stop'] = True 29 | #links.loc[first_last['last'],'stop'] = True 30 | links['cumsum'] = links['stop'].cumsum() 31 | links = links.drop(columns=['next_pickup', 'prev_drop_off']) 32 | #Aggregate of links and columns 33 | #ajouter dans parametre agg_dict() update mon agg_dict() 34 | agg_dict = {col: 'first' for col in links.columns} 35 | del agg_dict['cumsum'] 36 | del agg_dict['stop'] 37 | del agg_dict['speed'] 38 | agg_dict['a'] = 'first' 39 | agg_dict['b'] = 'last' 40 | agg_dict['geometry'] = line_list_to_polyline 41 | agg_dict['road_link_list'] = lambda x: sum(x, []) 42 | agg_dict['time'] = sum 43 | agg_dict['length'] = sum 44 | agg_dict['drop_off_type'] = 'last' 45 | agg_dict.update(add_dict) 46 | if original_links is True: 47 | links['original_links'] = [*zip(links['a'], links['b'])] 48 | agg_dict['original_links'] = list 49 | if 'selectLink' in links.columns: 50 | agg_dict['selectLink'] = lambda x: 'yes' if 'yes' in set(x) else None 51 | for col in links.columns: 52 | print(col, ' --> ', agg_dict.get(col, '! not agg !')) 53 | links = links.reset_index().groupby('cumsum').agg(agg_dict) 54 | links['speed'] = 3.6 * links['length'] / links['time'] 55 | # fix link_sequence 56 | lengths_sequence = links.groupby('trip_id')['a'].agg(len).values 57 | link_sequence = [i + 1 for l in lengths_sequence for i in range(l)] 58 | links['link_sequence'] = link_sequence 59 | links.index = 'link_' + links.index.astype(str) 60 | links.index.name = 'index' 61 | links = gpd.GeoDataFrame(links) 62 | links = links.set_crs(crs) 63 | 64 | return(links) -------------------------------------------------------------------------------- /syspy/surveys/discrete_choice.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import numpy as np 4 | import pandas as pd 5 | from syspy.surveys.array_example import base 6 | 7 | 8 | def get_array(array_class, verbose=False): 9 | selected = base.copy() 10 | for level, factors in array_class.items(): 11 | selected = selected .loc[ 12 | selected[level] >= factors 13 | ].copy() 14 | 15 | first = selected.iloc[0] 16 | exponents = first['exponents'] 17 | df = pd.DataFrame(json.loads(first['array'])) 18 | df.columns = get_index(exponents) 19 | 20 | array_classes = selected.loc[ 21 | selected['runs'] == first['runs'], 22 | 'exponents' 23 | ] 24 | if verbose: 25 | print('required array class:') 26 | print(array_class) 27 | print('available array classes (using first one): ') 28 | print(array_classes) 29 | return df[get_index(array_class)] 30 | 31 | 32 | def build_array(array_class, *args, **kwargs): 33 | try: 34 | return get_array(array_class, *args, **kwargs) 35 | except ValueError: 36 | i = 2 37 | m = max(array_class.keys()) 38 | pop = array_class.pop(m) 39 | l = [] 40 | for key in [int(m / i), i]: 41 | base = 0 42 | if key in array_class.keys(): 43 | base = array_class[key] 44 | array_class[key] = base + 1 45 | l.append('%ie%i' % (key, base)) 46 | 47 | oa = get_array(array_class) 48 | oa['%ie%i' % (m, 0)] = oa[l[0]] + oa[l[1]] * int(m / i) 49 | return oa.drop(l, axis=1) 50 | 51 | 52 | def get_index(exponents): 53 | index = [] 54 | for level, factors in exponents.items(): 55 | for i in range(factors): 56 | c = str(level) + 'e' + str(i) 57 | index.append(c) 58 | return sorted(index) 59 | 60 | 61 | def get_selection(array_class): 62 | selected = base.copy() 63 | for level, factors in array_class.items(): 64 | selected = selected .loc[ 65 | selected[level] >= factors 66 | ].copy() 67 | return selected 68 | 69 | 70 | def get_array_class(factors): 71 | array_class = {} 72 | join = {} 73 | 74 | for factor, levels in factors.items(): 75 | key = len(levels) 76 | if key in array_class: 77 | array_class[key] += 1 78 | else: 79 | array_class[key] = 1 80 | 81 | factor_index = array_class[key] - 1 82 | join[str(key) + 'e' + str(factor_index)] = factor 83 | return array_class, join 84 | 85 | 86 | def orthogonal_array(factors, *args, **kwargs): 87 | array_class, match = get_array_class(factors) 88 | 89 | df = build_array(array_class, *args, **kwargs) 90 | 91 | df.columns = [match[c] for c in df.columns] 92 | 93 | for factor, factor_list in factors.items(): 94 | df[factor] = df[factor].apply(lambda v: factor_list[v]) 95 | 96 | columns = list(set(df.columns)) 97 | identity = pd.DataFrame( 98 | np.identity(len(columns)), 99 | columns=columns, 100 | index=columns 101 | ) 102 | delta_corr = df.corr() - identity 103 | assert delta_corr.max().max() < 1e-9 104 | return df 105 | -------------------------------------------------------------------------------- /quetzal/io/hdf_io.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import pickle 3 | import uuid 4 | import zlib 5 | import zstandard 6 | import os 7 | 8 | import pandas as pd 9 | from tqdm import tqdm 10 | 11 | 12 | class PickleProtocol: 13 | def __init__(self, level): 14 | self.previous = pickle.HIGHEST_PROTOCOL 15 | self.level = level 16 | 17 | def __enter__(self): 18 | importlib.reload(pickle) 19 | pickle.HIGHEST_PROTOCOL = self.level 20 | 21 | def __exit__(self, *exc): 22 | importlib.reload(pickle) 23 | pickle.HIGHEST_PROTOCOL = self.previous 24 | 25 | 26 | def pickle_protocol(level): 27 | return PickleProtocol(level) 28 | 29 | 30 | def write_hdf_to_buffer(frames, level=4, complevel=None): 31 | with pickle_protocol(level): 32 | with pd.HDFStore( 33 | 'quetzal-%s.h5' % str(uuid.uuid4()), 34 | mode='a', 35 | driver='H5FD_CORE', 36 | driver_core_backing_store=0, 37 | complevel=complevel, 38 | ) as out: 39 | iterator = tqdm(frames.items()) 40 | for key, df in iterator: 41 | iterator.desc = key 42 | out[key] = df 43 | return out._handle.get_file_image() 44 | 45 | 46 | def to_zippedpickle(frame, filepath, pickle_protocol_level=4, complevel=-1): 47 | with pickle_protocol(pickle_protocol_level): 48 | buffer = pickle.dumps(frame) 49 | smallbuffer = zstandard.ZstdCompressor(level=complevel).compress(buffer) 50 | with open(filepath, 'wb') as file: 51 | file.write(smallbuffer) 52 | 53 | 54 | def read_zippedpickle(filename): 55 | with open(filename, 'rb') as file: 56 | buffer = file.read() 57 | decompressor = zstandard.ZstdDecompressor() 58 | bigbuffer = decompressor.decompress(buffer) 59 | return pickle.loads(bigbuffer) 60 | 61 | 62 | def frame_to_zip(frame, filepath, level=4, complevel=None): 63 | with pickle_protocol(level): 64 | with pd.HDFStore( 65 | 'quetzal-%s.h5' % str(uuid.uuid4()), 66 | mode='a', 67 | driver='H5FD_CORE', 68 | driver_core_backing_store=0, 69 | complevel=complevel, 70 | ) as out: 71 | out['frame'] = frame 72 | buffer = out._handle.get_file_image() 73 | smallbuffer = zlib.compress(buffer) 74 | with open(filepath, 'wb') as file: 75 | file.write(smallbuffer) 76 | 77 | 78 | def zip_to_frame(filepath): 79 | with open(filepath, 'rb') as file: 80 | data = file.read() 81 | bigbyte = zlib.decompress(data) 82 | 83 | with pd.HDFStore( 84 | 'quetzal-%s.h5' % str(uuid.uuid4()), 85 | mode='r', 86 | driver='H5FD_CORE', 87 | driver_core_backing_store=0, 88 | driver_core_image=bigbyte, 89 | ) as store: 90 | return store['frame'] 91 | 92 | 93 | def get_folder_size(folder): 94 | # return MB 95 | total_size = sum( 96 | os.path.getsize(os.path.join(dirpath, filename)) 97 | for dirpath, _, filenames in os.walk(folder) 98 | for filename in filenames 99 | ) 100 | return total_size / (1024 * 1024) # Convert bytes to MB 101 | -------------------------------------------------------------------------------- /docs/source/_build/html/_static/css/badge_only.css: -------------------------------------------------------------------------------- 1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}} 2 | /*# sourceMappingURL=badge_only.css.map */ 3 | -------------------------------------------------------------------------------- /quetzal/engine/graph_utils.py: -------------------------------------------------------------------------------- 1 | def build_neighbors(edges): 2 | neighbors = {} 3 | for a, b, w in edges: 4 | try: 5 | neighbors[a].add(b) 6 | except KeyError: 7 | neighbors[a] = {b} 8 | try: 9 | neighbors[b].add(a) 10 | except KeyError: 11 | neighbors[b] = {a} 12 | return neighbors 13 | 14 | def vertex_indexed_weights(edges): 15 | ab_dict = {a: dict() for a, b, w in edges} 16 | ba_dict = {b: dict() for a, b, w in edges} 17 | 18 | for a, b, w in edges: 19 | try: 20 | ab_dict[a][b] = w 21 | except KeyError: 22 | ab_dict[a] = {b: w} 23 | try: 24 | ba_dict[b][a] = w 25 | except KeyError: 26 | ba_dict[b] = {a: w} 27 | return ab_dict, ba_dict 28 | 29 | def combine_edges(edges, keep=set()): 30 | 31 | neighbors = build_neighbors(edges) 32 | 33 | # find nodes of degree two 34 | degree_two_or_less = {k for k, n in neighbors.items() if len(n) <= 2} 35 | to_combine = degree_two_or_less - keep 36 | 37 | ab_dict, ba_dict = vertex_indexed_weights(edges) 38 | new_edges = set() 39 | shortcuts = {} 40 | 41 | to_combine = { 42 | n for n in to_combine 43 | if n in ab_dict and n in ba_dict 44 | } # dead_ends can not be combined 45 | 46 | def pop_node(node, ab_dict, ba_dict, new_edges, shortcuts): 47 | 48 | 49 | ab = ab_dict.pop(node) 50 | ba = ba_dict.pop(node) 51 | 52 | for p, w_left in ba.items(): # predecessors 53 | ab_dict[p].pop(node) 54 | 55 | for s, w_right in ab.items(): # successors 56 | ba_dict[s].pop(node) 57 | 58 | for p, w_left in ba.items(): 59 | 60 | if p != s: 61 | time = w_left + w_right 62 | try: 63 | former_time = ab_dict[p][s] 64 | if time < former_time: 65 | ab_dict[p][s] = time 66 | ba_dict[s][p] = time 67 | new_edges.add((p, s)) 68 | left = shortcuts.get((p, node), [p, node]) 69 | right = shortcuts.get((node, s), [node, s]) 70 | shortcuts[(p, s)] = left + right[1:] 71 | 72 | except KeyError: # the edge does not exist 73 | ab_dict[p][s] = time 74 | ba_dict[s][p] = time 75 | new_edges.add((p, s)) 76 | left = shortcuts.get((p, node), [p, node]) 77 | right = shortcuts.get((node, s), [node, s]) 78 | shortcuts[(p, s)] = left + right[1:] 79 | 80 | for node in to_combine: 81 | pop_node(node, ab_dict, ba_dict, new_edges, shortcuts) 82 | 83 | e = [] 84 | for a, ss in ab_dict.items(): 85 | for b, w in ss.items(): 86 | e.append([a, b, w]) 87 | 88 | combined_edges = {(a, b) for a, b, w in e} 89 | shortcuts = {k: v for k, v in shortcuts.items() if k in combined_edges} 90 | new_edges = new_edges.intersection(combined_edges) 91 | 92 | return e, shortcuts 93 | 94 | def expand_path(p, shortcuts): 95 | path = [p[0]] 96 | for e in list(zip(p[:-1], p[1:])): # edge_path 97 | path += shortcuts.get(e, e)[1:] 98 | return path 99 | -------------------------------------------------------------------------------- /tests/data/jsons/loaded_nodes.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { "type": "Feature", "properties": { "index": "FUR_CREEK_RES", "stop_name": "Furnace Creek Resort (Demo)", "stop_desc": 0.0, "stop_lat": 36.425288, "stop_lon": -117.133162, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 1.846307147203984, "boardings": 0.8463171119253321, "alightings": 0.99999003527865182, "transfers": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -117.133162, 36.425288 ] } }, 5 | { "type": "Feature", "properties": { "index": "BEATTY_AIRPORT", "stop_name": "Nye County Airport (Demo)", "stop_desc": 0.0, "stop_lat": 36.868446, "stop_lon": -116.784582, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 2.0048428268202225, "boardings": 0.45033581134181183, "alightings": 0.45033757890762455, "transfers": 0.15367788940941798 }, "geometry": { "type": "Point", "coordinates": [ -116.784582, 36.868446 ] } }, 6 | { "type": "Feature", "properties": { "index": "BULLFROG", "stop_name": "Bullfrog (Demo)", "stop_desc": 0.0, "stop_lat": 36.88108, "stop_lon": -116.81797, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 2.1976134094415394, "boardings": 1.2966497247768585, "alightings": 1.296652923267144, "transfers": 0.7469955008400182 }, "geometry": { "type": "Point", "coordinates": [ -116.81797, 36.88108 ] } }, 7 | { "type": "Feature", "properties": { "index": "STAGECOACH", "stop_name": "Stagecoach Hotel & Casino (Demo)", "stop_desc": 0.0, "stop_lat": 36.915682, "stop_lon": -116.751677, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 1.0075274578207731, "boardings": 0.15367788940941798, "alightings": 0.0, "transfers": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.751677, 36.915682 ] } }, 8 | { "type": "Feature", "properties": { "index": "NADAV", "stop_name": "North Ave \/ D Ave N (Demo)", "stop_desc": 0.0, "stop_lat": 36.914893, "stop_lon": -116.76821, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 1.7595200009064602, "boardings": 0.0, "alightings": 0.0, "transfers": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.76821, 36.914893 ] } }, 9 | { "type": "Feature", "properties": { "index": "NANAA", "stop_name": "North Ave \/ N A Ave (Demo)", "stop_desc": 0.0, "stop_lat": 36.914944, "stop_lon": -116.761472, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.093939911307376153, "boardings": 0.0, "alightings": 0.0, "transfers": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.761472, 36.914944 ] } }, 10 | { "type": "Feature", "properties": { "index": "DADAN", "stop_name": "Doing Ave \/ D Ave N (Demo)", "stop_desc": 0.0, "stop_lat": 36.909489, "stop_lon": -116.768242, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.94810650699354992, "boardings": 0.0, "alightings": 0.0, "transfers": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.768242, 36.909489 ] } }, 11 | { "type": "Feature", "properties": { "index": "EMSI", "stop_name": "E Main St \/ S Irving St (Demo)", "stop_desc": 0.0, "stop_lat": 36.905697, "stop_lon": -116.76218, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 1.8891232754361238, "boardings": 0.0, "alightings": 0.0, "transfers": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.76218, 36.905697 ] } }, 12 | { "type": "Feature", "properties": { "index": "AMV", "stop_name": "Amargosa Valley (Demo)", "stop_desc": 0.0, "stop_lat": 36.641496, "stop_lon": -116.40094, "zone_id": 0.0, "stop_url": 0.0, "volume_pt": 0.0, "boardings": 0.0, "alightings": 0.0, "transfers": 0.0 }, "geometry": { "type": "Point", "coordinates": [ -116.40094, 36.641496 ] } } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # quetzal 3 | ## What is it? 4 | **quetzal** is a Python package providing flexible models for transport planning and traffic forecasting. 5 | ## Copyright 6 | (c) SYSTRA 7 | ## License 8 | [CeCILL-B](LICENSE.md) 9 | ## Documentation 10 | The official documentation is hosted on https://systragroup.github.io/quetzal 11 | ## Backward compatibility 12 | In order to improve the ergonomics, the code may be re-factored and a few method calls may be re-designed. As a consequence, the backward compatibility of the library is not guaranteed. Therefore, the version of quetzal used for a project should be specified in its requirements. 13 | 14 | # Installation from sources 15 | ## For Linux 16 | One should choose between 17 | - Poetry (recommended) 18 | - Virtualenv 19 | - Anaconda 20 | 21 | ### poetry 22 | 1) May need to set the default (or local) python version in the project 23 | ```bash 24 | pyenv local 3.12 25 | ``` 26 | 2) install dependancies (this will create a new virtualenv) 27 | ```bash 28 | poetry install 29 | ``` 30 | 3) activate the env 31 | ```bash 32 | poetry shell 33 | ``` 34 | 4) add the env to ipykernel (to use in jupyter) 35 | ```bash 36 | python -m ipykernel install --user --name=quetzal_env 37 | ``` 38 | 39 | ### Virtualenv 40 | Virtual environment: `virtualenv .venv -p python3.12; source .venv/bin/activate` or any equivalent command. 41 | 42 | ```bash 43 | pip install -e . 44 | ``` 45 | 46 | #### Anaconda 47 | In order to use python notebook, Anaconda 3 + Python 3.12 must be installed. 48 | Then create + activate quetzal environment: 49 | ```bash 50 | conda init 51 | conda create -n quetzal_env -y python=3.12 52 | conda activate quetzal_env 53 | pip install -e . -r requirements_win.txt 54 | python -m ipykernel install --user --name=quetzal_env 55 | ``` 56 | 57 | 58 | 59 | ## For Windows 60 | `Anaconda 3 + Python 3.12` is supposed to be installed 61 | #### PIP and Anaconda (recommended) 62 | To create quetzal_env automatically and install quetzal, open anaconda prompt and 63 | run windows-install batch file 64 | ```bash 65 | (base) C:users\you\path\to\quetzal> windows-install.bat 66 | ``` 67 | press enter to accept default environment name or enter a custom name 68 | #### If you are facing SSL issues 69 | ```bash 70 | (base) pip config set global.trusted-host "pypi.org files.pythonhosted.org" 71 | (base) C:users\you\path\to\quetzal> windows-install.bat 72 | ``` 73 | security warning: the host is added to pip.ini 74 | 75 | #### If you are facing DLL or dependencies issues 76 | Anaconda and Pip do not get along well, your Anaconda install may have been corrupted at some point. 77 | - Remove your envs 78 | - Uninstall Anaconda 79 | - Delete your Python and Anaconda folders (users\you\Anaconda3, users\you\Appdata\Roaming\Python, ...etc) 80 | - Install Anaconda 81 | 82 | 83 | ## migration to 3.12 84 | * pandas append was remove: 85 | ```python 86 | # before 87 | sm.volumes = sm.volumes.append(vol) 88 | #now 89 | sm.volumes = pd.concat([sm.volumes, vol]) 90 | #or 91 | sm.volumes = pd.concat([sm.volumes, pd.DataFrame(vol)]) 92 | ``` 93 | filtering index with set was remove: 94 | ```python 95 | # before 96 | sm.volumes = sm.volumes.loc[od_set] 97 | #now 98 | sm.volumes = sm.volumes.loc[list(od_set)] 99 | ``` 100 | 101 | * shapely 102 | ```python 103 | # before 104 | hull = zones.unary_union.convex_hull 105 | # now 106 | hull = zones.union_all().convex_hull 107 | ``` 108 | * scikitlearn 109 | ```python 110 | # add n_init='auto' 111 | KMeans(n_clusters=num_zones,random_state=0,n_init='auto') 112 | ``` 113 | -------------------------------------------------------------------------------- /syspy/graph/nearest_path.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | 3 | import networkx as nx 4 | from networkx import NetworkXNoPath 5 | 6 | 7 | def find_road_node_options(node_path, nearest_neighbors): 8 | df = nearest_neighbors.loc[nearest_neighbors['ix_one'].isin(node_path)].copy() 9 | df.sort_values('rank', inplace=True) 10 | 11 | options = {} 12 | for node_index in range(len(node_path)): 13 | node = node_path[node_index] 14 | road_nodes = set(df[df['ix_one'] == node]['ix_many']) 15 | tuples = [(node, road_node) for road_node in road_nodes] 16 | options[node] = tuples 17 | return options 18 | 19 | 20 | def build_shortcut_ghaph( 21 | node_path, 22 | road_node_options, 23 | road_graph, 24 | penalties=None 25 | ): 26 | if True: 27 | indexed_road_node_options = {} 28 | indexed_node_path = [] 29 | for node_index in range(len(node_path)): 30 | node = node_path[node_index] 31 | key = (node_index, node) 32 | value = [(node_index,) + option for option in road_node_options[node]] 33 | indexed_road_node_options[key] = value 34 | indexed_node_path.append(key) 35 | road_node_options = indexed_road_node_options 36 | node_path = indexed_node_path 37 | 38 | node_tuples = [ 39 | (node_path[i], node_path[i + 1]) 40 | for i in range(len(node_path) - 1) 41 | ] 42 | 43 | # Build the shortcut graph 44 | edges = [] 45 | 46 | for tuple_index in range(len(node_tuples)): 47 | origin, destination = node_tuples[tuple_index] 48 | product = list( 49 | itertools.product( 50 | road_node_options[origin], 51 | road_node_options[destination] 52 | ) 53 | ) 54 | 55 | edges += [p + (tuple_index,) for p in product] 56 | 57 | def penalty(node_road_node_tuple): 58 | if True: 59 | node_road_node_tuple = node_road_node_tuple[1:] 60 | 61 | if penalties: 62 | return penalties[node_road_node_tuple] 63 | else: 64 | return 0 65 | 66 | weighted_edges = [] 67 | for edge_index in range(len(edges)): 68 | origin, destination, tuple_index = edges[edge_index] 69 | road_origin = origin[-1] 70 | road_destination = destination[-1] 71 | try: 72 | length, path = nx.bidirectional_dijkstra( 73 | road_graph, 74 | road_origin, 75 | road_destination 76 | ) 77 | except NetworkXNoPath: 78 | length, path = float('inf'), ['wrong'] 79 | 80 | length += penalty(origin) + penalty(destination) 81 | 82 | weighted_edge = ( 83 | origin, 84 | destination, 85 | length 86 | ) 87 | weighted_edges.append(weighted_edge) 88 | 89 | origin_options = road_node_options[node_path[0]] 90 | destination_options = road_node_options[node_path[-1]] 91 | 92 | assert origin_options and destination_options 93 | o_edges = [['origin', o, penalty(o)] for o in origin_options] 94 | d_edges = [[o, 'destination', penalty(o)]for o in destination_options] 95 | 96 | shortcut_graph = nx.DiGraph() 97 | shortcut_graph.add_weighted_edges_from( 98 | weighted_edges + o_edges + d_edges 99 | ) 100 | return shortcut_graph 101 | 102 | 103 | def find_road_node_path(shortcut_graph): 104 | tuple_path = nx.dijkstra_path(shortcut_graph, 'origin', 'destination')[1:-1] 105 | return [t[-1] for t in tuple_path] 106 | -------------------------------------------------------------------------------- /syspy/pycube/dijkstra.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | 3 | import networkx as nx 4 | 5 | 6 | class DijkstraMonkey: 7 | """ 8 | nx.DiGraph based object. Runs Dijkstra algorithm to infer the extensive sequence of nodes from a partial 9 | sequence. Add intermediate nodes to a .LIN to fit a detailed network. 10 | 11 | example: 12 | :: 13 | df_edges =links[['a', 'b', 'length']] 14 | edges = [tuple(df_edges.ix[i]) for i in df_edges.index] # edges is a list of tuples (a, b, length) 15 | edsger = pycube.lin.DijkstraMonkey(edges) 16 | edsger.make_lin(data_path + 'monterrey_2045_edited.lin', data_path + 'monterrey_2045_edited_dijkstra.lin') 17 | """ 18 | def __init__(self, edges): 19 | self.g = nx.DiGraph() 20 | self.g.add_weighted_edges_from(edges) 21 | 22 | def _to_insert(path): 23 | """ returns a string containing all the intermediates nodes of a path in .lin format """ 24 | return ''.join(['N=-' + str(int(path[i])) + ', ' for i in range(1, len(path) - 1)]) 25 | _to_insert = staticmethod(_to_insert) 26 | 27 | def _path_from_pair(self, pair): 28 | _pair = [int(i.replace('-', '')) for i in pair] 29 | """ tries to return the shortest path between to points of a pair""" 30 | try: 31 | path = nx.dijkstra_path(self.g, _pair[0], _pair[1]) 32 | except Exception: 33 | print('fail at ' + str(pair)) 34 | path = [] 35 | 36 | return path 37 | 38 | def _line_with_intermediate_nodes(self, line): 39 | """ returns a string string with all the intermediates nodes from a .lin line string""" 40 | sequence = line.split('N=') 41 | pairs = [[sequence[i].split(',')[0], sequence[i + 1].split(',')[0]] for i in range(1, len(sequence) - 1)] 42 | paths = [self._path_from_pair(pair) for pair in pairs] 43 | 44 | k = 2 45 | for i in range(0, len(pairs)): 46 | if len(self._to_insert(paths[i])): 47 | sequence.insert(i + k, self._to_insert(paths[i])) 48 | k += 1 49 | return 'N='.join(sequence).replace('N=N', 'N') 50 | 51 | def make_lin(self, from_lin_file, to_lin_file, sep=None): 52 | """ 53 | make a .lin file from another using dijkstra algorithm to add intermediates nodes 54 | 55 | :param from_lin_file: the lin to process 56 | :param to_lin_file: the path to the lin to save 57 | :param sep: the string that separates the lines in the file ex: 'LINE NAME' 58 | :return: None 59 | """ 60 | # lecture du .LIN d'origine 61 | with open(from_lin_file, 'r') as f: 62 | lines = f.readlines() 63 | 64 | if sep: 65 | with open(from_lin_file, 'r') as f: 66 | lines = _to_n_equal(f.read()).split(sep) 67 | 68 | # construction de la liste des lignes du nouveau .LIN à partir de celle de l'ancien 69 | lines_with_intermediate_nodes = [self._line_with_intermediate_nodes(line) for line in lines] 70 | 71 | # écriture du nouveau .LIN 72 | with open(to_lin_file, 'w') as f: 73 | f.write(''.join(lines_with_intermediate_nodes)) 74 | if sep: 75 | with open(to_lin_file, 'w') as f: 76 | f.write(sep.join(lines_with_intermediate_nodes)) 77 | 78 | 79 | def _to_n_equal(l): 80 | return ','.join([_chunk_to_n_equal(c) for c in l.split(',')]) 81 | 82 | 83 | def _chunk_to_n_equal(c): 84 | return 'N=' + c if _represents_int(c) else c 85 | 86 | 87 | def _represents_int(s): 88 | try: 89 | int(s) 90 | return True 91 | except ValueError: 92 | return False 93 | -------------------------------------------------------------------------------- /quetzal/io/gtfs_reader/patterns.py: -------------------------------------------------------------------------------- 1 | import gtfs_kit as gk 2 | import numpy as np 3 | import pandas as pd 4 | from syspy.spatial import spatial 5 | 6 | 7 | def build_stop_clusters( 8 | stops, distance_threshold=150, col='cluster_id', use_parent_station=False 9 | ): 10 | """ 11 | Apply agglomerative clustering algorithm to stops. 12 | Add a column cluster_id with the cluster id. 13 | If use_parent_station = True: clustering based on parent stations when known 14 | """ 15 | # TODO: do not work for big feeds --> suggest to use KMeans in this case 16 | gdf = gk.stops.geometrize_stops_0(stops, use_utm=True) 17 | temp = gdf.copy() 18 | if use_parent_station: 19 | if 'parent_station' not in gdf.columns: 20 | gdf['parent_station'] = np.nan 21 | gdf['dissolve'] = gdf.apply( 22 | lambda x: x['parent_station'] if isinstance(x['parent_station'], str) else x['stop_id'], 23 | 1 24 | ) 25 | temp = gdf.dissolve('dissolve', as_index=False) 26 | temp.geometry = temp.geometry.centroid 27 | 28 | temp[col] = spatial.agglomerative_clustering( 29 | temp, distance_threshold=distance_threshold 30 | ) 31 | 32 | if use_parent_station: 33 | temp = gdf.merge(temp[['dissolve', col]], on='dissolve', how='left') 34 | temp.drop('dissolve', 1, inplace=True) 35 | return gk.stops.ungeometrize_stops_0(temp) 36 | 37 | 38 | def build_patterns( 39 | feed, group=['route_id'], on='stop_id' 40 | ): 41 | """ 42 | """ 43 | trip_footprints = get_trip_footprints(feed, on=on) 44 | patterns = get_patterns(feed.trips, trip_footprints, group=group) 45 | feed.trips = feed.trips.merge( 46 | patterns[['trip_id', 'pattern_id']], on='trip_id' 47 | ) 48 | 49 | 50 | def get_trip_stop_list(stop_times, stops=None, on='stop_id'): 51 | trip_stops = stop_times.copy() 52 | if on != 'stop_id': 53 | s_to_c = stops.set_index('stop_id')[on].reset_index() 54 | trip_stops = trip_stops.merge(s_to_c) 55 | trip_stops = trip_stops.sort_values(['trip_id', 'stop_sequence']).groupby('trip_id').agg( 56 | {on: lambda x: list(x)} 57 | ).rename(columns={on: 'stops'}) 58 | 59 | return trip_stops 60 | 61 | 62 | def get_trip_footprints(feed, on='stop_id'): 63 | """ 64 | Build each trip's footprint. 65 | The footprint is a String that will be used to derive the trip 66 | patterns: it must allow to identify trips that will be grouped 67 | and to distinguish trips that will not. Here we use the ordered 68 | list of stops or clusters to build each trip footprint. 69 | """ 70 | trip_stops = get_trip_stop_list(feed.stop_times, feed.stops, on=on) 71 | trip_footprints = trip_stops.rename(columns={'stops': 'footprint'}) 72 | trip_footprints['footprint'] = trip_footprints['footprint'].map(str) 73 | return trip_footprints 74 | 75 | 76 | def get_patterns(trips, trip_footprints, group=['route_id']): # we can add direction, it can also be on route_short_name, … 77 | patterns = trip_footprints.copy() 78 | patterns = patterns.merge( 79 | trips.set_index('trip_id')[group], 80 | left_index=True, 81 | right_index=True 82 | ) 83 | pattern_n = patterns.drop_duplicates().set_index(['footprint'] + group).groupby( 84 | group, 85 | as_index=False 86 | ).cumcount() 87 | pattern_n.name = 'pattern_num' 88 | patterns = patterns.reset_index().merge( 89 | pattern_n, 90 | on=['footprint'] + group 91 | ) 92 | patterns['pattern_id'] = patterns[group + ['pattern_num']].apply( 93 | lambda x: '_'.join(x.map(str)), 1 94 | ) 95 | return patterns 96 | -------------------------------------------------------------------------------- /.vscode/.ropeproject/config.py: -------------------------------------------------------------------------------- 1 | # The default ``config.py`` 2 | 3 | 4 | def set_prefs(prefs): 5 | """This function is called before opening the project""" 6 | 7 | # Specify which files and folders to ignore in the project. 8 | # Changes to ignored resources are not added to the history and 9 | # VCSs. Also they are not returned in `Project.get_files()`. 10 | # Note that ``?`` and ``*`` match all characters but slashes. 11 | # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' 12 | # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' 13 | # '.svn': matches 'pkg/.svn' and all of its children 14 | # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' 15 | # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' 16 | prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', 17 | '.hg', '.svn', '_svn', '.git', 18 | '__pycache__'] 19 | 20 | # Specifies which files should be considered python files. It is 21 | # useful when you have scripts inside your project. Only files 22 | # ending with ``.py`` are considered to be python files by 23 | # default. 24 | # prefs['python_files'] = ['*.py'] 25 | 26 | # Custom source folders: By default rope searches the project 27 | # for finding source folders (folders that should be searched 28 | # for finding modules). You can add paths to that list. Note 29 | # that rope guesses project source folders correctly most of the 30 | # time; use this if you have any problems. 31 | # The folders should be relative to project root and use '/' for 32 | # separating folders regardless of the platform rope is running on. 33 | # 'src/my_source_folder' for instance. 34 | # prefs.add('source_folders', 'src') 35 | 36 | # You can extend python path for looking up modules 37 | # prefs.add('python_path', '~/python/') 38 | 39 | # Should rope save object information or not. 40 | prefs['save_objectdb'] = True 41 | prefs['compress_objectdb'] = False 42 | 43 | # If `True`, rope analyzes each module when it is being saved. 44 | prefs['automatic_soa'] = True 45 | # The depth of calls to follow in static object analysis 46 | prefs['soa_followed_calls'] = 0 47 | 48 | # If `False` when running modules or unit tests "dynamic object 49 | # analysis" is turned off. This makes them much faster. 50 | prefs['perform_doa'] = True 51 | 52 | # Rope can check the validity of its object DB when running. 53 | prefs['validate_objectdb'] = True 54 | 55 | # How many undos to hold? 56 | prefs['max_history_items'] = 32 57 | 58 | # Shows whether to save history across sessions. 59 | prefs['save_history'] = True 60 | prefs['compress_history'] = False 61 | 62 | # Set the number spaces used for indenting. According to 63 | # :PEP:`8`, it is best to use 4 spaces. Since most of rope's 64 | # unit-tests use 4 spaces it is more reliable, too. 65 | prefs['indent_size'] = 4 66 | 67 | # Builtin and c-extension modules that are allowed to be imported 68 | # and inspected by rope. 69 | prefs['extension_modules'] = [] 70 | 71 | # Add all standard c-extensions to extension_modules list. 72 | prefs['import_dynload_stdmods'] = True 73 | 74 | # If `True` modules with syntax errors are considered to be empty. 75 | # The default value is `False`; When `False` syntax errors raise 76 | # `rope.base.exceptions.ModuleSyntaxError` exception. 77 | prefs['ignore_syntax_errors'] = False 78 | 79 | # If `True`, rope ignores unresolvable imports. Otherwise, they 80 | # appear in the importing namespace. 81 | prefs['ignore_bad_imports'] = False 82 | 83 | 84 | def project_opened(project): 85 | """This function is called after opening the project""" 86 | # Do whatever you like here! 87 | -------------------------------------------------------------------------------- /syspy/pycube/application.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import os 3 | import shutil 4 | 5 | 6 | class File: 7 | def __init__(self, soup): 8 | self.soup = soup 9 | self.soup_chunks = soup.split('\n') 10 | 11 | def __repr__(self): 12 | self.makesoup() 13 | return(self.soup) 14 | 15 | def makesoup(self): 16 | self.soup = '\n'.join([chunk for chunk in self.soup_chunks]) 17 | 18 | 19 | class Preface: 20 | def __init__(self, soup): 21 | self.soup = soup 22 | self.soup_chunks = soup.split('\n') 23 | 24 | def __repr__(self): 25 | self.makesoup() 26 | return(self.soup) 27 | 28 | def makesoup(self): 29 | self.soup = '\n'.join([chunk for chunk in self.soup_chunks]) 30 | 31 | 32 | class Program: 33 | 34 | def __init__(self, soup): 35 | self.soup = soup 36 | self.parse() 37 | 38 | def parse(self): 39 | self.preface = Preface(self.soup.split('#')[0]) 40 | self.infiles = [File('#INFIL' + chunk) for chunk in self.soup.split('#OUTFIL')[0].split('#INFIL')[1:]] 41 | self.outfiles = [File('#OUTFIL' + chunk) for chunk in self.soup.split('#OUTFIL')[1:]] 42 | self.files = self.infiles + self.outfiles 43 | 44 | def __repr__(self): 45 | self.makesoup() 46 | return self.soup 47 | 48 | def makesoup(self): 49 | self.soup = str(self.preface) + ''.join([str(file) for file in self.files]) 50 | 51 | 52 | class Application: 53 | 54 | ''' 55 | Contient toutes les informations caractéristiques d'une application 56 | ''' 57 | 58 | def __init__(self, file_name, copy=False): 59 | self.file_name = file_name 60 | self.duplicata = file_name.split('.')[0] + '_duplicata_deleteme.' + file_name.split('.')[1] 61 | if copy: 62 | if not os.path.isfile(self.duplicata): 63 | shutil.copyfile(file_name, self.duplicata) 64 | print('copy') 65 | self.file = open(self.file_name, 'r') 66 | self.soup = self.file.read() 67 | self.file.close() 68 | self.eatsoup() 69 | 70 | def makesoup(self): 71 | self.soup = str(self.preface) + ''.join(['#PROGRAM' + str(program) for program in self.programs]) 72 | 73 | def eatsoup(self): 74 | self.preface = Preface(self.soup.split('#PROGRAM')[0]) 75 | self.programs = [Program(chunk) for chunk in self.soup.split('#PROGRAM')][1:] 76 | 77 | def __repr__(self): 78 | self.makesoup() 79 | return self.soup 80 | 81 | def dump(self): 82 | self.makesoup() 83 | self.file = open(self.file_name, 'w') 84 | self.file.write(self.soup) 85 | self.file.close() 86 | 87 | def addprogram(self, program): 88 | prog = copy.deepcopy(program) 89 | prog_id = len(self.programs) 90 | prog.preface.soup_chunks[0] = str(prog_id) # on indique un id du programme qui suit ceux existants 91 | prog.preface.soup_chunks[3] = str(0) # on fixe la priorité à 0 92 | prog.makesoup() 93 | self.programs.append(prog.soup) 94 | 95 | def addprograms(self, app): 96 | for program in app.programs: 97 | if 'addprograms' in program.preface.soup_chunks[12]: 98 | self.addprogram(program) 99 | 100 | def sortprograms(self): 101 | priority_zero_id = len(self.programs) 102 | for program in self.programs: 103 | if program.preface.soup_chunks[3]: # si la priorité du programme est non nulle, on l'utilise pour numéroter le programme. 104 | program.preface.soup_chunks[0] = program.preface.soup_chunks[3] 105 | else: 106 | priority_zero_id += 1 107 | program.preface.soup_chunks[0] = priority_zero_id 108 | self.makesoup() 109 | -------------------------------------------------------------------------------- /syspy/io/pandasdbf/pandasdbf.py: -------------------------------------------------------------------------------- 1 | __author__ = 'qchasserieau' 2 | 3 | import os 4 | import pandas as pd 5 | from syspy.io.pandasdbf import exceltodbf_qc 6 | 7 | 8 | def read_dbf(path, encoding='utf-8'): 9 | """ 10 | read a .dbf file, temporary write it as a csv and return a pandas.core.frame.DataFrame object. 11 | 12 | :param path: The complete path to the .dbf to read 13 | :type path: str 14 | :param encoding: The codec to use when decoding text-based records 15 | :type encoding: str 16 | :return: a pandas.DataFrame corresponding to the .dbf file 17 | :rtype: pandas.core.frame.DataFrame 18 | 19 | .. warnings:: not all encodings are handled by this function 20 | """ 21 | from simpledbf import Dbf5 22 | dbf_instance = Dbf5(path, codec=encoding) 23 | csv_name = path[:-4] + '_from_dbf' + '.csv' 24 | 25 | # clear the folder from the temporary csv if necessary 26 | if os.path.isfile(csv_name): 27 | os.remove(csv_name) 28 | 29 | dbf_instance.to_csv(csv_name) 30 | df = pd.read_csv(csv_name, sep=',', encoding='Latin-1', na_values='None') 31 | os.remove(csv_name) 32 | return df 33 | 34 | 35 | def write_dbf(df, path, pre_process=True, encoding='cp850'): 36 | 37 | """ 38 | write a .dbf from a pandas.core.frame.DataFrame object 39 | 40 | :param df: the DataFrame to write as a dbf 41 | :param path: The complete path to the .dbf to write 42 | :param pre_process: pre-process df with convert_stringy_things_to_string if True 43 | 44 | :type df: pandas.core.frame.DataFrame 45 | :type path: str 46 | :type pre_process: bool 47 | 48 | :return: None 49 | :rtype: NoneType 50 | 51 | .. warnings:: the length of the .dbf file cannot exceed 1 000 000 lines 52 | """ 53 | 54 | inner_df = convert_stringy_things_to_string(df.copy())if pre_process else df.copy() 55 | xlsx_name = path.split('.')[0] + '_from_df' + '.xlsx' # temporary file name 56 | inner_df.to_excel(xlsx_name, index=False) # write index as a regular column. 57 | exceltodbf_qc.exceltodbf(xlsx_name, path, encoding=encoding) 58 | os.remove(xlsx_name) 59 | 60 | 61 | def normalize(frame): 62 | df = frame.copy().astype(float) 63 | for column in df.columns: 64 | weight = df[column].interpolate().sum() 65 | df[column] = df[column].interpolate() / weight 66 | return df 67 | 68 | 69 | def convert_bytes_to_string(df, debug=False, encoding='utf-8'): 70 | """ 71 | returns a pandas.core.frame.DataFrame where all bytes columns are converted to string 72 | 73 | :param df: the DataFrame to convert 74 | :type df: pandas.core.frame.DataFrame 75 | :return: inner_df 76 | :rtype: pandas.core.frame.DataFrame 77 | """ 78 | inner_df = df.copy() 79 | bytes_columns = [column for column in inner_df.columns if type(inner_df[column].iloc[0]) in {bytes, str}] 80 | if debug: 81 | print('bytes_columns converted to string:' + str(bytes_columns)) 82 | for column in bytes_columns: 83 | try: 84 | inner_df[column] = inner_df[column].apply(to_str, args={encoding}) 85 | except AttributeError: 86 | print('fail: column:', column) 87 | pass 88 | return inner_df 89 | 90 | 91 | def to_str(bor, encoding): 92 | if type(bor) == str: 93 | return bor 94 | else: 95 | return bor.decode(encoding=encoding, errors='strict') 96 | 97 | 98 | def convert_stringy_things_to_string(df, debug=False): 99 | """ 100 | returns a pandas.core.frame.DataFrame where all bytes columns are converted to string 101 | 102 | :param df: the DataFrame to convert 103 | :type df: pandas.core.frame.DataFrame 104 | :return: inner_df 105 | :rtype: pandas.core.frame.DataFrame 106 | """ 107 | inner_df = convert_bytes_to_string(df).copy() 108 | stringy_columns = [column for column in inner_df.columns if type(inner_df[column].iloc[0]) == str] 109 | if debug: 110 | print('stringy_columns converted to string:' + str(stringy_columns)) 111 | inner_df[stringy_columns] = inner_df[stringy_columns].astype(str) 112 | return inner_df 113 | 114 | 115 | def clean_dbf(path): 116 | write_dbf(read_dbf(path), path, pre_process=True) 117 | --------------------------------------------------------------------------------