mijtsma3 commited on
Commit
667cfa6
·
1 Parent(s): 59f91c1

Improvements to the visualization

Browse files
Files changed (3) hide show
  1. app.py +72 -64
  2. bash_scopy.sh +36 -0
  3. src/viz.py +5 -4
app.py CHANGED
@@ -68,7 +68,7 @@ def parse_all_data(path):
68
  for subfolder in subfolders:
69
  data[subfolder] = {
70
  'wnd_action_trace': pd.read_csv(f'{path}/{subfolder}/actionTrace_Agent_PIC Blaze.csv'),
71
- 'all_action_trace': parse_action_trace(f'{path}/{subfolder}/actionTrace.csv', exclude),
72
  }
73
  data[subfolder]['aircraft_data'] = {}
74
  for file in os.listdir(f'{path}/{subfolder}'):
@@ -84,22 +84,22 @@ def parse_all_data(path):
84
  app.layout = html.Div([
85
  html.Div([
86
  html.Div([
87
- html.Div("Select the desired input conditions, then click 'Simulate!':", id='text1'),
88
  # html.Label("Contingency Time: "),
89
  # dcc.Input( id='cont-time', type='text', placeholder='Time at which the lost link event occurs (set to "ALONGTIMEAWAY" (no quotes) if no lost link event needs to occur)', style={'width': '80%'}),
90
  # html.Br(),
91
- html.Label("backgroundDivert: "),
92
  dcc.RadioItems(
93
  id='backgroundDivert',
94
  options=[
95
- {'label': 'Divert', 'value': 'True'},
96
- {'label': 'Continue', 'value': 'False'}
97
  ],
98
  value='True',
99
  labelStyle={'display': 'inline-block'}
100
  ),
101
  html.Br(),
102
- html.Label("Required certainty: A value that represents how high certainty needs to be before Blaze will make a decision."),
103
  html.Br(),
104
  dcc.Slider(
105
  id='IFthreshold',
@@ -113,7 +113,7 @@ app.layout = html.Div([
113
  # style={'width': '100%'}, # Set the width of the div containing the slider to 80% of the container
114
  # dcc.Input( id='IFthreshold', type='text', placeholder='A `double` which represents the interaction factor at which Blaze will make a decision.', style={'width': '80%'}),
115
  # html.Br(),
116
- html.Label("Time buffer: The time left before a decision must be made."),
117
  dcc.Slider(
118
  id='TAthreshold',
119
  min=10,
@@ -125,7 +125,7 @@ app.layout = html.Div([
125
  ),
126
  # dcc.Input( id='TAthreshold', type='text', placeholder='An `integer` which represents how much time needs to be left before Blaze makes a decision.', style={'width': '80%'}),
127
  # html.Br(),
128
- html.Label("Wait interval: How long to wait before the next update is made."),
129
  dcc.Slider(
130
  id='updateTime',
131
  min=20,
@@ -140,23 +140,38 @@ app.layout = html.Div([
140
  # html.Button('Simulate!', id='button', n_clicks=0),
141
  ], style={'width': '50%', 'border': '1px solid gray'}),
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  html.Div([
144
- html.Div("Next, input the relative path to your results folder, then click 'Submit'. This will load the data:", id='text2'),
145
- dcc.Input(
146
- id='path-input',
147
- # value='data',
148
- type='text',
149
- placeholder='Type your path... For example, ../wmc5.1/Scenario/AAMv2/Results',
150
- style={'width': '70%'} # Make the input wider
 
151
  ),
152
- html.Button('Submit', id='submit-button', n_clicks=0),
153
- # Create a dropdown menu with the subfolders as options
154
- # html.Div("Once all subfolders are loaded (representing the different conditions you ran in WMC), you can select which one to plot:", id='text2'),
155
- # dcc.Dropdown(
156
- # id='subfolder-dropdown',
157
- # value=None #subfolders[0] # Default value
158
- # )
159
- ], style={'width': '50%', 'border': '1px solid gray'}),
160
  ], style={'display': 'flex'}),
161
 
162
  html.Div([
@@ -165,7 +180,7 @@ app.layout = html.Div([
165
  dcc.Dropdown(
166
  id='variable-dropdown',
167
  # options=[{'label': i, 'value': i} for i in subfolders],
168
- value=None #subfolders[0] # Default value
169
  ),
170
  dcc.Graph(id='altitude-series') # Third graph
171
  ], style={'width': '39%', 'display': 'inline-block', 'border': '1px solid gray'}),
@@ -174,18 +189,6 @@ app.layout = html.Div([
174
  ], style={'width': '59%', 'display': 'inline-block', 'border': '1px solid gray'})
175
  ], style={'display': 'flex'}),
176
 
177
- html.Div(
178
- dcc.Slider(
179
- id='time-slider',
180
- min=start_time,
181
- max=end_time,
182
- value=start_time+100,
183
- marks={str(time): str(time) for time in range(start_time, end_time+1, 50)},
184
- updatemode='drag'
185
- ),
186
- style={'width': '100%'} # Set the width of the div containing the slider to 80% of the container
187
- )
188
-
189
  ])
190
 
191
  # @app.callback(
@@ -215,31 +218,31 @@ app.layout = html.Div([
215
  # return f"error!"
216
 
217
  # Load data when the app starts and store it in the hidden div
218
- @app.callback(
219
- # dash.dependencies.Output('subfolder-dropdown', 'options'),
220
- # dash.dependencies.Output('variable-dropdown', 'options'),
221
- dash.dependencies.Output('submit-button', 'n_clicks'), # Add this output to reset submit button clicks
222
- [dash.dependencies.Input('submit-button', 'n_clicks')],
223
- [dash.dependencies.Input('path-input', 'value')],
224
- )
225
- def load_data(n_clicks, selected_path):
226
- print("selected path is",selected_path)
227
- global data_store
228
-
229
- if n_clicks > 0:
230
- if selected_path is None or not os.path.isdir(selected_path):
231
- return [], []
232
- subfolder_labels, data = parse_all_data(selected_path)
233
- print('subfolders',subfolder_labels)
234
- if data is None:
235
- data = {}
236
- # Store data in the global dictionary
237
- data_store = data
238
- labels = list(data[list(data.keys())[0]]['aircraft_data'][list(data[list(data.keys())[0]]['aircraft_data'].keys())[0]].columns.tolist()) # Extracting column names for the first aircraft-specific dataframe
239
- return subfolder_labels, labels, 0
240
- else:
241
- # return [], [], 0
242
- return 0
243
 
244
 
245
  # Define the callback to update the graphs based on the slider value
@@ -247,6 +250,7 @@ def load_data(n_clicks, selected_path):
247
  dash.dependencies.Output('time-series', 'figure'),
248
  dash.dependencies.Output('map', 'figure'),
249
  dash.dependencies.Output('altitude-series', 'figure'),
 
250
  # dash.dependencies.Output('timeline', 'figure'),
251
  # dash.dependencies.Input('path-input', 'value'),
252
  # [dash.dependencies.Input('subfolder-dropdown', 'value'),
@@ -269,9 +273,10 @@ def load_data(n_clicks, selected_path):
269
  def update_graph(selected_time, selected_variable, backgroundDivert, RequiredCertainty, TimeBuffer, WaitInterval): #selected_subfolder,
270
 
271
  selected_subfolder = "exampleTime=200"+backgroundDivert+"_"+str(RequiredCertainty)+"_"+str(TimeBuffer)+"_"+str(WaitInterval)
272
-
273
  if selected_subfolder not in data_store:
274
- return go.Figure(), go.Figure(), go.Figure(layout=dict(autosize=True, width=None, height=300))#, go.Figure()
 
275
 
276
  wnd_action_trace = data_store[selected_subfolder].get('wnd_action_trace', pd.DataFrame())
277
  all_action_trace = data_store[selected_subfolder].get('all_action_trace', [])
@@ -314,11 +319,14 @@ def update_graph(selected_time, selected_variable, backgroundDivert, RequiredCer
314
  # fig4 = viz.timeline(fig4, filtered_all_action_trace, selected_time, start_date, end_date)
315
  # fig4['layout']['uirevision'] = 'Hello world!'
316
 
317
- return fig2, fig1, fig3#, fig4
318
 
319
  # Run the app
320
  if __name__ == '__main__':
321
 
 
 
 
322
  # webbrowser.open_new("http://127.0.0.1:8050/")
323
  # app.run_server(debug=True)
324
  app.run_server(debug=True, host='0.0.0.0', port=7860)
 
68
  for subfolder in subfolders:
69
  data[subfolder] = {
70
  'wnd_action_trace': pd.read_csv(f'{path}/{subfolder}/actionTrace_Agent_PIC Blaze.csv'),
71
+ # 'all_action_trace': parse_action_trace(f'{path}/{subfolder}/actionTrace.csv', exclude),
72
  }
73
  data[subfolder]['aircraft_data'] = {}
74
  for file in os.listdir(f'{path}/{subfolder}'):
 
84
  app.layout = html.Div([
85
  html.Div([
86
  html.Div([
87
+ html.Div("Select the desired input conditions and see how the strategy on the What's Next Diagram changes:", id='text1'),
88
  # html.Label("Contingency Time: "),
89
  # dcc.Input( id='cont-time', type='text', placeholder='Time at which the lost link event occurs (set to "ALONGTIMEAWAY" (no quotes) if no lost link event needs to occur)', style={'width': '80%'}),
90
  # html.Br(),
91
+ html.Label("What is the behavior of Unmanned Aerial Vehicle when a lost link is detected?"),
92
  dcc.RadioItems(
93
  id='backgroundDivert',
94
  options=[
95
+ {'label': 'Divert to nearest vertiport', 'value': 'True'},
96
+ {'label': 'Continue to fly along its approved route', 'value': 'False'}
97
  ],
98
  value='True',
99
  labelStyle={'display': 'inline-block'}
100
  ),
101
  html.Br(),
102
+ html.Label("Required certainty: A value that represents how certain the pilot of Blaze needs to be about what's next before they make a decision."),
103
  html.Br(),
104
  dcc.Slider(
105
  id='IFthreshold',
 
113
  # style={'width': '100%'}, # Set the width of the div containing the slider to 80% of the container
114
  # dcc.Input( id='IFthreshold', type='text', placeholder='A `double` which represents the interaction factor at which Blaze will make a decision.', style={'width': '80%'}),
115
  # html.Br(),
116
+ html.Label("Time buffer: How many seconds before the Blazes `point of no return` should Blaze make decision, even if not quite certain about what's next?"),
117
  dcc.Slider(
118
  id='TAthreshold',
119
  min=10,
 
125
  ),
126
  # dcc.Input( id='TAthreshold', type='text', placeholder='An `integer` which represents how much time needs to be left before Blaze makes a decision.', style={'width': '80%'}),
127
  # html.Br(),
128
+ html.Label("Wait interval: How often should Blaze receive new information and revise projections?"),
129
  dcc.Slider(
130
  id='updateTime',
131
  min=20,
 
140
  # html.Button('Simulate!', id='button', n_clicks=0),
141
  ], style={'width': '50%', 'border': '1px solid gray'}),
142
 
143
+ # html.Div([
144
+ # html.Div("Next, input the relative path to your results folder, then click 'Submit'. This will load the data:", id='text2'),
145
+ # dcc.Input(
146
+ # id='path-input',
147
+ # # value='data',
148
+ # type='text',
149
+ # placeholder='Type your path... For example, ../wmc5.1/Scenario/AAMv2/Results',
150
+ # style={'width': '70%'} # Make the input wider
151
+ # ),
152
+ # html.Button('Submit', id='submit-button', n_clicks=0),
153
+ # # Create a dropdown menu with the subfolders as options
154
+ # # html.Div("Once all subfolders are loaded (representing the different conditions you ran in WMC), you can select which one to plot:", id='text2'),
155
+ # # dcc.Dropdown(
156
+ # # id='subfolder-dropdown',
157
+ # # value=None #subfolders[0] # Default value
158
+ # # )
159
+ # ], style={'width': '50%', 'border': '1px solid gray'}),
160
+
161
  html.Div([
162
+ html.Label("Use the slider to move through time."),
163
+ dcc.Slider(
164
+ id='time-slider',
165
+ min=start_time,
166
+ max=end_time,
167
+ value=start_time+100,
168
+ marks={str(time): str(time) for time in range(start_time, end_time+1, 50)},
169
+ updatemode='drag'
170
  ),
171
+ # style={'width': '100%'} # Set the width of the div containing the slider to 80% of the container
172
+ ], style={'width': '50%', 'border': '1px solid gray'}
173
+ )
174
+
 
 
 
 
175
  ], style={'display': 'flex'}),
176
 
177
  html.Div([
 
180
  dcc.Dropdown(
181
  id='variable-dropdown',
182
  # options=[{'label': i, 'value': i} for i in subfolders],
183
+ value='altitude_ft' #subfolders[0] # Default value
184
  ),
185
  dcc.Graph(id='altitude-series') # Third graph
186
  ], style={'width': '39%', 'display': 'inline-block', 'border': '1px solid gray'}),
 
189
  ], style={'width': '59%', 'display': 'inline-block', 'border': '1px solid gray'})
190
  ], style={'display': 'flex'}),
191
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  ])
193
 
194
  # @app.callback(
 
218
  # return f"error!"
219
 
220
  # Load data when the app starts and store it in the hidden div
221
+ # @app.callback(
222
+ # # dash.dependencies.Output('subfolder-dropdown', 'options'),
223
+ # # dash.dependencies.Output('variable-dropdown', 'options'),
224
+ # dash.dependencies.Output('submit-button', 'n_clicks'), # Add this output to reset submit button clicks
225
+ # [dash.dependencies.Input('submit-button', 'n_clicks')],
226
+ # [dash.dependencies.Input('path-input', 'value')],
227
+ # )
228
+ # def load_data(n_clicks, selected_path):
229
+ # print("selected path is",selected_path)
230
+ # global data_store
231
+
232
+ # if n_clicks > 0:
233
+ # if selected_path is None or not os.path.isdir(selected_path):
234
+ # return [], []
235
+ # subfolder_labels, data = parse_all_data(selected_path)
236
+ # print('subfolders',subfolder_labels)
237
+ # if data is None:
238
+ # data = {}
239
+ # # Store data in the global dictionary
240
+ # data_store = data
241
+ # labels = list(data[list(data.keys())[0]]['aircraft_data'][list(data[list(data.keys())[0]]['aircraft_data'].keys())[0]].columns.tolist()) # Extracting column names for the first aircraft-specific dataframe
242
+ # return 0
243
+ # else:
244
+ # # return [], [], 0
245
+ # return 0
246
 
247
 
248
  # Define the callback to update the graphs based on the slider value
 
250
  dash.dependencies.Output('time-series', 'figure'),
251
  dash.dependencies.Output('map', 'figure'),
252
  dash.dependencies.Output('altitude-series', 'figure'),
253
+ dash.dependencies.Output('variable-dropdown', 'options'),
254
  # dash.dependencies.Output('timeline', 'figure'),
255
  # dash.dependencies.Input('path-input', 'value'),
256
  # [dash.dependencies.Input('subfolder-dropdown', 'value'),
 
273
  def update_graph(selected_time, selected_variable, backgroundDivert, RequiredCertainty, TimeBuffer, WaitInterval): #selected_subfolder,
274
 
275
  selected_subfolder = "exampleTime=200"+backgroundDivert+"_"+str(RequiredCertainty)+"_"+str(TimeBuffer)+"_"+str(WaitInterval)
276
+ print(selected_subfolder)
277
  if selected_subfolder not in data_store:
278
+ print("Not found")
279
+ return go.Figure(), go.Figure(), go.Figure(layout=dict(autosize=True, width=None, height=300)), labels#, go.Figure()
280
 
281
  wnd_action_trace = data_store[selected_subfolder].get('wnd_action_trace', pd.DataFrame())
282
  all_action_trace = data_store[selected_subfolder].get('all_action_trace', [])
 
319
  # fig4 = viz.timeline(fig4, filtered_all_action_trace, selected_time, start_date, end_date)
320
  # fig4['layout']['uirevision'] = 'Hello world!'
321
 
322
+ return fig2, fig1, fig3, labels#, fig4
323
 
324
  # Run the app
325
  if __name__ == '__main__':
326
 
327
+ subfolder_labels, data_store = parse_all_data("Results")
328
+ labels = list(data_store[list(data_store.keys())[0]]['aircraft_data'][list(data_store[list(data_store.keys())[0]]['aircraft_data'].keys())[0]].columns.tolist()) # Extracting column names for the first aircraft-specific dataframe
329
+ print(subfolder_labels)
330
  # webbrowser.open_new("http://127.0.0.1:8050/")
331
  # app.run_server(debug=True)
332
  app.run_server(debug=True, host='0.0.0.0', port=7860)
bash_scopy.sh ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Source folder (replace with your actual source folder path)
4
+ SOURCE_FOLDER="Results/"
5
+
6
+ # Destination folder (replace with your actual destination folder path)
7
+ DEST_FOLDER="Simple_results"
8
+
9
+ # List of specific file names to copy (replace these with the actual file names)
10
+ FILES_TO_COPY=("actionTrace_Agent_PIC Blaze.csv" "GCCRaven_acstate.csv" "SNLBlaze_acstate.csv")
11
+
12
+ # Create the destination folder if it doesn't exist
13
+ mkdir -p "$DEST_FOLDER"
14
+
15
+ # Loop through each subfolder in the source folder
16
+ for SUBFOLDER in "$SOURCE_FOLDER"/*; do
17
+ if [ -d "$SUBFOLDER" ]; then
18
+ # Get the name of the subfolder
19
+ SUBFOLDER_NAME=$(basename "$SUBFOLDER")
20
+
21
+ # Create a corresponding subfolder in the destination folder
22
+ mkdir -p "$DEST_FOLDER/$SUBFOLDER_NAME"
23
+
24
+ # Copy the specific files if they exist in the subfolder
25
+ for FILENAME in "${FILES_TO_COPY[@]}"; do
26
+ SOURCE_FILE="$SUBFOLDER/$FILENAME"
27
+ if [ -f "$SOURCE_FILE" ]; then
28
+ cp "$SOURCE_FILE" "$DEST_FOLDER/$SUBFOLDER_NAME"
29
+ else
30
+ echo "File $FILENAME not found in $SUBFOLDER"
31
+ fi
32
+ done
33
+ fi
34
+ done
35
+
36
+ echo "Done! Specified files have been copied to the destination folder."
src/viz.py CHANGED
@@ -11,10 +11,10 @@ class Visualizer:
11
 
12
  def wnd_visualization(figure_handle, dataframe, current_time, start_time = 0, end_time = 10^6):
13
  # Diagonal line y=x
14
- figure_handle.add_trace(go.Scatter(x=[start_time, end_time], y=[start_time, end_time], mode='lines', line=dict(color='black', dash='dash')))
15
 
16
  # Dotted lines from the point to axes
17
- figure_handle.add_trace(go.Scatter(x=[current_time, current_time, start_time], y=[start_time, current_time, current_time], mode='lines', line=dict(color='black', dash='dot')))
18
 
19
  # Adding scatter points with hover text
20
  hover_text = [f"Time: {time}<br>Action: {name}" for time, name in dataframe[['time', 'actionName']].values]
@@ -24,7 +24,8 @@ class Visualizer:
24
  mode='markers',
25
  marker=dict(color='black', size=15),
26
  text=hover_text,
27
- hoverinfo='text'
 
28
  ))
29
 
30
  timestamps_and_ids_dict = {}
@@ -210,7 +211,7 @@ class Visualizer:
210
  lon=filtered_xdata,
211
  lat=filtered_ydata,
212
  line=dict(width=2, color=colors[color_index]),
213
- name=ac_name
214
  ))
215
 
216
  if len(filtered_xdata) > 0 and len(filtered_ydata) > 0:
 
11
 
12
  def wnd_visualization(figure_handle, dataframe, current_time, start_time = 0, end_time = 10^6):
13
  # Diagonal line y=x
14
+ figure_handle.add_trace(go.Scatter(x=[start_time, end_time], y=[start_time, end_time], mode='lines', line=dict(color='black', dash='dash'), showlegend=False))
15
 
16
  # Dotted lines from the point to axes
17
+ figure_handle.add_trace(go.Scatter(x=[current_time, current_time, start_time], y=[start_time, current_time, current_time], mode='lines', line=dict(color='black', dash='dot'), showlegend=False))
18
 
19
  # Adding scatter points with hover text
20
  hover_text = [f"Time: {time}<br>Action: {name}" for time, name in dataframe[['time', 'actionName']].values]
 
24
  mode='markers',
25
  marker=dict(color='black', size=15),
26
  text=hover_text,
27
+ hoverinfo='text',
28
+ name='Action'
29
  ))
30
 
31
  timestamps_and_ids_dict = {}
 
211
  lon=filtered_xdata,
212
  lat=filtered_ydata,
213
  line=dict(width=2, color=colors[color_index]),
214
+ name=ac_name + " Flight Path"
215
  ))
216
 
217
  if len(filtered_xdata) > 0 and len(filtered_ydata) > 0: