import pandas as pd
import plotly.express as px
from ambdes import Model, SimConfig, ambsys, Results, Runner
Run model for 100 minutes with log messages
TODO: Convert this into logging tests which compare patient results with record in the vidigi logger.
ambsys_data = ambsys(
csv_path= "data/AmbSYS-to-Mar-2026-UI7FG.csv" ,
org_code= "RYF" ,
month= "3" ,
year= 2026 ,
)
ambsys_data
{'mean_iat_min': {'C1': 5.02646098412341,
'C2': 1.042868823735545,
'C3': 2.4551754482455177,
'C4': 135.6838905775076},
'mean_handover_time_min': 29.916666666666668,
'p90_handover_time_min': 51.28333333333333,
'sd_handover_time_min': 11.385314934097805}
config = SimConfig(
ambsys_data= ambsys_data,
)
config.n_ambulances= 1
model = Model(run_number= 0 , config= config)
model.run()
log = model.logger.to_dataframe()
print (model.patients[0 ].__dict__)
log[log["entity_id" ] == 1 ]
{'patient_id': 1, 'category': 'C2', 'call_timestamp': 0.83753254853899, 'response_time': 4.073026530173381}
0
1
arrival_departure
arrival
0.837533
0
NaN
1
1
queue
ambulance_wait_begins
0.837533
0
NaN
2
1
resource_use
ambulance_arrives
0.837533
0
1.0
271
1
resource_use_end
ambulance_available
96.261361
0
1.0
272
1
arrival_departure
depart
96.261361
0
NaN
print (model.patients[1 ].__dict__)
log[log["entity_id" ] == 2 ]
{'patient_id': 2, 'category': 'C2', 'call_timestamp': 1.2359102250485265, 'response_time': None}
3
2
arrival_departure
arrival
1.235910
0
NaN
4
2
queue
ambulance_wait_begins
1.235910
0
NaN
273
2
resource_use
ambulance_arrives
96.261361
0
1.0
Run model for longer and inspect patient times
config = SimConfig(
ambsys_data= ambsys_data,
run_length= 10080 , # One week
)
model = Model(run_number= 0 , config= config)
model.run()
df = pd.DataFrame(
{
"response_time" : [p.response_time for p in model.patients],
"category" : [p.category for p in model.patients],
}
)
fig = px.histogram(
df,
x= "response_time" ,
facet_col= "category" ,
nbins= 50 ,
category_orders= {"category" : ["C1" , "C2" , "C3" , "C4" ]},
labels= {
"response_time" : "Response time (minutes)" ,
"category" : "Category" ,
},
title= "Distribution of response times by category" ,
)
# fig.update_yaxes(
# matches=None,
# showticklabels=True,
# )
fig.layout.yaxis.title.text = "Number of patients"
fig.show()
for cat in ["C1" , "C2" , "C3" , "C4" ]:
fig = px.histogram(
df[df["category" ] == cat],
x= "response_time" ,
nbins= 20 ,
title= f"Response times: { cat} " ,
labels= {"response_time" : "Response time (minutes)" },
)
fig.update_yaxes(title_text= "Number of patients" )
fig.show()
Average results
results = runner.run_reps()
0
0
1
C2
0.837533
4.073027
1
0
2
C2
1.235910
7.424848
2
0
3
C2
1.615698
3.004763
3
0
4
C2
2.167870
1.554013
4
0
5
C3
3.757094
7.215603
...
...
...
...
...
...
79223
4
15974
C2
10076.322889
NaN
79224
4
15975
C2
10076.676822
1.634170
79225
4
15976
C2
10076.729948
NaN
79226
4
15977
C2
10077.762373
0.346001
79227
4
15978
C3
10078.551056
NaN
79228 rows × 5 columns
0
C1
2016
10.043064
0
1
C2
9861
9.874453
0
2
C3
3956
9.786215
0
3
C4
76
9.607152
0
4
C1
2024
10.011695
1
5
C2
9570
9.819834
1
6
C3
4150
10.001758
1
7
C4
69
9.693440
1
8
C1
2027
10.179896
2
9
C2
9662
10.040621
2
10
C3
4122
9.891074
2
11
C4
84
10.730120
2
12
C1
2003
9.810804
3
13
C2
9621
9.895342
3
14
C3
3925
10.219530
3
15
C4
84
10.448439
3
16
C1
1997
9.739551
4
17
C2
9758
9.935218
4
18
C3
4136
10.249755
4
19
C4
87
11.583257
4
0
C1
2013.4
9.957002
1
C2
9694.4
9.913094
2
C3
4057.8
10.029666
3
C4
80.0
10.412481
config.n_ambulances = 1
config.run_length = 50_000
config.log_to_console = False
runner = Runner(config)
results = runner.run_single(run_number= 0 )
0
C1
10122
24882.128638
0
1
C2
47831
24981.944913
0
2
C3
20204
25145.029568
0
3
C4
392
33869.408274
0
results["patients" ].head(20 )
0
0
1
C2
0.837533
4.073027
1
0
2
C2
1.235910
102.450299
2
0
3
C2
1.615698
200.196118
3
0
4
C2
2.167870
306.023344
4
0
5
C3
3.757094
405.667583
5
0
6
C3
4.039516
522.338683
6
0
7
C2
5.075784
619.716820
7
0
8
C3
6.931662
745.773423
8
0
9
C2
7.120883
847.157297
9
0
10
C2
8.110538
949.657591
10
0
11
C3
12.243683
1038.956183
11
0
12
C2
12.455700
1166.599226
12
0
13
C2
13.068331
1274.419547
13
0
14
C3
13.186539
1381.522168
14
0
15
C3
14.411677
1514.495141
15
0
16
C3
15.247608
1641.393826
16
0
17
C2
15.976105
1735.483518
17
0
18
C1
16.554789
1870.729585
18
0
19
C3
17.581974
1967.770161
19
0
20
C2
18.574372
2064.439026
results["model" ].logger.to_dataframe().head(30 )
0
1
arrival_departure
arrival
0.837533
0
NaN
1
1
queue
ambulance_wait_begins
0.837533
0
NaN
2
1
resource_use
ambulance_arrives
0.837533
0
1.0
3
2
arrival_departure
arrival
1.235910
0
NaN
4
2
queue
ambulance_wait_begins
1.235910
0
NaN
5
3
arrival_departure
arrival
1.615698
0
NaN
6
3
queue
ambulance_wait_begins
1.615698
0
NaN
7
4
arrival_departure
arrival
2.167870
0
NaN
8
4
queue
ambulance_wait_begins
2.167870
0
NaN
9
5
arrival_departure
arrival
3.757094
0
NaN
10
5
queue
ambulance_wait_begins
3.757094
0
NaN
11
6
arrival_departure
arrival
4.039516
0
NaN
12
6
queue
ambulance_wait_begins
4.039516
0
NaN
13
7
arrival_departure
arrival
5.075784
0
NaN
14
7
queue
ambulance_wait_begins
5.075784
0
NaN
15
8
arrival_departure
arrival
6.931662
0
NaN
16
8
queue
ambulance_wait_begins
6.931662
0
NaN
17
9
arrival_departure
arrival
7.120883
0
NaN
18
9
queue
ambulance_wait_begins
7.120883
0
NaN
19
10
arrival_departure
arrival
8.110538
0
NaN
20
10
queue
ambulance_wait_begins
8.110538
0
NaN
21
11
arrival_departure
arrival
12.243683
0
NaN
22
11
queue
ambulance_wait_begins
12.243683
0
NaN
23
12
arrival_departure
arrival
12.455700
0
NaN
24
12
queue
ambulance_wait_begins
12.455700
0
NaN
25
13
arrival_departure
arrival
13.068331
0
NaN
26
13
queue
ambulance_wait_begins
13.068331
0
NaN
27
14
arrival_departure
arrival
13.186539
0
NaN
28
14
queue
ambulance_wait_begins
13.186539
0
NaN
29
15
arrival_departure
arrival
14.411677
0
NaN