add_secondary_travel_matrix

site.SiteProblem.add_secondary_travel_matrix(
    travel_matrix_df,
    source_col,
    label,
    skip_cols=None,
    unit=None,
    from_unit=None,
    to_unit=None,
    threshold_for_coverage=None,
    allow_missing=False,
    treat_as_missing=None,
)

Register an additional travel/cost matrix for a different mode or scenario (e.g. public transport alongside a primary car matrix).

Unlike add_travel_matrix(), a secondary matrix is never used as the optimisation cost matrix – the primary matrix set via add_travel_matrix() always drives site selection and search/pruning. Instead, each registered secondary matrix contributes its own set of per-solution metric columns (suffixed __<label>, e.g. min_cost__public_transport, weighted_average__public_transport) into every solution solve() produces, so it can be used directly in plots, Metric(column=...), and post-hoc ranking (sort_by="max__public_transport") – without needing to .copy() the problem and solve it twice.

Post-hoc ranking reorders whatever solve() already returned, so it only reorders candidates that survived the primary matrix’s search and pruning. If brute_force_keep_best_n (or _worst_n) is set, candidates were discarded on primary-matrix performance before secondary metrics were ever considered – so a secondary ranking over what survives is not the true best solution for that mode. To search on a secondary matrix rather than merely re-sort by it, pass the column to solve(rank_on=...), which makes the pruning itself use that metric. Alternatively, retain every combination (no brute_force_keep_best_n/_worst_n) and use compute_pareto_front() to explore the trade-off across both matrices at once.

You may call this method multiple times with different labels to register as many secondary matrices as needed. Each one adds approximately the per-candidate cost of evaluating the primary matrix, so solve() time scales close to linearly with the number of secondary matrices registered. Under n_jobs > 1, every registered matrix’s aligned frame is pickled to each worker process alongside the problem, so peak memory also scales with matrix count.

Parameters

Name Type Description Default
travel_matrix_df pandas.DataFrame or geopandas.GeoDataFrame or str The dataset containing travel costs for this matrix, or a local or web path to its location. required
source_col str The column name in travel_matrix_df that identifies the origin points (should correspond to IDs in the demand data). required
label str A unique label identifying this matrix, used to suffix every metric column it produces (e.g. label="public_transport" -> min_cost__public_transport). Must be non-empty, must not contain "__", and must not already be registered. required
skip_cols list of str A list of column names to ignore during data loading. None
unit str A label for the units used in the matrix. Used if no conversion is performed. None
from_unit (seconds, minutes, hours) The current time unit of the numeric values in the dataframe. "seconds"
to_unit (seconds, minutes, hours) The target time unit for the numeric values in the dataframe. "seconds"
threshold_for_coverage float The coverage threshold to apply to this matrix specifically (e.g. 60 minutes for public transport vs 20 for car). If not provided, falls back to the threshold_for_coverage passed to solve() / evaluate_single_solution_single_objective(). None
allow_missing bool Whether to allow missing (NaN) travel costs – a demand location with no feasible journey to a given site. By default a missing value raises KeyError once solve() builds this matrix’s aligned frame (see Notes below); allow_missing=True treats it as genuinely unreachable instead, the same as add_travel_matrix(allow_missing=True). False
treat_as_missing scalar or callable An existing missing-data sentinel already baked into travel_matrix_df (e.g. 9999), converted to a proper missing value before anything else runs – see add_travel_matrix(treat_as_missing=...). None

Returns

Name Type Description
None

Raises

Name Type Description
ValueError If label is empty, contains "__", or has already been registered.
KeyError If source_col is missing from the provided dataframe.

Notes

Secondary matrices must be complete: every demand location and every candidate site must have a row/column, and (unless allow_missing= True) a non-missing value. This is validated when solve() builds the aligned per-solution frames (not here, since demand/sites may not yet be registered) – see solve() for the specific errors raised for missing rows or missing columns.

Back to top