from __future__ import annotations
from typing import Dict, Tuple
import matplotlib
import numpy as np
import pandas as pd
from conflowgen.previews.inbound_and_outbound_vehicle_capacity_preview import \
InboundAndOutboundVehicleCapacityPreview
from conflowgen.domain_models.data_types.mode_of_transport import ModeOfTransport
from conflowgen.reporting import AbstractReportWithMatplotlib
[docs]
class InboundAndOutboundVehicleCapacityPreviewReport(AbstractReportWithMatplotlib):
"""
This preview report takes the data structure as generated by
:class:`.InboundAndOutboundVehicleCapacityPreview`
and creates a comprehensible representation for the user, either as text or as a graph.
A similar report can be found at
:class:`.VehicleCapacityExceededPreviewReport`.
The visual and table are expected to approximately look like in the
`example InboundAndOutboundVehicleCapacityPreviewReport \
<notebooks/previews.ipynb#Inbound-And-Outbound-Vehicle-Capacity-Preview-Report>`_.
"""
report_description = """
This report previews the container flow in terms of transshipment share and modal split for the hinterland.
"""
def __init__(self):
super().__init__()
self._df = None
self.preview = InboundAndOutboundVehicleCapacityPreview(
self.start_date,
self.end_date,
self.transportation_buffer
)
def hypothesize_with_mode_of_transport_distribution(
self,
mode_of_transport_distribution: Dict[ModeOfTransport, Dict[ModeOfTransport, float]]
):
self.preview.hypothesize_with_mode_of_transport_distribution(mode_of_transport_distribution)
[docs]
def get_report_as_text(self, **kwargs) -> str:
assert len(kwargs) == 0, f"No keyword arguments supported for {self.__class__.__name__}"
inbound_capacities, outbound_average_capacities, outbound_maximum_capacities = self._get_capacities()
# create string representation
report = "\n"
report += "vehicle type "
report += "inbound volume (in TEU) "
report += "outbound avg volume (in TEU) "
report += "outbound max capacity (in TEU)"
report += "\n"
for vehicle_type in self.order_of_vehicle_types_in_report:
vehicle_type_as_text = str(vehicle_type).replace("_", " ")
max_capacities_repr = -1 if np.isnan(outbound_maximum_capacities[vehicle_type]) \
else outbound_maximum_capacities[vehicle_type]
report += f"{vehicle_type_as_text:<15} "
report += f"{inbound_capacities[vehicle_type]:>25.1f} "
report += f"{outbound_average_capacities[vehicle_type]:>30.1f} "
report += f"{max_capacities_repr:>30.1f}"
report += "\n"
report += "(rounding errors might exist)\n"
return report
[docs]
def get_report_as_graph(self, **kwargs) -> matplotlib.axis.Axis:
"""
The report as a graph is represented as a bar chart using pandas.
Returns:
The matplotlib axis of the bar chart.
"""
assert len(kwargs) == 0, f"No keyword arguments supported for {self.__class__.__name__}"
inbound_capacities, outbound_average_capacities, outbound_maximum_capacities = self._get_capacities()
self._df = pd.DataFrame({
"inbound volume": inbound_capacities,
"outbound average volume": outbound_average_capacities,
"outbound maximum capacity": outbound_maximum_capacities
})
self._df.index = [str(i).replace("_", " ") for i in self._df.index]
ax = self._df.plot.barh()
ax.set_xlabel("Container volume (in TEU)")
ax.set_title("Inbound and outbound vehicle capacity preview")
return ax
def _get_capacities(
self
) -> Tuple[dict[ModeOfTransport, float], dict[ModeOfTransport, float], dict[ModeOfTransport, float]]:
assert self.start_date is not None
assert self.end_date is not None
assert self.transportation_buffer is not None
self.preview.update(
start_date=self.start_date,
end_date=self.end_date,
transportation_buffer=self.transportation_buffer
)
# gather data
inbound_capacities = self.preview.get_inbound_capacity_of_vehicles().teu
capacities = self.preview.get_outbound_capacity_of_vehicles()
outbound_average_capacities, outbound_maximum_capacities = capacities.used.teu, capacities.maximum.teu
return inbound_capacities, outbound_average_capacities, outbound_maximum_capacities