flightplotting 0.2.7__tar.gz → 0.2.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. {flightplotting-0.2.7 → flightplotting-0.2.8}/PKG-INFO +1 -1
  2. flightplotting-0.2.8/flightplotting/plots.py +371 -0
  3. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting/traces.py +12 -13
  4. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting.egg-info/PKG-INFO +1 -1
  5. flightplotting-0.2.7/flightplotting/plots.py +0 -285
  6. {flightplotting-0.2.7 → flightplotting-0.2.8}/.github/workflows/publish_pypi.yml +0 -0
  7. {flightplotting-0.2.7 → flightplotting-0.2.8}/.gitignore +0 -0
  8. {flightplotting-0.2.7 → flightplotting-0.2.8}/.vscode/settings.json +0 -0
  9. {flightplotting-0.2.7 → flightplotting-0.2.8}/COPYING +0 -0
  10. {flightplotting-0.2.7 → flightplotting-0.2.8}/MANIFEST.in +0 -0
  11. {flightplotting-0.2.7 → flightplotting-0.2.8}/README.md +0 -0
  12. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting/__init__.py +0 -0
  13. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting/data/ColdDraftF3APlane.obj +0 -0
  14. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting/data/__init__.py +0 -0
  15. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting/model.py +0 -0
  16. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting/templates.py +0 -0
  17. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting/titlerenderer.py +0 -0
  18. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting.egg-info/SOURCES.txt +0 -0
  19. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting.egg-info/dependency_links.txt +0 -0
  20. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting.egg-info/requires.txt +0 -0
  21. {flightplotting-0.2.7 → flightplotting-0.2.8}/flightplotting.egg-info/top_level.txt +0 -0
  22. {flightplotting-0.2.7 → flightplotting-0.2.8}/pyproject.toml +0 -0
  23. {flightplotting-0.2.7 → flightplotting-0.2.8}/requirements.txt +0 -0
  24. {flightplotting-0.2.7 → flightplotting-0.2.8}/setup.cfg +0 -0
  25. {flightplotting-0.2.7 → flightplotting-0.2.8}/tests/__init__.py +0 -0
  26. {flightplotting-0.2.7 → flightplotting-0.2.8}/tests/data/__init__.py +0 -0
  27. {flightplotting-0.2.7 → flightplotting-0.2.8}/tests/data/p23_flight.json +0 -0
  28. {flightplotting-0.2.7 → flightplotting-0.2.8}/tests/test_plots.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flightplotting
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Tools for Plotting Flight Data in Plotly
5
5
  Author-email: Thomas David <thomasdavid0@gmail.com>
6
6
  License: GNU GPL v3
@@ -0,0 +1,371 @@
1
+ import plotly.graph_objects as go
2
+ from plotly.subplots import make_subplots
3
+ import plotly.express as px
4
+ import flightplotting.templates
5
+ from flightplotting.traces import (
6
+ tiptrace,
7
+ meshes,
8
+ control_input_trace,
9
+ axis_rate_trace,
10
+ aoa_trace,
11
+ cgtrace,
12
+ ribbon,
13
+ vectors,
14
+ axestrace,
15
+ )
16
+
17
+ from flightdata import State
18
+ from flightdata.base.labeling import get_appended_id
19
+ from geometry import Coord
20
+ from flightplotting.model import obj
21
+ import numpy.typing as npt
22
+ import numpy as np
23
+ import pandas as pd
24
+ from typing import List, Union
25
+
26
+
27
+ def plotsec(
28
+ secs: State | list[State] | dict[str, State],
29
+ scale=5,
30
+ nmodels=0,
31
+ fig=None,
32
+ color: Union[str, list[str]] = None,
33
+ cg=False,
34
+ width=None,
35
+ height=None,
36
+ show_axes=False,
37
+ ribb: bool = False,
38
+ tips: bool = True,
39
+ origin=False,
40
+ ):
41
+ traces = []
42
+ keys = None
43
+ if isinstance(secs, State):
44
+ secs = [secs]
45
+
46
+ if isinstance(secs, dict):
47
+ keys = list(secs.keys())
48
+ secs = list(secs.values())
49
+ showkeys = True
50
+ else:
51
+ keys = list(range(len(secs)))
52
+ showkeys = False
53
+
54
+ for i, sec in enumerate(secs):
55
+ text = sec.data.t - sec.data.t.iloc[0]
56
+ _color = color if color is not None else px.colors.qualitative.Plotly[i]
57
+ if ribb:
58
+ traces += ribbon(sec, scale * 1.85, _color, name=keys[i])
59
+ if tips:
60
+ traces += tiptrace(sec, scale * 1.85, text=text, name=keys[i])
61
+ if nmodels > 0:
62
+ traces += meshes(nmodels, sec, _color, scale)
63
+ if cg:
64
+ traces.append(cgtrace(sec, line=dict(color=_color, width=2), name=keys[i], text=text))
65
+
66
+ if origin:
67
+ traces += axestrace(Coord.zero(), 50)
68
+
69
+ if showkeys:
70
+ for i, key in enumerate(keys):
71
+ traces.append(
72
+ go.Scatter3d(
73
+ x=[],
74
+ y=[],
75
+ z=[],
76
+ mode="markers",
77
+ marker=dict(size=5, color=px.colors.qualitative.Plotly[i]),
78
+ name=key,
79
+ showlegend=True,
80
+ )
81
+ )
82
+
83
+ if fig is None:
84
+ fig = go.Figure(
85
+ data=traces,
86
+ layout=go.Layout(template="flight3d+judge_view", uirevision="foo"),
87
+ )
88
+ if show_axes:
89
+ fig.update_layout(
90
+ scene=dict(
91
+ aspectmode="data",
92
+ xaxis=dict(visible=True, showticklabels=True),
93
+ yaxis=dict(visible=True, showticklabels=True),
94
+ zaxis=dict(visible=True, showticklabels=True),
95
+ )
96
+ )
97
+ if width is not None:
98
+ fig.update_layout(width=width)
99
+ if height is not None:
100
+ fig.update_layout(height=height)
101
+ else:
102
+ fig.add_traces(traces)
103
+ return fig
104
+
105
+
106
+ def plotdtw(sec: State, manoeuvres: List[str], span=3, fig=None):
107
+ if fig is None:
108
+ fig = go.Figure(layout=go.Layout(template="flight3d+judge_view"))
109
+
110
+ traces = [] # tiptrace(sec, span)
111
+
112
+ for i, name in enumerate(manoeuvres):
113
+ try:
114
+ seg = sec.get_man_or_el(name)
115
+
116
+ traces += ribbon(seg, span, px.colors.qualitative.Alphabet[i], name)
117
+
118
+ traces.append(
119
+ go.Scatter3d(
120
+ x=seg.pos.x,
121
+ y=seg.pos.y,
122
+ z=seg.pos.z,
123
+ mode="lines",
124
+ line=dict(width=6, color=px.colors.qualitative.Alphabet[i]),
125
+ name=name,
126
+ )
127
+ )
128
+ except Exception as ex:
129
+ pass
130
+ print("no data for manoeuvre {}, {}".format(name, ex))
131
+
132
+ fig.add_traces(traces)
133
+
134
+ return fig
135
+
136
+
137
+ def plot_regions(
138
+ st: State, lab_cols: list[str], span=3, colours=None, fig=None, **kwargs
139
+ ):
140
+ colours = px.colors.qualitative.Plotly if colours is None else colours
141
+ lab_cols = [lab_cols] if isinstance(lab_cols, str) else lab_cols
142
+
143
+ st = st.label(clabs=st.cumulative_labels(*lab_cols))
144
+
145
+ colmap = {}
146
+
147
+ traces = []
148
+ for i, (k, seg) in enumerate(st.split_labels("clabs").items()):
149
+ if len(seg) < 3:
150
+ continue
151
+ blab, id = get_appended_id(k)
152
+ if blab not in colmap:
153
+ colmap[blab] = colours[len(colmap) % len(colours)]
154
+ traces += ribbon(
155
+ seg,
156
+ span,
157
+ colmap[blab],
158
+ name=blab,
159
+ showlegend=int(id) == 0,
160
+ **kwargs[blab] if blab in kwargs else {},
161
+ )
162
+ traces.append(
163
+ go.Scatter3d(
164
+ x=seg.pos.x,
165
+ y=seg.pos.y,
166
+ z=seg.pos.z,
167
+ mode="lines",
168
+ line=dict(width=0, color=colmap[blab]),
169
+ name=k,
170
+ showlegend=False,
171
+ )
172
+ )
173
+
174
+ if fig is None:
175
+ fig = go.Figure(layout=go.Layout(template="flight3d+judge_view"))
176
+ fig.add_traces(traces)
177
+ return fig
178
+
179
+
180
+ def create_3d_plot(traces):
181
+ return go.Figure(traces, layout=go.Layout(template="flight3d+judge_view"))
182
+
183
+
184
+ nb_layout = dict(
185
+ margin=dict(l=5, r=5, t=5, b=1),
186
+ legend=dict(yanchor="top", xanchor="left", x=0.8, y=0.99),
187
+ )
188
+
189
+
190
+ def control_brv_plot(sec, control_inputs=["aileron", "elevator", "rudder", "throttle"]):
191
+ """create a nice 2d plot showing control inputs and rotational velocities for a section"""
192
+ fig = make_subplots(specs=[[{"secondary_y": True}]])
193
+
194
+ fig.add_traces(axis_rate_trace(sec, dash="dash"), secondary_ys=np.full(3, False))
195
+
196
+ fig.add_traces(control_input_trace(sec), secondary_ys=[True for i in range(4)])
197
+
198
+ rvrng = np.ceil(np.degrees(sec.brvel.abs().max().max()) / 180) * 180
199
+ cirng = np.ceil(sec.data.loc[:, control_inputs].abs().max().max() / 50) * 50
200
+
201
+ fig.update_layout(
202
+ xaxis=dict(title="time, s"),
203
+ yaxis=dict(title="axis rate deg/s", range=(-rvrng, rvrng)),
204
+ yaxis2=dict(title="control pwm offset, ms", range=(-cirng, cirng)),
205
+ **nb_layout,
206
+ )
207
+ return fig
208
+
209
+
210
+ def aoa_brv_plot(sec):
211
+ """create a nice 2d plot showing rotational velocities and angle of attack for a section"""
212
+ fig = make_subplots(specs=[[{"secondary_y": True}]])
213
+ fig.add_traces(axis_rate_trace(sec), secondary_ys=np.full(3, False))
214
+ fig.add_traces(
215
+ aoa_trace(sec, colours=px.colors.qualitative.Plotly[4:]),
216
+ secondary_ys=np.full(2, True),
217
+ )
218
+ fig.update_layout(
219
+ xaxis=dict(title="Time (s)"),
220
+ yaxis=dict(title="Axis Rate (deg/s)"),
221
+ yaxis2=dict(title="Angle of Attack (deg)"),
222
+ **nb_layout,
223
+ )
224
+ return fig
225
+
226
+
227
+ def compare_3d(sec1, sec2):
228
+ fig = make_subplots(1, 2, specs=[[{"type": "scene"}, {"type": "scene"}]])
229
+ flowntr = plotsec(sec1, scale=2, nmodels=4).data
230
+ templtr = plotsec(sec2, scale=2, nmodels=4).data
231
+
232
+ fig.add_traces(
233
+ flowntr,
234
+ cols=[1 for i in range(len(flowntr))],
235
+ rows=[1 for i in range(len(flowntr))],
236
+ )
237
+ fig.add_traces(
238
+ templtr,
239
+ cols=[2 for i in range(len(templtr))],
240
+ rows=[1 for i in range(len(templtr))],
241
+ )
242
+ fig.update_layout(template="flight3d", showlegend=False)
243
+ return fig
244
+
245
+
246
+ def grid3dplot(plots):
247
+ """takes an n*m list of lists of 3d figures, puts them into a n*m subplot grid"""
248
+
249
+ nrows = len(plots)
250
+ ncols = len(plots[0])
251
+
252
+ fig = make_subplots(
253
+ cols=len(plots[0]),
254
+ rows=len(plots),
255
+ specs=[[{"type": "scene"} for i in range(ncols)] for j in range(nrows)],
256
+ )
257
+
258
+ sceneids = ["scene{}".format(i + 1) for i in range(ncols * nrows)]
259
+ sceneids[0] = "scene"
260
+ fig.update_layout(
261
+ **{
262
+ "scene{}".format(i + 1 if i > 0 else ""): dict(aspectmode="data")
263
+ for i in range(ncols * nrows)
264
+ }
265
+ )
266
+
267
+ for ir, plotrow in enumerate(plots):
268
+ for ic, plot in enumerate(plotrow):
269
+ fig.add_traces(
270
+ plot.data,
271
+ cols=np.full(len(plot.data), ic + 1).tolist(),
272
+ rows=np.full(len(plot.data), ir + 1).tolist(),
273
+ )
274
+
275
+ return fig
276
+
277
+
278
+ def plot_analysis(
279
+ analysis, obj=obj, nmodels=20, scale=4, cg=False, tip=True, fig=None, **kwargs
280
+ ):
281
+ obj = obj.scale(scale)
282
+
283
+ fig = go.Figure() if not fig else fig
284
+
285
+ if cg:
286
+ fig.add_traces(cgtrace(analysis.body, **kwargs))
287
+ if tip:
288
+ fig.add_traces(tiptrace(analysis.body, scale * 1.85))
289
+
290
+ fig.add_traces(
291
+ vectors(nmodels, analysis.body, analysis.environment.wind * scale / 3)
292
+ )
293
+
294
+ fig.add_traces(meshes(nmodels, analysis.judge, "blue", obj))
295
+ fig.add_traces(meshes(nmodels, analysis.wind, "red", obj))
296
+ fig.add_traces(meshes(nmodels, analysis.body, "green", obj))
297
+
298
+ fig.update_layout(
299
+ scene=dict(
300
+ aspectmode="data",
301
+ xaxis=dict(visible=True, showticklabels=True),
302
+ yaxis=dict(visible=True, showticklabels=True),
303
+ zaxis=dict(visible=True, showticklabels=True),
304
+ ),
305
+ height=800,
306
+ )
307
+ return fig
308
+
309
+
310
+ def multi_y_subplots(data: dict[str, pd.DataFrame], x: npt.NDArray = None):
311
+ fig = make_subplots(
312
+ rows=len(data),
313
+ cols=1,
314
+ shared_xaxes=True,
315
+ vertical_spacing=0.01,
316
+ #subplot_titles=list(data.keys()),
317
+ )
318
+
319
+ for row, (k, v) in enumerate(data.items(), 1):
320
+ for tr, col in enumerate(v.columns):
321
+ fig.add_trace(
322
+ go.Scatter(
323
+ x=v.index if x is None else np.abs(x),
324
+ y=v[col],
325
+ name=f"{k}_{col}",
326
+ line=dict(
327
+ color=px.colors.qualitative.Plotly[tr],
328
+ dash=[
329
+ "solid",
330
+ "dot",
331
+ "dash",
332
+ "longdash",
333
+ "dashdot",
334
+ "longdashdot",
335
+ ][row % 5],
336
+ ),
337
+ legend=f"legend{row}",
338
+ ),
339
+ row=row,
340
+ col=1,
341
+ )
342
+
343
+ for i, yaxis in enumerate(fig.select_yaxes(), 1):
344
+ fig.update_layout(
345
+ {
346
+ f"legend{i}": dict(
347
+ # name = list(data.keys())[i],
348
+ y=yaxis.domain[1],
349
+ yanchor="top",
350
+ ),
351
+ f"yaxis{i}": dict(
352
+ title=list(data.keys())[i-1],
353
+ showline=True,
354
+ ),
355
+ }
356
+ )
357
+
358
+ return fig.update_layout(
359
+ hovermode="x unified",
360
+ hoversubplots="axis",
361
+ )
362
+
363
+
364
+ axis = dict(
365
+ gridcolor="lightgrey",
366
+ linewidth=2,
367
+ linecolor="lightgrey",
368
+ zerolinewidth=2,
369
+ zerolinecolor="lightgrey",
370
+ showline=True,
371
+ )
@@ -8,7 +8,6 @@ from flightplotting.model import obj, OBJ
8
8
  import plotly.express as px
9
9
 
10
10
 
11
-
12
11
  def boxtrace():
13
12
  xlim=170*np.tan(np.radians(60))
14
13
  ylim=170
@@ -28,14 +27,19 @@ def meshes(npoints, seq: State, colour, scale=1, _obj: OBJ=None):
28
27
  _obj = obj if _obj is None else _obj
29
28
  if scale != 1:
30
29
  _obj = _obj.scale(scale)
31
- step = int(len(seq.data) / max(npoints, 1))
32
-
30
+ locs = []
31
+ if npoints >= 1:
32
+ locs.append(0)
33
+ if npoints >= 2:
34
+ locs.append(-1)
35
+ if npoints >= 3:
36
+ locs = locs + list(np.cumsum(np.full(npoints-2, len(seq) / (npoints-1))).astype(int))
37
+
33
38
  ms = []
34
-
35
- for st in seq[::step]:
39
+ for loc in locs:
36
40
  ms.append(_obj.transform(
37
- Transformation(st.pos, st.att)
38
- ).create_mesh(colour,f"{st.time.t[0]:.1f}"))
41
+ Transformation(seq.pos[loc], seq.att[loc])
42
+ ).create_mesh(colour,f"{seq.time.t[loc]:.1f}"))
39
43
  return ms
40
44
 
41
45
  def vector(origin, direction, **kwargs):
@@ -68,12 +72,7 @@ def trace3d(datax, datay, dataz, **kwargs):
68
72
  def cgtrace(seq, **kwargs):
69
73
  return trace3d(
70
74
  *seq.pos.data.T,
71
- **dict(
72
- dict(
73
- text=["{:.1f}".format(val) for val in seq.data.index]
74
- ),
75
- **kwargs
76
- )
75
+ **kwargs
77
76
  )
78
77
 
79
78
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flightplotting
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Tools for Plotting Flight Data in Plotly
5
5
  Author-email: Thomas David <thomasdavid0@gmail.com>
6
6
  License: GNU GPL v3
@@ -1,285 +0,0 @@
1
- import plotly.graph_objects as go
2
- from plotly.subplots import make_subplots
3
- import plotly.express as px
4
- import flightplotting.templates
5
- from flightplotting.traces import (
6
- tiptrace,
7
- meshes,
8
- control_input_trace,
9
- axis_rate_trace,
10
- aoa_trace,
11
- cgtrace,
12
- ribbon,
13
- vectors,
14
- axestrace
15
- )
16
-
17
- from flightdata import State
18
- from flightdata.base.labeling import get_appended_id
19
- from geometry import Coord
20
- from flightplotting.model import obj
21
- import numpy as np
22
- from typing import List, Union
23
-
24
-
25
- def plotsec(secs: State | list[State] | dict[str, State], scale=5, nmodels=0, fig=None,
26
- color: Union[str, list[str]]=None, cg=False, width=None,
27
- height=None, show_axes=False, ribb: bool=False, tips: bool=True, origin=False):
28
-
29
- traces = []
30
- keys = None
31
- if isinstance(secs, State):
32
- secs = [secs]
33
-
34
- if isinstance(secs, dict):
35
- keys = list(secs.keys())
36
- secs = list(secs.values())
37
- showkeys=True
38
- else:
39
- keys = list(range(len(secs)))
40
- showkeys=False
41
-
42
- for i, sec in enumerate(secs):
43
- text = ["{:.1f}".format(val) for val in sec.data.index]
44
- _color = color if color is not None else px.colors.qualitative.Plotly[i]
45
- if ribb:
46
- traces += ribbon(sec, scale * 1.85, _color, name=keys[i])
47
- if tips:
48
- traces += tiptrace(sec, scale * 1.85, text=text, name=keys[i])
49
- if nmodels > 0:
50
- traces += meshes(nmodels, sec, _color, scale)
51
- if cg:
52
- traces.append(cgtrace(sec, line=dict(color=_color, width=2), name=keys[i]))
53
-
54
- if origin:
55
- traces += axestrace(Coord.zero(), 50)
56
-
57
- if showkeys:
58
- for i, key in enumerate(keys):
59
- traces.append(go.Scatter3d(
60
- x=[],
61
- y=[],
62
- z=[],
63
- mode='markers',
64
- marker=dict(size=5, color=px.colors.qualitative.Plotly[i]),
65
- name=key,
66
- showlegend=True
67
- ))
68
-
69
- if fig is None:
70
-
71
- fig = go.Figure(
72
- data=traces,
73
- layout=go.Layout(template="flight3d+judge_view", uirevision='foo')
74
- )
75
- if show_axes:
76
- fig.update_layout(
77
- scene=dict(
78
- aspectmode='data',
79
- xaxis=dict(visible=True, showticklabels=True),
80
- yaxis=dict(visible=True, showticklabels=True),
81
- zaxis=dict(visible=True, showticklabels=True)
82
- )
83
- )
84
- if width is not None:
85
- fig.update_layout(width=width)
86
- if height is not None:
87
- fig.update_layout(height=height)
88
- else:
89
- fig.add_traces(traces)
90
- return fig
91
-
92
-
93
-
94
- def plotdtw(sec: State, manoeuvres: List[str], span=3, fig=None):
95
- if fig is None:
96
- fig = go.Figure(layout=go.Layout(template="flight3d+judge_view"))
97
-
98
- traces = []#tiptrace(sec, span)
99
-
100
- for i, name in enumerate(manoeuvres):
101
- try:
102
- seg = sec.get_man_or_el(name)
103
-
104
- traces += ribbon(seg, span, px.colors.qualitative.Alphabet[i], name)
105
-
106
- traces.append(go.Scatter3d(
107
- x=seg.pos.x,
108
- y=seg.pos.y,
109
- z=seg.pos.z,
110
- mode='lines',
111
- line=dict(width=6, color=px.colors.qualitative.Alphabet[i]),
112
- name=name
113
- ))
114
- except Exception as ex:
115
- pass
116
- print("no data for manoeuvre {}, {}".format(name, ex))
117
-
118
- fig.add_traces(traces)
119
-
120
-
121
- return fig
122
-
123
- def plot_regions(st: State, lab_cols: list[str], span=3, colours=None, fig=None, **kwargs):
124
- colours = px.colors.qualitative.Plotly if colours is None else colours
125
- lab_cols = [lab_cols] if isinstance(lab_cols, str) else lab_cols
126
-
127
-
128
- st = st.label(clabs=st.cumulative_labels(*lab_cols))
129
-
130
- def get_base_label(clab):
131
- base = clab
132
- try:
133
- id = int(clab.split('_')[-1])
134
- base = clab[:-len(f'_{id}')]
135
- except Exception:
136
- pass
137
- return base
138
-
139
- colmap = {}
140
-
141
- traces = []
142
- for i, (k, seg) in enumerate(st.split_labels('clabs').items()):
143
- if len(seg) < 3:
144
- continue
145
- blab, id = get_appended_id(k)
146
- if blab not in colmap:
147
- colmap[blab] = colours[len(colmap) % len(colours)]
148
- traces += ribbon(
149
- seg, span, colmap[blab], name=blab,
150
- showlegend=int(id)==0,
151
- **kwargs[blab] if blab in kwargs else {}
152
- )
153
- traces.append(go.Scatter3d(
154
- x=seg.pos.x,
155
- y=seg.pos.y,
156
- z=seg.pos.z,
157
- mode='lines',
158
- line=dict(width=0, color=colmap[blab]),
159
- name=k,
160
- showlegend=False
161
- ))
162
-
163
- if fig is None:
164
- fig = go.Figure(layout=go.Layout(template="flight3d+judge_view"))
165
- fig.add_traces(traces)
166
- return fig
167
-
168
- def create_3d_plot(traces):
169
- return go.Figure(
170
- traces,
171
- layout=go.Layout(template="flight3d+judge_view"))
172
-
173
-
174
-
175
- nb_layout = dict(
176
- margin=dict(l=5, r=5, t=5, b=1),
177
- legend=dict(yanchor="top", xanchor="left", x=0.8, y=0.99)
178
- )
179
-
180
-
181
- def control_brv_plot(sec, control_inputs = ["aileron", "elevator", "rudder", "throttle"]):
182
- """create a nice 2d plot showing control inputs and rotational velocities for a section"""
183
- fig = make_subplots(specs=[[{"secondary_y": True}]])
184
-
185
- fig.add_traces(axis_rate_trace(sec, dash="dash"), secondary_ys=np.full(3, False))
186
-
187
- fig.add_traces(control_input_trace(sec), secondary_ys=[True for i in range(4)])
188
-
189
- rvrng = np.ceil(np.degrees(sec.brvel.abs().max().max()) / 180) * 180
190
- cirng = np.ceil(sec.data.loc[:,control_inputs].abs().max().max() / 50) * 50
191
-
192
- fig.update_layout(
193
- xaxis=dict(title="time, s"),
194
- yaxis=dict(title="axis rate deg/s",range=(-rvrng, rvrng)),
195
- yaxis2=dict(title="control pwm offset, ms",range=(-cirng, cirng)),
196
- **nb_layout
197
- )
198
- return fig
199
-
200
-
201
- def aoa_brv_plot(sec):
202
- """create a nice 2d plot showing rotational velocities and angle of attack for a section"""
203
- fig = make_subplots(specs=[[{"secondary_y": True}]])
204
- fig.add_traces(axis_rate_trace(sec), secondary_ys=np.full(3, False))
205
- fig.add_traces(aoa_trace(sec, colours=px.colors.qualitative.Plotly[4:]), secondary_ys=np.full(2, True))
206
- fig.update_layout(
207
- xaxis=dict(title="Time (s)"),
208
- yaxis=dict(title="Axis Rate (deg/s)"),
209
- yaxis2=dict(title="Angle of Attack (deg)"),
210
- **nb_layout
211
- )
212
- return fig
213
-
214
-
215
- def compare_3d(sec1, sec2):
216
- fig = make_subplots(1, 2, specs=[[{'type': 'scene'}, {'type': 'scene'}]])
217
- flowntr = plotsec(sec1, scale=2, nmodels=4).data
218
- templtr = plotsec(sec2, scale=2, nmodels=4).data
219
-
220
- fig.add_traces(flowntr, cols = [1 for i in range(len(flowntr))], rows=[1 for i in range(len(flowntr))] )
221
- fig.add_traces(templtr, cols = [2 for i in range(len(templtr))], rows=[1 for i in range(len(templtr))] )
222
- fig.update_layout(template="flight3d", showlegend=False)
223
- return fig
224
-
225
-
226
- def grid3dplot(plots):
227
- """takes an n*m list of lists of 3d figures, puts them into a n*m subplot grid"""
228
-
229
- nrows = len(plots)
230
- ncols = len(plots[0])
231
-
232
- fig = make_subplots(
233
- cols=len(plots[0]),
234
- rows=len(plots),
235
- specs=[[{"type": "scene"} for i in range(ncols)] for j in range(nrows)]
236
- )
237
-
238
- sceneids = ["scene{}".format(i+1) for i in range(ncols*nrows)]
239
- sceneids[0] = "scene"
240
- fig.update_layout(**{"scene{}".format(i+1 if i>0 else ""):dict(aspectmode='data') for i in range(ncols*nrows)})
241
-
242
- for ir, plotrow in enumerate(plots):
243
- for ic, plot in enumerate(plotrow):
244
- fig.add_traces(plot.data, cols=np.full(len(plot.data), ic+1).tolist(), rows=np.full(len(plot.data), ir+1).tolist())
245
-
246
- return fig
247
-
248
-
249
-
250
- def plot_analysis(analysis, obj=obj, nmodels=20, scale=4, cg=False, tip=True, fig=None, **kwargs):
251
-
252
- obj = obj.scale(scale)
253
-
254
- fig = go.Figure() if not fig else fig
255
-
256
- if cg:
257
- fig.add_traces(cgtrace(analysis.body, **kwargs))
258
- if tip:
259
- fig.add_traces(tiptrace(analysis.body, scale*1.85))
260
-
261
- fig.add_traces(vectors(nmodels, analysis.body, analysis.environment.wind * scale / 3))
262
-
263
- fig.add_traces(meshes(nmodels,analysis.judge, "blue", obj))
264
- fig.add_traces(meshes(nmodels,analysis.wind, "red", obj))
265
- fig.add_traces(meshes(nmodels,analysis.body, "green", obj))
266
-
267
- fig.update_layout(
268
- scene=dict(
269
- aspectmode='data',
270
- xaxis=dict(visible=True, showticklabels=True),
271
- yaxis=dict(visible=True, showticklabels=True),
272
- zaxis=dict(visible=True, showticklabels=True)
273
- ), height=800)
274
- return fig
275
-
276
-
277
- axis = dict(
278
- gridcolor="lightgrey",
279
- linewidth=2,
280
- linecolor='lightgrey',
281
- zerolinewidth=2,
282
- zerolinecolor='lightgrey',
283
- showline=True
284
- )
285
-
File without changes
File without changes
File without changes