flightplotting 0.2.6__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 (30) hide show
  1. {flightplotting-0.2.6 → flightplotting-0.2.8}/PKG-INFO +4 -4
  2. flightplotting-0.2.8/flightplotting/plots.py +371 -0
  3. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting/traces.py +17 -14
  4. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting.egg-info/PKG-INFO +4 -4
  5. flightplotting-0.2.8/flightplotting.egg-info/requires.txt +6 -0
  6. flightplotting-0.2.8/requirements.txt +6 -0
  7. flightplotting-0.2.6/flightplotting/plots.py +0 -265
  8. flightplotting-0.2.6/flightplotting.egg-info/requires.txt +0 -6
  9. flightplotting-0.2.6/requirements.txt +0 -6
  10. {flightplotting-0.2.6 → flightplotting-0.2.8}/.github/workflows/publish_pypi.yml +0 -0
  11. {flightplotting-0.2.6 → flightplotting-0.2.8}/.gitignore +0 -0
  12. {flightplotting-0.2.6 → flightplotting-0.2.8}/.vscode/settings.json +0 -0
  13. {flightplotting-0.2.6 → flightplotting-0.2.8}/COPYING +0 -0
  14. {flightplotting-0.2.6 → flightplotting-0.2.8}/MANIFEST.in +0 -0
  15. {flightplotting-0.2.6 → flightplotting-0.2.8}/README.md +0 -0
  16. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting/__init__.py +0 -0
  17. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting/data/ColdDraftF3APlane.obj +0 -0
  18. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting/data/__init__.py +0 -0
  19. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting/model.py +0 -0
  20. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting/templates.py +0 -0
  21. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting/titlerenderer.py +0 -0
  22. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting.egg-info/SOURCES.txt +0 -0
  23. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting.egg-info/dependency_links.txt +0 -0
  24. {flightplotting-0.2.6 → flightplotting-0.2.8}/flightplotting.egg-info/top_level.txt +0 -0
  25. {flightplotting-0.2.6 → flightplotting-0.2.8}/pyproject.toml +0 -0
  26. {flightplotting-0.2.6 → flightplotting-0.2.8}/setup.cfg +0 -0
  27. {flightplotting-0.2.6 → flightplotting-0.2.8}/tests/__init__.py +0 -0
  28. {flightplotting-0.2.6 → flightplotting-0.2.8}/tests/data/__init__.py +0 -0
  29. {flightplotting-0.2.6 → flightplotting-0.2.8}/tests/data/p23_flight.json +0 -0
  30. {flightplotting-0.2.6 → 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.6
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
@@ -11,9 +11,9 @@ License-File: COPYING
11
11
  Requires-Dist: numpy
12
12
  Requires-Dist: pandas
13
13
  Requires-Dist: plotly
14
- Requires-Dist: pfc-geometry>=0.2.4
15
- Requires-Dist: flightdata>=0.2.6
16
- Requires-Dist: flightanalysis>=0.2.6
14
+ Requires-Dist: pfc-geometry>=0.2.8
15
+ Requires-Dist: flightdata>=0.2.16
16
+ Requires-Dist: flightanalysis>=0.2.17
17
17
 
18
18
  # FlightPlotting
19
19
 
@@ -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
@@ -24,14 +23,23 @@ def boxtrace():
24
23
  )]
25
24
 
26
25
 
27
- def meshes(npoints, seq: State, colour, obj: OBJ=obj):
28
- step = int(len(seq.data) / max(npoints, 1))
29
-
26
+ def meshes(npoints, seq: State, colour, scale=1, _obj: OBJ=None):
27
+ _obj = obj if _obj is None else _obj
28
+ if scale != 1:
29
+ _obj = _obj.scale(scale)
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
+
30
38
  ms = []
31
-
32
- sts = [seq[0]] + [ st for st in seq[::step]] + [seq[-1]]
33
- for st in sts:
34
- ms.append(obj.transform(Transformation(st.pos, st.att)).create_mesh(colour,f"{st.time.t[0]:.1f}"))
39
+ for loc in locs:
40
+ ms.append(_obj.transform(
41
+ Transformation(seq.pos[loc], seq.att[loc])
42
+ ).create_mesh(colour,f"{seq.time.t[loc]:.1f}"))
35
43
  return ms
36
44
 
37
45
  def vector(origin, direction, **kwargs):
@@ -64,12 +72,7 @@ def trace3d(datax, datay, dataz, **kwargs):
64
72
  def cgtrace(seq, **kwargs):
65
73
  return trace3d(
66
74
  *seq.pos.data.T,
67
- **dict(
68
- dict(
69
- text=["{:.1f}".format(val) for val in seq.data.index]
70
- ),
71
- **kwargs
72
- )
75
+ **kwargs
73
76
  )
74
77
 
75
78
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flightplotting
3
- Version: 0.2.6
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
@@ -11,9 +11,9 @@ License-File: COPYING
11
11
  Requires-Dist: numpy
12
12
  Requires-Dist: pandas
13
13
  Requires-Dist: plotly
14
- Requires-Dist: pfc-geometry>=0.2.4
15
- Requires-Dist: flightdata>=0.2.6
16
- Requires-Dist: flightanalysis>=0.2.6
14
+ Requires-Dist: pfc-geometry>=0.2.8
15
+ Requires-Dist: flightdata>=0.2.16
16
+ Requires-Dist: flightanalysis>=0.2.17
17
17
 
18
18
  # FlightPlotting
19
19
 
@@ -0,0 +1,6 @@
1
+ numpy
2
+ pandas
3
+ plotly
4
+ pfc-geometry>=0.2.8
5
+ flightdata>=0.2.16
6
+ flightanalysis>=0.2.17
@@ -0,0 +1,6 @@
1
+ numpy
2
+ pandas
3
+ plotly
4
+ pfc-geometry>=0.2.8
5
+ flightdata>=0.2.16
6
+ flightanalysis>=0.2.17
@@ -1,265 +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, OBJ
21
- import numpy as np
22
- from typing import List, Union
23
-
24
-
25
- def plotsec(secs: Union[State, list[State]], scale=5, nmodels=0, fig=None,
26
- color: Union[str, list[str]]=None, obj: OBJ=obj, cg=False, width=None,
27
- height=None, show_axes=False, ribb: bool=False, tips: bool=True, origin=False):
28
-
29
- traces = []
30
-
31
- if isinstance(secs, State):
32
- secs = [secs]
33
-
34
- for i, sec in enumerate(secs):
35
- text = ["{:.1f}".format(val) for val in sec.data.index]
36
- _color = color if color is not None else px.colors.qualitative.Plotly[i]
37
- if ribb:
38
- traces += ribbon(sec, scale * 1.85, _color)
39
- if tips:
40
- traces += tiptrace(sec, scale * 1.85, text=text)
41
- if nmodels > 0:
42
- traces += meshes(nmodels, sec, _color, obj.scale(scale))
43
- if cg:
44
- traces.append(cgtrace(sec, line=dict(color=_color, width=2)))
45
-
46
- if origin:
47
- traces += axestrace(Coord.zero(), 50)
48
-
49
- if fig is None:
50
-
51
- fig = go.Figure(
52
- data=traces,
53
- layout=go.Layout(template="flight3d+judge_view", uirevision='foo')
54
- )
55
- if show_axes:
56
- fig.update_layout(
57
- scene=dict(
58
- aspectmode='data',
59
- xaxis=dict(visible=True, showticklabels=True),
60
- yaxis=dict(visible=True, showticklabels=True),
61
- zaxis=dict(visible=True, showticklabels=True)
62
- )
63
- )
64
- if width is not None:
65
- fig.update_layout(width=width)
66
- if height is not None:
67
- fig.update_layout(height=height)
68
- else:
69
- fig.add_traces(traces)
70
- return fig
71
-
72
-
73
-
74
- def plotdtw(sec: State, manoeuvres: List[str], span=3, fig=None):
75
- if fig is None:
76
- fig = go.Figure(layout=go.Layout(template="flight3d+judge_view"))
77
-
78
- traces = []#tiptrace(sec, span)
79
-
80
- for i, name in enumerate(manoeuvres):
81
- try:
82
- seg = sec.get_man_or_el(name)
83
-
84
- traces += ribbon(seg, span, px.colors.qualitative.Alphabet[i], name)
85
-
86
- traces.append(go.Scatter3d(
87
- x=seg.pos.x,
88
- y=seg.pos.y,
89
- z=seg.pos.z,
90
- mode='lines',
91
- line=dict(width=6, color=px.colors.qualitative.Alphabet[i]),
92
- name=name
93
- ))
94
- except Exception as ex:
95
- pass
96
- print("no data for manoeuvre {}, {}".format(name, ex))
97
-
98
- fig.add_traces(traces)
99
-
100
-
101
- return fig
102
-
103
- def plot_regions(st: State, lab_cols: list[str], span=3, colours=None, fig=None, **kwargs):
104
- colours = px.colors.qualitative.Plotly if colours is None else colours
105
- lab_cols = [lab_cols] if isinstance(lab_cols, str) else lab_cols
106
-
107
-
108
- st = st.label(clabs=st.cumulative_labels(*lab_cols))
109
-
110
- def get_base_label(clab):
111
- base = clab
112
- try:
113
- id = int(clab.split('_')[-1])
114
- base = clab[:-len(f'_{id}')]
115
- except Exception:
116
- pass
117
- return base
118
-
119
- colmap = {}
120
-
121
- traces = []
122
- for i, (k, seg) in enumerate(st.split_labels('clabs').items()):
123
- if len(seg) < 3:
124
- continue
125
- blab, id = get_appended_id(k)
126
- if blab not in colmap:
127
- colmap[blab] = colours[len(colmap) % len(colours)]
128
- traces += ribbon(
129
- seg, span, colmap[blab], name=blab,
130
- showlegend=int(id)==0,
131
- **kwargs[blab] if blab in kwargs else {}
132
- )
133
- traces.append(go.Scatter3d(
134
- x=seg.pos.x,
135
- y=seg.pos.y,
136
- z=seg.pos.z,
137
- mode='lines',
138
- line=dict(width=0, color=colmap[blab]),
139
- name=k,
140
- showlegend=False
141
- ))
142
-
143
- if fig is None:
144
- fig = go.Figure(layout=go.Layout(template="flight3d+judge_view"))
145
- fig.add_traces(traces)
146
- return fig
147
-
148
- def create_3d_plot(traces):
149
- return go.Figure(
150
- traces,
151
- layout=go.Layout(template="flight3d+judge_view"))
152
-
153
-
154
-
155
- nb_layout = dict(
156
- margin=dict(l=5, r=5, t=5, b=1),
157
- legend=dict(yanchor="top", xanchor="left", x=0.8, y=0.99)
158
- )
159
-
160
-
161
- def control_brv_plot(sec, control_inputs = ["aileron", "elevator", "rudder", "throttle"]):
162
- """create a nice 2d plot showing control inputs and rotational velocities for a section"""
163
- fig = make_subplots(specs=[[{"secondary_y": True}]])
164
-
165
- fig.add_traces(axis_rate_trace(sec, dash="dash"), secondary_ys=np.full(3, False))
166
-
167
- fig.add_traces(control_input_trace(sec), secondary_ys=[True for i in range(4)])
168
-
169
- rvrng = np.ceil(np.degrees(sec.brvel.abs().max().max()) / 180) * 180
170
- cirng = np.ceil(sec.data.loc[:,control_inputs].abs().max().max() / 50) * 50
171
-
172
- fig.update_layout(
173
- xaxis=dict(title="time, s"),
174
- yaxis=dict(title="axis rate deg/s",range=(-rvrng, rvrng)),
175
- yaxis2=dict(title="control pwm offset, ms",range=(-cirng, cirng)),
176
- **nb_layout
177
- )
178
- return fig
179
-
180
-
181
- def aoa_brv_plot(sec):
182
- """create a nice 2d plot showing rotational velocities and angle of attack for a section"""
183
- fig = make_subplots(specs=[[{"secondary_y": True}]])
184
- fig.add_traces(axis_rate_trace(sec), secondary_ys=np.full(3, False))
185
- fig.add_traces(aoa_trace(sec, colours=px.colors.qualitative.Plotly[4:]), secondary_ys=np.full(2, True))
186
- fig.update_layout(
187
- xaxis=dict(title="Time (s)"),
188
- yaxis=dict(title="Axis Rate (deg/s)"),
189
- yaxis2=dict(title="Angle of Attack (deg)"),
190
- **nb_layout
191
- )
192
- return fig
193
-
194
-
195
- def compare_3d(sec1, sec2):
196
- fig = make_subplots(1, 2, specs=[[{'type': 'scene'}, {'type': 'scene'}]])
197
- flowntr = plotsec(sec1, scale=2, nmodels=4).data
198
- templtr = plotsec(sec2, scale=2, nmodels=4).data
199
-
200
- fig.add_traces(flowntr, cols = [1 for i in range(len(flowntr))], rows=[1 for i in range(len(flowntr))] )
201
- fig.add_traces(templtr, cols = [2 for i in range(len(templtr))], rows=[1 for i in range(len(templtr))] )
202
- fig.update_layout(template="flight3d", showlegend=False)
203
- return fig
204
-
205
-
206
- def grid3dplot(plots):
207
- """takes an n*m list of lists of 3d figures, puts them into a n*m subplot grid"""
208
-
209
- nrows = len(plots)
210
- ncols = len(plots[0])
211
-
212
- fig = make_subplots(
213
- cols=len(plots[0]),
214
- rows=len(plots),
215
- specs=[[{"type": "scene"} for i in range(ncols)] for j in range(nrows)]
216
- )
217
-
218
- sceneids = ["scene{}".format(i+1) for i in range(ncols*nrows)]
219
- sceneids[0] = "scene"
220
- fig.update_layout(**{"scene{}".format(i+1 if i>0 else ""):dict(aspectmode='data') for i in range(ncols*nrows)})
221
-
222
- for ir, plotrow in enumerate(plots):
223
- for ic, plot in enumerate(plotrow):
224
- fig.add_traces(plot.data, cols=np.full(len(plot.data), ic+1).tolist(), rows=np.full(len(plot.data), ir+1).tolist())
225
-
226
- return fig
227
-
228
-
229
-
230
- def plot_analysis(analysis, obj=obj, nmodels=20, scale=4, cg=False, tip=True, fig=None, **kwargs):
231
-
232
- obj = obj.scale(scale)
233
-
234
- fig = go.Figure() if not fig else fig
235
-
236
- if cg:
237
- fig.add_traces(cgtrace(analysis.body, **kwargs))
238
- if tip:
239
- fig.add_traces(tiptrace(analysis.body, scale*1.85))
240
-
241
- fig.add_traces(vectors(nmodels, analysis.body, analysis.environment.wind * scale / 3))
242
-
243
- fig.add_traces(meshes(nmodels,analysis.judge, "blue", obj))
244
- fig.add_traces(meshes(nmodels,analysis.wind, "red", obj))
245
- fig.add_traces(meshes(nmodels,analysis.body, "green", obj))
246
-
247
- fig.update_layout(
248
- scene=dict(
249
- aspectmode='data',
250
- xaxis=dict(visible=True, showticklabels=True),
251
- yaxis=dict(visible=True, showticklabels=True),
252
- zaxis=dict(visible=True, showticklabels=True)
253
- ), height=800)
254
- return fig
255
-
256
-
257
- axis = dict(
258
- gridcolor="lightgrey",
259
- linewidth=2,
260
- linecolor='lightgrey',
261
- zerolinewidth=2,
262
- zerolinecolor='lightgrey',
263
- showline=True
264
- )
265
-
@@ -1,6 +0,0 @@
1
- numpy
2
- pandas
3
- plotly
4
- pfc-geometry>=0.2.4
5
- flightdata>=0.2.6
6
- flightanalysis>=0.2.6
@@ -1,6 +0,0 @@
1
- numpy
2
- pandas
3
- plotly
4
- pfc-geometry>=0.2.4
5
- flightdata>=0.2.6
6
- flightanalysis>=0.2.6
File without changes
File without changes
File without changes