5
5
6
6
import matplotlib .figure
7
7
import matplotlib .pyplot as plt
8
+ import numpy as np
8
9
import pandas as pd
9
10
10
11
from conflowgen .analyses .container_flow_by_vehicle_instance_analysis import ContainerFlowByVehicleInstanceAnalysis
11
- from conflowgen .descriptive_datatypes import VehicleIdentifier , FlowDirection
12
12
from conflowgen .domain_models .data_types .mode_of_transport import ModeOfTransport
13
13
from conflowgen .reporting import AbstractReportWithMatplotlib
14
14
from conflowgen .reporting .no_data_plot import no_data_graph
@@ -35,10 +35,15 @@ def __init__(self):
35
35
self .analysis = ContainerFlowByVehicleInstanceAnalysis ()
36
36
37
37
def get_report_as_text (
38
- self , ** kwargs
38
+ self ,
39
+ vehicle_types : ModeOfTransport | str | typing .Collection = "scheduled vehicles" ,
40
+ ** kwargs
39
41
) -> str :
40
42
"""
41
43
Keyword Args:
44
+ vehicle_types (typing.Collection[ModeOfTransport]): A collection of vehicle types, e.g., passed as a
45
+ :class:`list` or :class:`set`.
46
+ Only the vehicles that correspond to the provided vehicle type(s) are considered in the analysis.
42
47
start_date (datetime.datetime): The earliest arriving container that is included.
43
48
Consider all containers if :obj:`None`.
44
49
end_date (datetime.datetime): The latest departing container that is included.
@@ -47,38 +52,39 @@ def get_report_as_text(
47
52
Returns:
48
53
The report in human-readable text format
49
54
"""
50
- container_flow = self ._get_analysis (kwargs )
55
+ plain_table , vehicle_types = self ._get_analysis (kwargs )
51
56
52
- report = "(pending)"
57
+ if len (plain_table ) > 0 :
58
+ df = self ._get_dataframe_from_plain_table (plain_table )
59
+ report = str (df )
60
+ else :
61
+ report = "(no report feasible because no data is available)"
53
62
54
- # create string representation
55
63
return report
56
64
57
- def _get_analysis (self , kwargs : dict ) -> typing .Dict [
58
- ModeOfTransport , typing .Dict [VehicleIdentifier , typing .Dict [FlowDirection , (int , int )]]
59
- ]:
65
+ def _get_analysis (self , kwargs : dict ) -> (list , list ):
60
66
start_date = kwargs .pop ("start_date" , None )
61
67
end_date = kwargs .pop ("end_date" , None )
68
+ vehicle_types = kwargs .pop ("vehicle_types" , (
69
+ ModeOfTransport .train ,
70
+ ModeOfTransport .feeder ,
71
+ ModeOfTransport .deep_sea_vessel ,
72
+ ModeOfTransport .barge
73
+ ))
74
+
62
75
assert len (kwargs ) == 0 , f"Keyword(s) { kwargs .keys ()} have not been processed"
63
76
64
77
container_flow = self .analysis .get_container_flow_by_vehicle (
78
+ vehicle_types = vehicle_types ,
65
79
start_date = start_date ,
66
- end_date = end_date
80
+ end_date = end_date ,
67
81
)
68
- return container_flow
69
-
70
- def get_report_as_graph (self , ** kwargs ) -> matplotlib .figure .Figure :
71
- """
72
- Visualize the container flows (import, export, transshipment) over time.
73
82
74
- Returns:
75
- The diagram.
76
- """
77
- container_flow = self ._get_analysis (kwargs )
83
+ vehicle_types = list (container_flow .keys ())
78
84
79
85
plain_table = []
80
86
81
- for mode_of_transport in ( set ( container_flow . keys ()) - set ([ ModeOfTransport . truck ])) :
87
+ for mode_of_transport in vehicle_types :
82
88
for vehicle_identifier in container_flow [mode_of_transport ].keys ():
83
89
for flow_direction in container_flow [mode_of_transport ][vehicle_identifier ]:
84
90
for journey_direction in container_flow [mode_of_transport ][vehicle_identifier ][flow_direction ]:
@@ -91,35 +97,59 @@ def get_report_as_graph(self, **kwargs) -> matplotlib.figure.Figure:
91
97
str (flow_direction ), journey_direction , handled_volume )
92
98
)
93
99
100
+ return plain_table , vehicle_types
101
+
102
+ def get_report_as_graph (self , ** kwargs ) -> matplotlib .figure .Figure :
103
+ """
104
+ Keyword Args:
105
+ vehicle_types (typing.Collection[ModeOfTransport]): A collection of vehicle types, e.g., passed as a
106
+ :class:`list` or :class:`set`.
107
+ Only the vehicles that correspond to the provided vehicle type(s) are considered in the analysis.
108
+ start_date (datetime.datetime):
109
+ The earliest arriving container that is included. Consider all containers if :obj:`None`.
110
+ end_date (datetime.datetime):
111
+ The latest departing container that is included. Consider all containers if :obj:`None`.
112
+
113
+ Returns:
114
+ Grouped by vehicle type and vehicle instance, how many import, export, and transshipment containers are
115
+ unloaded and loaded (measured in TEU).
116
+ """
117
+ plain_table , vehicle_types = self ._get_analysis (kwargs )
118
+
94
119
plot_title = "Container Flow By Vehicle Instance Analysis Report"
95
120
96
121
if len (plain_table ) == 0 :
97
122
fig , ax = no_data_graph ()
98
123
ax .set_title (plot_title )
99
124
return fig
100
125
101
- column_names = ("mode_of_transport" , "vehicle_id" , "vehicle_name" , "service_name" , "vehicle_arrival_time" ,
102
- "flow_direction" , "journey_direction" , "handled_volume" )
103
-
104
- df = pd .DataFrame (plain_table )
105
- df .columns = column_names
106
- df .set_index ("vehicle_arrival_time" , inplace = True )
107
-
108
- self ._df = df
126
+ df = self ._get_dataframe_from_plain_table (plain_table )
109
127
110
- fig , axes = plt .subplots (nrows = 2 * (len (ModeOfTransport ) - 1 ), figsize = (7 , 20 ))
128
+ number_subplots = 2 * len (vehicle_types )
129
+ fig , axes = plt .subplots (nrows = number_subplots , figsize = (7 , 4 * number_subplots ))
111
130
i = 0
112
- for mode_of_transport in ( set ( ModeOfTransport ) - set ([ ModeOfTransport . truck ])) :
131
+ for mode_of_transport in vehicle_types :
113
132
for journey_direction in ["inbound" , "outbound" ]:
114
133
ax = axes [i ]
115
134
i += 1
116
- ax .set_title (f"{ mode_of_transport } - { journey_direction } " )
135
+ ax .set_title (f"{ str ( mode_of_transport ). replace ( '_' , ' ' ). capitalize () } - { journey_direction } " )
117
136
df [(df ["mode_of_transport" ] == mode_of_transport )
118
137
& (df ["journey_direction" ] == journey_direction )
119
138
].groupby ("flow_direction" )["handled_volume" ].plot (ax = ax , linestyle = ":" , marker = "." )
139
+ ax .set_ylabel ("" )
120
140
121
141
plt .legend (loc = 'center left' , bbox_to_anchor = (1 , 0.5 ))
122
142
123
143
plt .tight_layout ()
124
144
125
145
return fig
146
+
147
+ def _get_dataframe_from_plain_table (self , plain_table ):
148
+ column_names = ("mode_of_transport" , "vehicle_id" , "vehicle_name" , "service_name" , "vehicle_arrival_time" ,
149
+ "flow_direction" , "journey_direction" , "handled_volume" )
150
+ df = pd .DataFrame (plain_table )
151
+ df .columns = column_names
152
+ df .set_index ("vehicle_arrival_time" , inplace = True )
153
+ df .replace (0 , np .nan , inplace = True )
154
+ self ._df = df
155
+ return df
0 commit comments