flightplotting 0.2.11__tar.gz → 0.2.13__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.
- {flightplotting-0.2.11 → flightplotting-0.2.13}/PKG-INFO +5 -4
- {flightplotting-0.2.11 → flightplotting-0.2.13}/pyproject.toml +5 -11
- {flightplotting-0.2.11 → flightplotting-0.2.13}/src/plotting/plots.py +21 -34
- {flightplotting-0.2.11 → flightplotting-0.2.13}/src/plotting/templates.py +6 -14
- {flightplotting-0.2.11 → flightplotting-0.2.13}/src/plotting/traces.py +20 -10
- flightplotting-0.2.13/uv.lock +345 -0
- flightplotting-0.2.11/uv.lock +0 -615
- {flightplotting-0.2.11 → flightplotting-0.2.13}/.github/workflows/publish_pypi.yml +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/.gitignore +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/.vscode/settings.json +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/COPYING +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/MANIFEST.in +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/README.md +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/src/plotting/__init__.py +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/src/plotting/data/ColdDraftF3APlane.obj +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/src/plotting/data/__init__.py +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/src/plotting/model.py +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/src/plotting/py.typed +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/src/plotting/titlerenderer.py +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/tests/__init__.py +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/tests/data/__init__.py +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/tests/data/p23_flight.json +0 -0
- {flightplotting-0.2.11 → flightplotting-0.2.13}/tests/test_plots.py +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: flightplotting
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.13
|
|
4
4
|
Summary: Add your description here
|
|
5
5
|
Author-email: Thomas David <thomasdavid0@gmail.com>
|
|
6
|
+
License-File: COPYING
|
|
6
7
|
Requires-Python: >=3.12
|
|
7
|
-
Requires-Dist:
|
|
8
|
-
Requires-Dist: flightdata>=0.2.24
|
|
8
|
+
Requires-Dist: flightdata>=0.3.0
|
|
9
9
|
Requires-Dist: numpy>=2.1.3
|
|
10
10
|
Requires-Dist: pandas>=2.2.3
|
|
11
11
|
Requires-Dist: pfc-geometry
|
|
12
|
+
Requires-Dist: pfcschemas
|
|
12
13
|
Requires-Dist: plotly>=5.24.1
|
|
13
14
|
Description-Content-Type: text/markdown
|
|
14
15
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flightplotting"
|
|
3
|
-
version="v0.2.
|
|
3
|
+
version="v0.2.13"
|
|
4
4
|
description = "Add your description here"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Thomas David", email = "thomasdavid0@gmail.com" }]
|
|
7
7
|
requires-python = ">=3.12"
|
|
8
8
|
dependencies = [
|
|
9
|
-
"flightanalysis>=0.3.13",
|
|
10
|
-
"flightdata>=0.2.24",
|
|
11
9
|
"numpy>=2.1.3",
|
|
12
10
|
"pandas>=2.2.3",
|
|
13
|
-
"pfc-geometry",
|
|
14
11
|
"plotly>=5.24.1",
|
|
12
|
+
"flightdata>=0.3.0",
|
|
13
|
+
"pfc-geometry",
|
|
14
|
+
"pfcschemas",
|
|
15
15
|
]
|
|
16
16
|
|
|
17
17
|
[build-system]
|
|
@@ -21,11 +21,5 @@ build-backend = "hatchling.build"
|
|
|
21
21
|
[tool.hatch.build.targets.wheel]
|
|
22
22
|
packages = ["src/plotting"]
|
|
23
23
|
|
|
24
|
-
[tool.uv.sources]
|
|
25
|
-
pfc-geometry = { path = "../geometry" , editable = true}
|
|
26
|
-
flightdata = { path = "../FlightData" , editable = true}
|
|
27
|
-
flightanalysis = { path = "../FlightAnalysis" , editable = true}
|
|
28
|
-
ardupilot_log_reader = { path = "../ArdupilotLogReader" , editable = true}
|
|
29
|
-
|
|
30
24
|
[dependency-groups]
|
|
31
|
-
dev = ["
|
|
25
|
+
dev = ["pytest>=8.3.3"]
|
|
@@ -15,14 +15,12 @@ from plotting.traces import (
|
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
from flightdata import State
|
|
18
|
-
from flightdata.base.labeling import get_appended_id
|
|
19
18
|
from geometry import Coord
|
|
20
19
|
from plotting.model import obj
|
|
21
20
|
import numpy.typing as npt
|
|
22
21
|
import numpy as np
|
|
23
22
|
import pandas as pd
|
|
24
23
|
from typing import List, Union
|
|
25
|
-
from flightanalysis.scoring.box import Box
|
|
26
24
|
|
|
27
25
|
|
|
28
26
|
def plotsec(
|
|
@@ -37,6 +35,7 @@ def plotsec(
|
|
|
37
35
|
show_axes=False,
|
|
38
36
|
ribb: bool = False,
|
|
39
37
|
tips: bool = True,
|
|
38
|
+
ribbonhover="t",
|
|
40
39
|
origin=False,
|
|
41
40
|
):
|
|
42
41
|
traces = []
|
|
@@ -53,16 +52,18 @@ def plotsec(
|
|
|
53
52
|
showkeys = False
|
|
54
53
|
|
|
55
54
|
for i, sec in enumerate(secs):
|
|
56
|
-
text = sec.data.t
|
|
55
|
+
text = sec.data.t # - sec.data.t.iloc[0]
|
|
57
56
|
_color = color if color is not None else px.colors.qualitative.Plotly[i]
|
|
58
57
|
if ribb:
|
|
59
|
-
traces += ribbon(sec, scale * 1.85,
|
|
58
|
+
traces += ribbon(sec, 0.5 * scale * 1.85, "grey", name=keys[i], opacity=0.5, hover=ribbonhover)
|
|
60
59
|
if tips:
|
|
61
60
|
traces += tiptrace(sec, scale * 1.85, text=text, name=keys[i])
|
|
62
61
|
if nmodels > 0:
|
|
63
62
|
traces += meshes(nmodels, sec, _color, scale)
|
|
64
63
|
if cg:
|
|
65
|
-
traces.append(
|
|
64
|
+
traces.append(
|
|
65
|
+
cgtrace(sec, line=dict(color=_color, width=2), name=keys[i], text=text)
|
|
66
|
+
)
|
|
66
67
|
|
|
67
68
|
if origin:
|
|
68
69
|
traces += axestrace(Coord.zero(), 50)
|
|
@@ -136,47 +137,33 @@ def plotdtw(sec: State, manoeuvres: List[str], span=3, fig=None):
|
|
|
136
137
|
|
|
137
138
|
|
|
138
139
|
def plot_regions(
|
|
139
|
-
st: State,
|
|
140
|
+
st: State,
|
|
141
|
+
label_group_name: str,
|
|
142
|
+
span=3,
|
|
143
|
+
colours=None,
|
|
144
|
+
fig=None,
|
|
145
|
+
ribbonhover="t",
|
|
146
|
+
**kwargs,
|
|
140
147
|
):
|
|
141
148
|
colours = px.colors.qualitative.Plotly if colours is None else colours
|
|
142
|
-
lab_cols = [lab_cols] if isinstance(lab_cols, str) else lab_cols
|
|
143
|
-
|
|
144
|
-
st = st.label(clabs=st.cumulative_labels(*lab_cols))
|
|
145
|
-
|
|
146
|
-
colmap = {}
|
|
147
149
|
|
|
148
150
|
traces = []
|
|
149
|
-
for i,
|
|
151
|
+
for i, k in enumerate(st.labels[label_group_name].keys()):
|
|
152
|
+
seg = getattr(st, label_group_name)[k]
|
|
150
153
|
if len(seg) < 3:
|
|
151
154
|
continue
|
|
152
|
-
blab, id = get_appended_id(k)
|
|
153
|
-
if blab not in colmap:
|
|
154
|
-
colmap[blab] = colours[len(colmap) % len(colours)]
|
|
155
155
|
traces += ribbon(
|
|
156
156
|
seg,
|
|
157
157
|
span,
|
|
158
|
-
|
|
159
|
-
name=
|
|
160
|
-
|
|
161
|
-
**kwargs[blab] if blab in kwargs else {},
|
|
162
|
-
)
|
|
163
|
-
traces.append(
|
|
164
|
-
go.Scatter3d(
|
|
165
|
-
x=seg.pos.x,
|
|
166
|
-
y=seg.pos.y,
|
|
167
|
-
z=seg.pos.z,
|
|
168
|
-
mode="lines",
|
|
169
|
-
line=dict(width=0, color=colmap[blab]),
|
|
170
|
-
name=k,
|
|
171
|
-
showlegend=False,
|
|
172
|
-
)
|
|
158
|
+
colours[i%len(colours)],
|
|
159
|
+
name=k,
|
|
160
|
+
hover=ribbonhover
|
|
173
161
|
)
|
|
174
162
|
|
|
163
|
+
|
|
175
164
|
if fig is None:
|
|
176
165
|
fig = go.Figure(layout=go.Layout(template="flight3d+judge_view"))
|
|
177
166
|
fig.add_traces(traces)
|
|
178
|
-
if box:
|
|
179
|
-
fig.add_traces(box.plot())
|
|
180
167
|
return fig
|
|
181
168
|
|
|
182
169
|
|
|
@@ -316,7 +303,7 @@ def multi_y_subplots(data: dict[str, pd.DataFrame], x: npt.NDArray = None):
|
|
|
316
303
|
cols=1,
|
|
317
304
|
shared_xaxes=True,
|
|
318
305
|
vertical_spacing=0.01,
|
|
319
|
-
#subplot_titles=list(data.keys()),
|
|
306
|
+
# subplot_titles=list(data.keys()),
|
|
320
307
|
)
|
|
321
308
|
|
|
322
309
|
for row, (k, v) in enumerate(data.items(), 1):
|
|
@@ -352,7 +339,7 @@ def multi_y_subplots(data: dict[str, pd.DataFrame], x: npt.NDArray = None):
|
|
|
352
339
|
yanchor="top",
|
|
353
340
|
),
|
|
354
341
|
f"yaxis{i}": dict(
|
|
355
|
-
title=list(data.keys())[i-1],
|
|
342
|
+
title=list(data.keys())[i - 1],
|
|
356
343
|
showline=True,
|
|
357
344
|
),
|
|
358
345
|
}
|
|
@@ -2,21 +2,14 @@
|
|
|
2
2
|
import plotly.graph_objects as go
|
|
3
3
|
import plotly.io as pio
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
generic3d_template = go.layout.Template(layout=go.Layout(
|
|
6
7
|
margin=dict(l=0, r=0, t=0, b=0),
|
|
7
|
-
scene=dict(
|
|
8
|
-
aspectmode='data',
|
|
9
|
-
),
|
|
10
|
-
legend=dict(
|
|
11
|
-
font=dict(size=20),
|
|
12
|
-
yanchor="top",
|
|
13
|
-
y=0.99,
|
|
14
|
-
xanchor="left",
|
|
15
|
-
x=0.01
|
|
16
|
-
)
|
|
8
|
+
scene=dict(aspectmode='data')
|
|
17
9
|
))
|
|
18
10
|
|
|
19
|
-
pio.templates["
|
|
11
|
+
pio.templates["generic3d"] = generic3d_template
|
|
12
|
+
pio.templates["flight3d"] = generic3d_template
|
|
20
13
|
|
|
21
14
|
judges_view_template = go.layout.Template(layout=go.Layout(scene_camera=dict(
|
|
22
15
|
up=dict(x=0, y=0, z=1),
|
|
@@ -32,10 +25,9 @@ pio.templates["judge_view"] = judges_view_template
|
|
|
32
25
|
clean_paper_template = go.layout.Template(layout=go.Layout(
|
|
33
26
|
margin=dict(l=0, r=0, t=0, b=0),
|
|
34
27
|
scene=dict(
|
|
35
|
-
aspectmode='data',
|
|
36
28
|
xaxis = dict(visible=False),
|
|
37
29
|
yaxis = dict(visible=False),
|
|
38
|
-
zaxis =dict(visible=False)
|
|
30
|
+
zaxis = dict(visible=False)
|
|
39
31
|
),
|
|
40
32
|
legend=dict(
|
|
41
33
|
font=dict(size=20),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from typing import Literal
|
|
1
2
|
import plotly.graph_objects as go
|
|
2
3
|
import plotting.templates
|
|
3
4
|
from geometry import Point, Coord, Transformation
|
|
@@ -23,7 +24,7 @@ def boxtrace():
|
|
|
23
24
|
)]
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
def meshes(npoints, seq: State, colour, scale=1, _obj: OBJ=None):
|
|
27
|
+
def meshes(npoints, seq: State | Transformation, colour: str=None, scale=1, _obj: OBJ=None):
|
|
27
28
|
_obj = obj if _obj is None else _obj
|
|
28
29
|
if scale != 1:
|
|
29
30
|
_obj = _obj.scale(scale)
|
|
@@ -36,10 +37,10 @@ def meshes(npoints, seq: State, colour, scale=1, _obj: OBJ=None):
|
|
|
36
37
|
locs = locs + list(np.cumsum(np.full(npoints-2, len(seq) / (npoints-1))).astype(int))
|
|
37
38
|
|
|
38
39
|
ms = []
|
|
39
|
-
for loc in locs:
|
|
40
|
+
for i, loc in enumerate(locs):
|
|
40
41
|
ms.append(_obj.transform(
|
|
41
|
-
|
|
42
|
-
).create_mesh(colour,f"{seq.time.t[loc]:.1f}"))
|
|
42
|
+
seq.iloc[loc].transform if isinstance(seq, State) else seq[loc]
|
|
43
|
+
).create_mesh(colour or "grey",f"{(seq.time.t[loc] if isinstance(seq, State) else i):.1f}"))
|
|
43
44
|
return ms
|
|
44
45
|
|
|
45
46
|
def vector(origin, direction, **kwargs):
|
|
@@ -201,24 +202,25 @@ def aoa_trace(sec, dash="dash", colours = px.colors.qualitative.Plotly):
|
|
|
201
202
|
#sec = sec.append_columns(sec.aoa())
|
|
202
203
|
return sec_col_trace(sec, ["alpha", "beta"], dash, colours, np.degrees)
|
|
203
204
|
|
|
204
|
-
def axestrace(cid: Coord, length:float=20.0):
|
|
205
|
+
def axestrace(cid: Coord | Transformation, length:float=20.0, **kwargs):
|
|
205
206
|
ntraces = []
|
|
206
207
|
colours = {"x":"red", "y":"blue", "z":"green"}
|
|
207
208
|
for i, ci in enumerate(cid):
|
|
209
|
+
if isinstance(ci, Transformation):
|
|
210
|
+
ci = ci.apply(Coord.zero())
|
|
208
211
|
for ax, col in zip([ci.x_axis, ci.y_axis, ci.z_axis], list("xyz")):
|
|
209
212
|
axis = Point.concatenate([ci.origin, ci.origin + ax * length])
|
|
210
213
|
ntraces.append(go.Scatter3d(
|
|
211
214
|
x=axis.x, y=axis.y, z=axis.z, mode="lines",
|
|
212
215
|
line=dict(color=colours[col]),
|
|
213
|
-
name=col,
|
|
214
|
-
|
|
216
|
+
name=f"{i}_{col}",
|
|
217
|
+
**kwargs
|
|
215
218
|
))
|
|
216
219
|
|
|
217
220
|
return ntraces
|
|
218
221
|
|
|
219
222
|
|
|
220
223
|
|
|
221
|
-
|
|
222
224
|
def _npinterzip(a, b):
|
|
223
225
|
"""
|
|
224
226
|
takes two numpy arrays and zips them.
|
|
@@ -243,7 +245,7 @@ def _npinterzip(a, b):
|
|
|
243
245
|
return c
|
|
244
246
|
|
|
245
247
|
|
|
246
|
-
def ribbon(sec: State, span: float, color, **kwargs):
|
|
248
|
+
def ribbon(sec: State, span: float, color, hover: Literal["i", "t"]='i', **kwargs):
|
|
247
249
|
"""TODO make the colouring more generic
|
|
248
250
|
"""
|
|
249
251
|
|
|
@@ -252,7 +254,13 @@ def ribbon(sec: State, span: float, color, **kwargs):
|
|
|
252
254
|
|
|
253
255
|
points = Point(_npinterzip(left.data, right.data))
|
|
254
256
|
|
|
255
|
-
|
|
257
|
+
match hover:
|
|
258
|
+
case "i":
|
|
259
|
+
text=[f"{i}" for i in np.arange(len(sec)*2)]
|
|
260
|
+
case _:
|
|
261
|
+
text=[f"{t:.1f}" for t in _npinterzip(sec.t, sec.t)]
|
|
262
|
+
|
|
263
|
+
|
|
256
264
|
_i = np.array(range(len(points) - 2)) # 1 2 3 4 5
|
|
257
265
|
|
|
258
266
|
_js = np.array(range(1, len(points), 2))
|
|
@@ -265,5 +273,7 @@ def ribbon(sec: State, span: float, color, **kwargs):
|
|
|
265
273
|
x=points.x, y=points.y, z=points.z, i=_i, j=_j, k=_k,
|
|
266
274
|
intensitymode="cell",
|
|
267
275
|
facecolor=np.full(len(_i), color),
|
|
276
|
+
text=text,
|
|
277
|
+
hovertemplate='i:%{text}<br>',
|
|
268
278
|
**kwargs
|
|
269
279
|
)]
|