-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ContainerFlowByVehicleInstanceAnalysis and its report incl. docs,…
… fix name of OutboundToInboundVehicleCapacityUtilizationAnalysis and its report
- Loading branch information
Showing
14 changed files
with
280 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
conflowgen/analyses/container_flow_by_vehicle_instance_analysis.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
from __future__ import annotations | ||
|
||
import datetime | ||
import typing | ||
|
||
from conflowgen.data_summaries.data_summaries_cache import DataSummariesCache | ||
from conflowgen.domain_models.container import Container | ||
from conflowgen.domain_models.data_types.mode_of_transport import ModeOfTransport | ||
from conflowgen.analyses.abstract_analysis import AbstractAnalysis | ||
from conflowgen.descriptive_datatypes import VehicleIdentifier, FlowDirection | ||
|
||
|
||
class ContainerFlowByVehicleInstanceAnalysis(AbstractAnalysis): | ||
""" | ||
This analysis can be run after the synthetic data has been generated. | ||
The analysis returns a data structure that can be used for generating reports (e.g., in text or as a figure) | ||
as it is the case with :class:`.ContainerFlowByVehicleInstanceAnalysisReport`. | ||
""" | ||
|
||
@staticmethod | ||
@DataSummariesCache.cache_result | ||
def get_container_flow_by_vehicle( | ||
start_date: typing.Optional[datetime.datetime] = None, | ||
end_date: typing.Optional[datetime.datetime] = None | ||
) -> typing.Dict[ | ||
ModeOfTransport, typing.Dict[VehicleIdentifier, typing.Dict[FlowDirection, (int, int)]] | ||
]: | ||
""" | ||
This shows for each of the vehicles | ||
Args: | ||
start_date: | ||
The earliest arriving container that is included. Consider all containers if :obj:`None`. | ||
end_date: | ||
The latest departing container that is included. Consider all containers if :obj:`None`. | ||
Returns: | ||
Grouped by vehicle type and vehicle instance, how much import, export, and transshipment is unloaded and | ||
loaded. | ||
""" | ||
container_flow_by_vehicle: typing.Dict[ | ||
ModeOfTransport, typing.Dict[VehicleIdentifier, | ||
typing.Dict[FlowDirection, typing.Dict[str, int]]]] = { | ||
vehicle_type: {} | ||
for vehicle_type in ModeOfTransport | ||
} | ||
|
||
vehicle_identifier_cache = {} | ||
|
||
container: Container | ||
for container in Container.select(): | ||
if start_date and container.get_arrival_time() < start_date: | ||
continue | ||
if end_date and container.get_departure_time() > end_date: | ||
continue | ||
|
||
if container.delivered_by_large_scheduled_vehicle is not None: # if not transported by truck | ||
|
||
if container.delivered_by_large_scheduled_vehicle not in vehicle_identifier_cache: | ||
vehicle_id_inbound = VehicleIdentifier( | ||
id=container.delivered_by_large_scheduled_vehicle.id, | ||
mode_of_transport=container.delivered_by, | ||
service_name=container.delivered_by_large_scheduled_vehicle.schedule.service_name, | ||
vehicle_name=container.delivered_by_large_scheduled_vehicle.vehicle_name, | ||
vehicle_arrival_time=container.get_arrival_time(), | ||
) | ||
vehicle_identifier_cache[container.delivered_by_large_scheduled_vehicle] = vehicle_id_inbound | ||
|
||
vehicle_id_inbound = vehicle_identifier_cache[container.delivered_by_large_scheduled_vehicle] | ||
|
||
if vehicle_id_inbound not in container_flow_by_vehicle[container.delivered_by]: | ||
container_flow_by_vehicle[container.delivered_by][vehicle_id_inbound] = { | ||
flow_direction: { | ||
"inbound": 0, | ||
"outbound": 0, | ||
} | ||
for flow_direction in FlowDirection | ||
} | ||
container_flow_by_vehicle[ | ||
container.delivered_by][vehicle_id_inbound][container.flow_direction]["inbound"] += 1 | ||
|
||
if container.picked_up_by_large_scheduled_vehicle is not None: # if not transported by truck | ||
|
||
if container.picked_up_by_large_scheduled_vehicle not in vehicle_identifier_cache: | ||
vehicle_id_outbound = VehicleIdentifier( | ||
id=container.picked_up_by_large_scheduled_vehicle.id, | ||
mode_of_transport=container.picked_up_by, | ||
service_name=container.picked_up_by_large_scheduled_vehicle.schedule.service_name, | ||
vehicle_name=container.picked_up_by_large_scheduled_vehicle.vehicle_name, | ||
vehicle_arrival_time=container.get_departure_time(), | ||
) | ||
vehicle_identifier_cache[container.picked_up_by_large_scheduled_vehicle] = vehicle_id_outbound | ||
|
||
vehicle_id_outbound = vehicle_identifier_cache[container.picked_up_by_large_scheduled_vehicle] | ||
|
||
if vehicle_id_outbound not in container_flow_by_vehicle[container.picked_up_by]: | ||
container_flow_by_vehicle[container.picked_up_by][vehicle_id_outbound] = { | ||
flow_direction: { | ||
"inbound": 0, | ||
"outbound": 0, | ||
} | ||
for flow_direction in FlowDirection | ||
} | ||
container_flow_by_vehicle[ | ||
container.picked_up_by][vehicle_id_outbound][container.flow_direction]["outbound"] += 1 | ||
|
||
return container_flow_by_vehicle |
125 changes: 125 additions & 0 deletions
125
conflowgen/analyses/container_flow_by_vehicle_instance_analysis_report.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
from __future__ import annotations | ||
|
||
import logging | ||
import typing | ||
|
||
import matplotlib.figure | ||
import matplotlib.pyplot as plt | ||
import pandas as pd | ||
|
||
from conflowgen.analyses.container_flow_by_vehicle_instance_analysis import ContainerFlowByVehicleInstanceAnalysis | ||
from conflowgen.descriptive_datatypes import VehicleIdentifier, FlowDirection | ||
from conflowgen.domain_models.data_types.mode_of_transport import ModeOfTransport | ||
from conflowgen.reporting import AbstractReportWithMatplotlib | ||
from conflowgen.reporting.no_data_plot import no_data_graph | ||
|
||
|
||
class ContainerFlowByVehicleInstanceAnalysisReport(AbstractReportWithMatplotlib): | ||
""" | ||
This analysis report takes the data structure as generated by :class:`.ContainerFlowByVehicleInstanceAnalysis` | ||
and creates a comprehensible representation for the user, either as text or as a graph. | ||
The visual and table are expected to approximately look like in the | ||
`example ContainerFlowByVehicleInstanceAnalysisReport \ | ||
<notebooks/analyses.ipynb#Container-Flow-By-Vehicle-Instance-Analysis-Report>`_. | ||
""" | ||
|
||
report_description = """ | ||
Analyze how many import, export, and transshipment containers were unloaded and loaded on each vehicle. | ||
""" | ||
|
||
logger = logging.getLogger("conflowgen") | ||
|
||
def __init__(self): | ||
super().__init__() | ||
self._df = None | ||
self.analysis = ContainerFlowByVehicleInstanceAnalysis() | ||
|
||
def get_report_as_text( | ||
self, **kwargs | ||
) -> str: | ||
""" | ||
Keyword Args: | ||
start_date (datetime.datetime): The earliest arriving container that is included. | ||
Consider all containers if :obj:`None`. | ||
end_date (datetime.datetime): The latest departing container that is included. | ||
Consider all containers if :obj:`None`. | ||
Returns: | ||
The report in human-readable text format | ||
""" | ||
container_flow = self._get_analysis(kwargs) | ||
|
||
report = "(pending)" | ||
|
||
# create string representation | ||
return report | ||
|
||
def _get_analysis(self, kwargs: dict) -> typing.Dict[ | ||
ModeOfTransport, typing.Dict[VehicleIdentifier, typing.Dict[FlowDirection, (int, int)]] | ||
]: | ||
start_date = kwargs.pop("start_date", None) | ||
end_date = kwargs.pop("end_date", None) | ||
assert len(kwargs) == 0, f"Keyword(s) {kwargs.keys()} have not been processed" | ||
|
||
container_flow = self.analysis.get_container_flow_by_vehicle( | ||
start_date=start_date, | ||
end_date=end_date | ||
) | ||
return container_flow | ||
|
||
def get_report_as_graph(self, **kwargs) -> matplotlib.figure.Figure: | ||
""" | ||
Visualize the container flows (import, export, transshipment) over time. | ||
Returns: | ||
The diagram. | ||
""" | ||
container_flow = self._get_analysis(kwargs) | ||
|
||
plain_table = [] | ||
|
||
for mode_of_transport in (set(container_flow.keys()) - set([ModeOfTransport.truck])): | ||
for vehicle_identifier in container_flow[mode_of_transport].keys(): | ||
for flow_direction in container_flow[mode_of_transport][vehicle_identifier]: | ||
for journey_direction in container_flow[mode_of_transport][vehicle_identifier][flow_direction]: | ||
handled_volume = container_flow[ | ||
mode_of_transport][vehicle_identifier][flow_direction][journey_direction] | ||
|
||
plain_table.append( | ||
(mode_of_transport, vehicle_identifier.id, vehicle_identifier.vehicle_name, | ||
vehicle_identifier.service_name, vehicle_identifier.vehicle_arrival_time, | ||
str(flow_direction), journey_direction, handled_volume) | ||
) | ||
|
||
plot_title = "Container Flow By Vehicle Instance Analysis Report" | ||
|
||
if len(plain_table) == 0: | ||
fig, ax = no_data_graph() | ||
ax.set_title(plot_title) | ||
return fig | ||
|
||
column_names = ("mode_of_transport", "vehicle_id", "vehicle_name", "service_name", "vehicle_arrival_time", | ||
"flow_direction", "journey_direction", "handled_volume") | ||
|
||
df = pd.DataFrame(plain_table) | ||
df.columns = column_names | ||
df.set_index("vehicle_arrival_time", inplace=True) | ||
|
||
self._df = df | ||
|
||
fig, axes = plt.subplots(nrows=2 * (len(ModeOfTransport) - 1), figsize=(7, 20)) | ||
i = 0 | ||
for mode_of_transport in (set(ModeOfTransport) - set([ModeOfTransport.truck])): | ||
for journey_direction in ["inbound", "outbound"]: | ||
ax = axes[i] | ||
i += 1 | ||
ax.set_title(f"{mode_of_transport} - {journey_direction}") | ||
df[(df["mode_of_transport"] == mode_of_transport) | ||
& (df["journey_direction"] == journey_direction) | ||
].groupby("flow_direction")["handled_volume"].plot(ax=ax, linestyle=":", marker=".") | ||
|
||
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5)) | ||
|
||
plt.tight_layout() | ||
|
||
return fig |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.