spectra-plot 0.2.7__tar.gz → 0.3.0__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.
- {spectra_plot-0.2.7/spectra_plot.egg-info → spectra_plot-0.3.0}/PKG-INFO +3 -1
- spectra_plot-0.3.0/VERSION +1 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/pyproject.toml +4 -1
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/__init__.py +10 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_codec_fb.py +18 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_easy.py +345 -4
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_embed.py +3 -3
- {spectra_plot-0.2.7 → spectra_plot-0.3.0/spectra_plot.egg-info}/PKG-INFO +3 -1
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra_plot.egg-info/requires.txt +2 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_easy.py +3 -2
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_easy_embed.py +2 -2
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_embed.py +2 -2
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_phase2.py +1 -1
- spectra_plot-0.2.7/VERSION +0 -1
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/MANIFEST.in +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/setup.cfg +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_animation.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_axes.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_blob.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_cli.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_codec.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_download.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_errors.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/__init__.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/__init__.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/AckStatePayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/CmdAssignFiguresPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/CmdCloseWindowPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/CmdRemoveFigurePayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/CmdSetActivePayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/DiffOp.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/DiffOpType.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/EvtFigureDestroyedPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/EvtInputPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/EvtTopicListChangedPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/EvtWindowClosedPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/HelloPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/InputType.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqAddSeriesPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqAppendDataPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqCloseFigurePayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqCloseWindowPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqCreateAxesPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqCreateFigurePayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqCreateWindowPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqDeclareTopicPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqDestroyFigurePayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqDetachFigurePayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqListTopicsPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqPublishTopicSamplesPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqReconnectPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqRemoveSeriesPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqSetDataPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqShowPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqSubscribeTopicPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqUnsubscribeTopicPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqUpdateBatchPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqUpdatePropertyPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespAxesCreatedPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespErrPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespFigureCreatedPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespFigureListPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespOkPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespSeriesAddedPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespSubscribeTopicPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespTopicListPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/SnapshotAxisState.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/SnapshotFigureState.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/SnapshotKnobState.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/SnapshotSeriesState.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/StateDiffPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/StateSnapshotPayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/TopicInfoEntry.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/WelcomePayload.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/__init__.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_figure.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_launcher.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_log.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_persistence.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_protocol.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_series.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_session.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_transport.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/backends/__init__.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/backends/_qt_compat.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/backends/backend_qtagg.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/embed.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/topic.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra_plot.egg-info/SOURCES.txt +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra_plot.egg-info/dependency_links.txt +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra_plot.egg-info/entry_points.txt +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra_plot.egg-info/top_level.txt +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_codec.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_cross_codec.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_download.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_packaging_metadata.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_phase3.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_phase4.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_phase5.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_qt_backend.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_topic_publisher.py +0 -0
- {spectra_plot-0.2.7 → spectra_plot-0.3.0}/tests/test_windows_compat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spectra-plot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: GPU-accelerated scientific plotting via IPC
|
|
5
5
|
License: MIT
|
|
6
6
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -15,8 +15,10 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
15
15
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
16
16
|
Requires-Python: >=3.9
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: flatbuffers>=2.0
|
|
18
19
|
Provides-Extra: numpy
|
|
19
20
|
Requires-Dist: numpy>=1.20; extra == "numpy"
|
|
20
21
|
Provides-Extra: dev
|
|
21
22
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
22
23
|
Requires-Dist: numpy>=1.20; extra == "dev"
|
|
24
|
+
Requires-Dist: flatbuffers>=2.0; extra == "dev"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.3.0
|
|
@@ -9,6 +9,9 @@ description = "GPU-accelerated scientific plotting via IPC"
|
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
11
11
|
requires-python = ">=3.9"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"flatbuffers>=2.0",
|
|
14
|
+
]
|
|
12
15
|
classifiers = [
|
|
13
16
|
"Development Status :: 3 - Alpha",
|
|
14
17
|
"Intended Audience :: Science/Research",
|
|
@@ -24,7 +27,7 @@ classifiers = [
|
|
|
24
27
|
|
|
25
28
|
[project.optional-dependencies]
|
|
26
29
|
numpy = ["numpy>=1.20"]
|
|
27
|
-
dev = ["pytest>=7.0", "numpy>=1.20"]
|
|
30
|
+
dev = ["pytest>=7.0", "numpy>=1.20", "flatbuffers>=2.0"]
|
|
28
31
|
|
|
29
32
|
[project.scripts]
|
|
30
33
|
spectra-backend = "spectra._cli:backend_main"
|
|
@@ -8,6 +8,8 @@ Usage::
|
|
|
8
8
|
|
|
9
9
|
sp.plot([1, 4, 9, 16]) # that's it. window opens.
|
|
10
10
|
sp.plot(x, y, color="red", label="data") # with style
|
|
11
|
+
sp.hline(0) # horizontal reference line
|
|
12
|
+
sp.fplot(lambda x: x**2, -2, 2) # plot a function
|
|
11
13
|
sp.scatter(x, y) # scatter plot
|
|
12
14
|
sp.hist(data, bins=50) # histogram
|
|
13
15
|
sp.plot3(x, y, z) # 3D line
|
|
@@ -52,6 +54,10 @@ from ._easy import (
|
|
|
52
54
|
violin_plot,
|
|
53
55
|
hline,
|
|
54
56
|
vline,
|
|
57
|
+
fplot,
|
|
58
|
+
ihline,
|
|
59
|
+
ivline,
|
|
60
|
+
ifplot,
|
|
55
61
|
plot3,
|
|
56
62
|
scatter3,
|
|
57
63
|
surf,
|
|
@@ -105,6 +111,10 @@ __all__ = [
|
|
|
105
111
|
"violin_plot",
|
|
106
112
|
"hline",
|
|
107
113
|
"vline",
|
|
114
|
+
"fplot",
|
|
115
|
+
"ihline",
|
|
116
|
+
"ivline",
|
|
117
|
+
"ifplot",
|
|
108
118
|
"plot3",
|
|
109
119
|
"scatter3",
|
|
110
120
|
"surf",
|
|
@@ -560,3 +560,21 @@ def decode_fb_req_update_property(data: bytes) -> dict:
|
|
|
560
560
|
"str_val": str_val_raw.decode("utf-8") if str_val_raw else "",
|
|
561
561
|
}
|
|
562
562
|
|
|
563
|
+
|
|
564
|
+
def decode_fb_snapshot_knobs(data: bytes) -> dict:
|
|
565
|
+
"""Extract knob name → value from a STATE_SNAPSHOT / RESP_SNAPSHOT payload."""
|
|
566
|
+
from ._fb_generated.spectra.ipc.fb.StateSnapshotPayload import StateSnapshotPayload
|
|
567
|
+
|
|
568
|
+
raw = _strip(data)
|
|
569
|
+
snap = StateSnapshotPayload.GetRootAs(bytearray(raw), 0)
|
|
570
|
+
out: dict = {}
|
|
571
|
+
n = snap.KnobsLength()
|
|
572
|
+
for i in range(n):
|
|
573
|
+
k = snap.Knobs(i)
|
|
574
|
+
if k is None:
|
|
575
|
+
continue
|
|
576
|
+
name = k.Name()
|
|
577
|
+
if name:
|
|
578
|
+
out[name.decode("utf-8")] = float(k.Value())
|
|
579
|
+
return out
|
|
580
|
+
|
|
@@ -137,6 +137,10 @@ class _EasyState:
|
|
|
137
137
|
self._shutting_down = False
|
|
138
138
|
self._axes_bounds: dict = {} # id(axes) -> [xmin, xmax, ymin, ymax]
|
|
139
139
|
self._subplot_cache: dict = {} # (figure_id, rows, cols, index) -> Axes
|
|
140
|
+
self._pending_knobs: List[dict] = []
|
|
141
|
+
self._interactive_bindings: List = []
|
|
142
|
+
self._interactive_started = False
|
|
143
|
+
self._knob_values: dict = {}
|
|
140
144
|
|
|
141
145
|
def _ensure_session(self):
|
|
142
146
|
"""Lazily create the backend session."""
|
|
@@ -160,8 +164,10 @@ class _EasyState:
|
|
|
160
164
|
"""Show the current figure if it hasn't been shown yet."""
|
|
161
165
|
fig = self._current_fig
|
|
162
166
|
if fig is not None and id(fig) in self._pending_show:
|
|
167
|
+
self._flush_pending_knobs()
|
|
163
168
|
self._pending_show.discard(id(fig))
|
|
164
169
|
fig.show()
|
|
170
|
+
_ensure_interactive_loop()
|
|
165
171
|
|
|
166
172
|
def _ensure_axes(self):
|
|
167
173
|
"""Lazily create axes on the current figure."""
|
|
@@ -178,6 +184,32 @@ class _EasyState:
|
|
|
178
184
|
self._current_axes3d = fig.subplot3d(1, 1, 1)
|
|
179
185
|
return self._current_axes3d
|
|
180
186
|
|
|
187
|
+
def _flush_pending_knobs(self) -> None:
|
|
188
|
+
"""Push queued knob definitions to the backend before the window opens."""
|
|
189
|
+
if not self._pending_knobs:
|
|
190
|
+
return
|
|
191
|
+
from . import _protocol as P
|
|
192
|
+
from . import _codec as codec
|
|
193
|
+
|
|
194
|
+
session = self._ensure_session()
|
|
195
|
+
for spec in self._pending_knobs:
|
|
196
|
+
payload = codec.encode_req_update_property(
|
|
197
|
+
figure_id=spec["figure_id"],
|
|
198
|
+
axes_index=0,
|
|
199
|
+
series_index=0,
|
|
200
|
+
prop="add_knob",
|
|
201
|
+
f1=spec["value"],
|
|
202
|
+
f2=spec["min"],
|
|
203
|
+
f3=spec["max"],
|
|
204
|
+
str_val=spec["name"],
|
|
205
|
+
)
|
|
206
|
+
try:
|
|
207
|
+
session._request(P.REQ_UPDATE_PROPERTY, payload)
|
|
208
|
+
except Exception:
|
|
209
|
+
pass
|
|
210
|
+
self._knob_values[spec["name"]] = spec["value"]
|
|
211
|
+
self._pending_knobs.clear()
|
|
212
|
+
|
|
181
213
|
def shutdown(self):
|
|
182
214
|
"""Clean shutdown — stop live threads, close session."""
|
|
183
215
|
self._shutting_down = True
|
|
@@ -187,6 +219,10 @@ class _EasyState:
|
|
|
187
219
|
t.join(timeout=2.0)
|
|
188
220
|
self._live_threads.clear()
|
|
189
221
|
self._live_stop_events.clear()
|
|
222
|
+
self._pending_knobs.clear()
|
|
223
|
+
self._interactive_bindings.clear()
|
|
224
|
+
self._interactive_started = False
|
|
225
|
+
self._knob_values.clear()
|
|
190
226
|
if self._session is not None:
|
|
191
227
|
try:
|
|
192
228
|
self._session.close()
|
|
@@ -686,8 +722,22 @@ def violin_plot(
|
|
|
686
722
|
return series
|
|
687
723
|
|
|
688
724
|
|
|
689
|
-
def hline(
|
|
690
|
-
|
|
725
|
+
def hline(
|
|
726
|
+
y: float,
|
|
727
|
+
color: Union[str, Tuple, List, None] = "gray",
|
|
728
|
+
label: str = "",
|
|
729
|
+
*,
|
|
730
|
+
interactive: bool = False,
|
|
731
|
+
ymin: float = -10.0,
|
|
732
|
+
ymax: float = 10.0,
|
|
733
|
+
knob_name: str = "Y line",
|
|
734
|
+
):
|
|
735
|
+
"""Draw a horizontal reference line at y (e.g. ``hline(0)`` for the x-axis).
|
|
736
|
+
|
|
737
|
+
Set ``interactive=True`` (or use ``ihline``) to drag a slider that moves the line.
|
|
738
|
+
"""
|
|
739
|
+
if interactive:
|
|
740
|
+
return ihline(y, ymin, ymax, color=color, label=label, knob_name=knob_name)
|
|
691
741
|
ax = _state._ensure_axes()
|
|
692
742
|
series = ax.line([-1e12, 1e12], [y, y], label=label)
|
|
693
743
|
c = _parse_color(color)
|
|
@@ -697,8 +747,22 @@ def hline(y: float, color: Union[str, Tuple, List, None] = "gray", label: str =
|
|
|
697
747
|
return series
|
|
698
748
|
|
|
699
749
|
|
|
700
|
-
def vline(
|
|
701
|
-
|
|
750
|
+
def vline(
|
|
751
|
+
x: float,
|
|
752
|
+
color: Union[str, Tuple, List, None] = "gray",
|
|
753
|
+
label: str = "",
|
|
754
|
+
*,
|
|
755
|
+
interactive: bool = False,
|
|
756
|
+
xmin: float = -10.0,
|
|
757
|
+
xmax: float = 10.0,
|
|
758
|
+
knob_name: str = "X line",
|
|
759
|
+
):
|
|
760
|
+
"""Draw a vertical reference line at x (e.g. ``vline(0)`` for the y-axis).
|
|
761
|
+
|
|
762
|
+
Set ``interactive=True`` (or use ``ivline``) to drag a slider that moves the line.
|
|
763
|
+
"""
|
|
764
|
+
if interactive:
|
|
765
|
+
return ivline(x, xmin, xmax, color=color, label=label, knob_name=knob_name)
|
|
702
766
|
ax = _state._ensure_axes()
|
|
703
767
|
series = ax.line([x, x], [-1e12, 1e12], label=label)
|
|
704
768
|
c = _parse_color(color)
|
|
@@ -708,6 +772,283 @@ def vline(x: float, color: Union[str, Tuple, List, None] = "gray", label: str =
|
|
|
708
772
|
return series
|
|
709
773
|
|
|
710
774
|
|
|
775
|
+
def fplot(
|
|
776
|
+
func,
|
|
777
|
+
xmin: Optional[float] = None,
|
|
778
|
+
xmax: Optional[float] = None,
|
|
779
|
+
n: int = 200,
|
|
780
|
+
color: Union[str, Tuple, List, None] = None,
|
|
781
|
+
width: Optional[float] = None,
|
|
782
|
+
label: str = "",
|
|
783
|
+
*,
|
|
784
|
+
interactive: bool = False,
|
|
785
|
+
params: Optional[List[Tuple[str, float, float, float]]] = None,
|
|
786
|
+
**kwargs,
|
|
787
|
+
):
|
|
788
|
+
"""Plot y = func(x) over an x range.
|
|
789
|
+
|
|
790
|
+
Usage::
|
|
791
|
+
|
|
792
|
+
sp.fplot(lambda x: x ** 2, -2, 2)
|
|
793
|
+
sp.fplot(math.sin) # uses current axes x-range or [-1, 1]
|
|
794
|
+
sp.fplot(lambda x: x ** 2, color="red", label="parabola")
|
|
795
|
+
sp.ifplot(lambda x, a, b: a * x * x + b, -3, 3, params=[("a", 0.2, -1, 1)])
|
|
796
|
+
|
|
797
|
+
If *xmin* / *xmax* are omitted, uses accumulated axes bounds from prior plots
|
|
798
|
+
on the same axes, otherwise ``[-1, 1]``.
|
|
799
|
+
|
|
800
|
+
Set ``interactive=True`` with *params* ``[(name, value, min, max), ...]`` to
|
|
801
|
+
expose sliders for each coefficient (or use ``ifplot``).
|
|
802
|
+
"""
|
|
803
|
+
if interactive:
|
|
804
|
+
return ifplot(func, xmin, xmax, n=n, color=color, width=width, label=label,
|
|
805
|
+
params=params or [], **kwargs)
|
|
806
|
+
|
|
807
|
+
ax = _state._ensure_axes()
|
|
808
|
+
|
|
809
|
+
if xmin is None or xmax is None:
|
|
810
|
+
ax_key = (ax._figure_id, ax._index)
|
|
811
|
+
if ax_key in _state._axes_bounds:
|
|
812
|
+
bounds = _state._axes_bounds[ax_key]
|
|
813
|
+
if xmin is None:
|
|
814
|
+
xmin = bounds[0]
|
|
815
|
+
if xmax is None:
|
|
816
|
+
xmax = bounds[1]
|
|
817
|
+
else:
|
|
818
|
+
if xmin is None:
|
|
819
|
+
xmin = -1.0
|
|
820
|
+
if xmax is None:
|
|
821
|
+
xmax = 1.0
|
|
822
|
+
|
|
823
|
+
if xmin == xmax:
|
|
824
|
+
xmax = xmin + 1.0
|
|
825
|
+
|
|
826
|
+
n = max(int(n), 2)
|
|
827
|
+
step = (xmax - xmin) / (n - 1)
|
|
828
|
+
xs = [xmin + i * step for i in range(n)]
|
|
829
|
+
ys = [float(func(x)) for x in xs]
|
|
830
|
+
|
|
831
|
+
series = ax.line(xs, ys, label=label)
|
|
832
|
+
_apply_series_style(series, color=color, width=width, **kwargs)
|
|
833
|
+
_auto_fit_axes(ax, xs, ys)
|
|
834
|
+
_state._show_if_pending()
|
|
835
|
+
return series
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
# ─── Interactive reference lines & function plots ─────────────────────────────
|
|
839
|
+
|
|
840
|
+
_REF_SPAN = 1e12
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
class _InteractiveHLine:
|
|
844
|
+
__slots__ = ("series", "knob_name")
|
|
845
|
+
|
|
846
|
+
def __init__(self, series, knob_name: str) -> None:
|
|
847
|
+
self.series = series
|
|
848
|
+
self.knob_name = knob_name
|
|
849
|
+
|
|
850
|
+
def apply(self, knobs: dict) -> None:
|
|
851
|
+
if self.knob_name not in knobs:
|
|
852
|
+
return
|
|
853
|
+
y = float(knobs[self.knob_name])
|
|
854
|
+
self.series.set_data([-_REF_SPAN, _REF_SPAN], [y, y])
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
class _InteractiveVLine:
|
|
858
|
+
__slots__ = ("series", "knob_name")
|
|
859
|
+
|
|
860
|
+
def __init__(self, series, knob_name: str) -> None:
|
|
861
|
+
self.series = series
|
|
862
|
+
self.knob_name = knob_name
|
|
863
|
+
|
|
864
|
+
def apply(self, knobs: dict) -> None:
|
|
865
|
+
if self.knob_name not in knobs:
|
|
866
|
+
return
|
|
867
|
+
x = float(knobs[self.knob_name])
|
|
868
|
+
self.series.set_data([x, x], [-_REF_SPAN, _REF_SPAN])
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
class _InteractiveFplot:
|
|
872
|
+
__slots__ = ("series", "func", "xs", "param_names")
|
|
873
|
+
|
|
874
|
+
def __init__(self, series, func, xs: List[float], param_names: List[str]) -> None:
|
|
875
|
+
self.series = series
|
|
876
|
+
self.func = func
|
|
877
|
+
self.xs = xs
|
|
878
|
+
self.param_names = param_names
|
|
879
|
+
|
|
880
|
+
def apply(self, knobs: dict) -> None:
|
|
881
|
+
pvals = [float(knobs.get(n, 0.0)) for n in self.param_names]
|
|
882
|
+
ys = [float(self.func(x, *pvals)) for x in self.xs]
|
|
883
|
+
self.series.set_data(self.xs, ys)
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def _queue_knob(ax, name: str, value: float, vmin: float, vmax: float) -> None:
|
|
887
|
+
spec = {
|
|
888
|
+
"figure_id": ax._figure_id,
|
|
889
|
+
"name": name,
|
|
890
|
+
"value": float(value),
|
|
891
|
+
"min": float(vmin),
|
|
892
|
+
"max": float(vmax),
|
|
893
|
+
}
|
|
894
|
+
_state._knob_values[name] = float(value)
|
|
895
|
+
fig = _state._current_fig
|
|
896
|
+
if fig is not None and id(fig) not in _state._pending_show:
|
|
897
|
+
from . import _protocol as P
|
|
898
|
+
from . import _codec as codec
|
|
899
|
+
|
|
900
|
+
session = _state._ensure_session()
|
|
901
|
+
payload = codec.encode_req_update_property(
|
|
902
|
+
figure_id=spec["figure_id"],
|
|
903
|
+
axes_index=0,
|
|
904
|
+
series_index=0,
|
|
905
|
+
prop="add_knob",
|
|
906
|
+
f1=spec["value"],
|
|
907
|
+
f2=spec["min"],
|
|
908
|
+
f3=spec["max"],
|
|
909
|
+
str_val=spec["name"],
|
|
910
|
+
)
|
|
911
|
+
try:
|
|
912
|
+
session._request(P.REQ_UPDATE_PROPERTY, payload)
|
|
913
|
+
except Exception:
|
|
914
|
+
_state._pending_knobs.append(spec)
|
|
915
|
+
else:
|
|
916
|
+
_state._pending_knobs.append(spec)
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
def _poll_knob_values(session) -> dict:
|
|
920
|
+
from . import _protocol as P
|
|
921
|
+
from . import _codec as codec
|
|
922
|
+
|
|
923
|
+
try:
|
|
924
|
+
resp = session._request(P.REQ_GET_SNAPSHOT, b"")
|
|
925
|
+
payload = resp["payload"]
|
|
926
|
+
if payload and payload[0] == P.PAYLOAD_FORMAT_FLATBUFFERS:
|
|
927
|
+
from . import _codec_fb as fb_codec
|
|
928
|
+
return fb_codec.decode_fb_snapshot_knobs(payload)
|
|
929
|
+
except Exception:
|
|
930
|
+
pass
|
|
931
|
+
return dict(_state._knob_values)
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
def _ensure_interactive_loop() -> None:
|
|
935
|
+
if _state._interactive_started or not _state._interactive_bindings:
|
|
936
|
+
return
|
|
937
|
+
_state._interactive_started = True
|
|
938
|
+
from ._animation import ipc_sleep
|
|
939
|
+
from ._log import log
|
|
940
|
+
|
|
941
|
+
stop_event = threading.Event()
|
|
942
|
+
_state._live_stop_events.append(stop_event)
|
|
943
|
+
|
|
944
|
+
def _loop() -> None:
|
|
945
|
+
session = _state._ensure_session()
|
|
946
|
+
session._live_thread_count += 1
|
|
947
|
+
try:
|
|
948
|
+
while not stop_event.is_set():
|
|
949
|
+
ipc_sleep(0.05, session)
|
|
950
|
+
knobs = _poll_knob_values(session)
|
|
951
|
+
_state._knob_values.update(knobs)
|
|
952
|
+
for binding in _state._interactive_bindings:
|
|
953
|
+
try:
|
|
954
|
+
binding.apply(knobs)
|
|
955
|
+
except Exception as e:
|
|
956
|
+
log.warning("interactive update error: %s", e)
|
|
957
|
+
finally:
|
|
958
|
+
session._live_thread_count -= 1
|
|
959
|
+
|
|
960
|
+
thread = threading.Thread(target=_loop, daemon=True, name="spectra-interactive")
|
|
961
|
+
thread.start()
|
|
962
|
+
_state._live_threads.append(thread)
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
def ihline(
|
|
966
|
+
y: float,
|
|
967
|
+
ymin: float = -10.0,
|
|
968
|
+
ymax: float = 10.0,
|
|
969
|
+
color: Union[str, Tuple, List, None] = "gray",
|
|
970
|
+
label: str = "",
|
|
971
|
+
knob_name: str = "Y line",
|
|
972
|
+
):
|
|
973
|
+
"""Interactive horizontal line — drag the PARAMETERS slider to move y."""
|
|
974
|
+
series = hline(y, color=color, label=label)
|
|
975
|
+
ax = _state._ensure_axes()
|
|
976
|
+
_queue_knob(ax, knob_name, y, ymin, ymax)
|
|
977
|
+
_state._interactive_bindings.append(_InteractiveHLine(series, knob_name))
|
|
978
|
+
_state._show_if_pending()
|
|
979
|
+
return series
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
def ivline(
|
|
983
|
+
x: float,
|
|
984
|
+
xmin: float = -10.0,
|
|
985
|
+
xmax: float = 10.0,
|
|
986
|
+
color: Union[str, Tuple, List, None] = "gray",
|
|
987
|
+
label: str = "",
|
|
988
|
+
knob_name: str = "X line",
|
|
989
|
+
):
|
|
990
|
+
"""Interactive vertical line — drag the PARAMETERS slider to move x."""
|
|
991
|
+
series = vline(x, color=color, label=label)
|
|
992
|
+
ax = _state._ensure_axes()
|
|
993
|
+
_queue_knob(ax, knob_name, x, xmin, xmax)
|
|
994
|
+
_state._interactive_bindings.append(_InteractiveVLine(series, knob_name))
|
|
995
|
+
_state._show_if_pending()
|
|
996
|
+
return series
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
def ifplot(
|
|
1000
|
+
func,
|
|
1001
|
+
xmin: Optional[float] = None,
|
|
1002
|
+
xmax: Optional[float] = None,
|
|
1003
|
+
n: int = 200,
|
|
1004
|
+
color: Union[str, Tuple, List, None] = None,
|
|
1005
|
+
width: Optional[float] = None,
|
|
1006
|
+
label: str = "",
|
|
1007
|
+
params: Optional[List[Tuple[str, float, float, float]]] = None,
|
|
1008
|
+
**kwargs,
|
|
1009
|
+
):
|
|
1010
|
+
"""Interactive function plot — sliders retune each entry in *params*.
|
|
1011
|
+
|
|
1012
|
+
*func* signature: ``func(x, *param_values)`` matching *params* order::
|
|
1013
|
+
|
|
1014
|
+
sp.ifplot(lambda x, a, b: a * x * x + b, -3, 3,
|
|
1015
|
+
params=[("a", 0.2, -1, 1), ("b", 0, -2, 2)])
|
|
1016
|
+
"""
|
|
1017
|
+
param_specs = params or []
|
|
1018
|
+
ax = _state._ensure_axes()
|
|
1019
|
+
|
|
1020
|
+
if xmin is None or xmax is None:
|
|
1021
|
+
ax_key = (ax._figure_id, ax._index)
|
|
1022
|
+
if ax_key in _state._axes_bounds:
|
|
1023
|
+
bounds = _state._axes_bounds[ax_key]
|
|
1024
|
+
xmin = xmin if xmin is not None else bounds[0]
|
|
1025
|
+
xmax = xmax if xmax is not None else bounds[1]
|
|
1026
|
+
else:
|
|
1027
|
+
xmin = xmin if xmin is not None else -1.0
|
|
1028
|
+
xmax = xmax if xmax is not None else 1.0
|
|
1029
|
+
if xmin == xmax:
|
|
1030
|
+
xmax = xmin + 1.0
|
|
1031
|
+
|
|
1032
|
+
n = max(int(n), 2)
|
|
1033
|
+
step = (xmax - xmin) / (n - 1)
|
|
1034
|
+
xs = [xmin + i * step for i in range(n)]
|
|
1035
|
+
pvals = [p[1] for p in param_specs]
|
|
1036
|
+
ys = [float(func(x, *pvals)) for x in xs]
|
|
1037
|
+
|
|
1038
|
+
series = ax.line(xs, ys, label=label)
|
|
1039
|
+
_apply_series_style(series, color=color, width=width, **kwargs)
|
|
1040
|
+
_auto_fit_axes(ax, xs, ys)
|
|
1041
|
+
|
|
1042
|
+
param_names: List[str] = []
|
|
1043
|
+
for name, value, vmin, vmax in param_specs:
|
|
1044
|
+
_queue_knob(ax, name, value, vmin, vmax)
|
|
1045
|
+
param_names.append(name)
|
|
1046
|
+
|
|
1047
|
+
_state._interactive_bindings.append(_InteractiveFplot(series, func, xs, param_names))
|
|
1048
|
+
_state._show_if_pending()
|
|
1049
|
+
return series
|
|
1050
|
+
|
|
1051
|
+
|
|
711
1052
|
# ─── Auto-fit helper ─────────────────────────────────────────────────────────
|
|
712
1053
|
|
|
713
1054
|
def _auto_fit_axes(ax, x: List[float], y: List[float]) -> None:
|
|
@@ -76,7 +76,7 @@ def _find_library() -> str:
|
|
|
76
76
|
return env_path
|
|
77
77
|
|
|
78
78
|
# 2. Next to this file (installed package)
|
|
79
|
-
pkg_dir = Path(__file__).parent
|
|
79
|
+
pkg_dir = Path(__file__).resolve().parent
|
|
80
80
|
for candidate in [
|
|
81
81
|
pkg_dir / "libspectra_embed.so",
|
|
82
82
|
pkg_dir / "spectra_embed.dll",
|
|
@@ -93,9 +93,9 @@ def _find_library() -> str:
|
|
|
93
93
|
if candidate.is_file():
|
|
94
94
|
return str(candidate)
|
|
95
95
|
|
|
96
|
-
# 4. System search
|
|
96
|
+
# 4. System search (only accept resolvable absolute paths)
|
|
97
97
|
found = ctypes.util.find_library("spectra_embed")
|
|
98
|
-
if found:
|
|
98
|
+
if found and os.path.isabs(found) and os.path.isfile(found):
|
|
99
99
|
return found
|
|
100
100
|
|
|
101
101
|
raise FileNotFoundError(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spectra-plot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: GPU-accelerated scientific plotting via IPC
|
|
5
5
|
License: MIT
|
|
6
6
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -15,8 +15,10 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
15
15
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
16
16
|
Requires-Python: >=3.9
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: flatbuffers>=2.0
|
|
18
19
|
Provides-Extra: numpy
|
|
19
20
|
Requires-Dist: numpy>=1.20; extra == "numpy"
|
|
20
21
|
Provides-Extra: dev
|
|
21
22
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
22
23
|
Requires-Dist: numpy>=1.20; extra == "dev"
|
|
24
|
+
Requires-Dist: flatbuffers>=2.0; extra == "dev"
|
|
@@ -190,7 +190,7 @@ class TestAPISurface:
|
|
|
190
190
|
"""Verify all expected functions are importable."""
|
|
191
191
|
|
|
192
192
|
def test_plot_functions(self):
|
|
193
|
-
from spectra import plot, scatter, stem, hist, bar, hline, vline
|
|
193
|
+
from spectra import plot, scatter, stem, hist, bar, hline, vline, fplot
|
|
194
194
|
assert callable(plot)
|
|
195
195
|
assert callable(scatter)
|
|
196
196
|
assert callable(stem)
|
|
@@ -198,6 +198,7 @@ class TestAPISurface:
|
|
|
198
198
|
assert callable(bar)
|
|
199
199
|
assert callable(hline)
|
|
200
200
|
assert callable(vline)
|
|
201
|
+
assert callable(fplot)
|
|
201
202
|
|
|
202
203
|
def test_3d_functions(self):
|
|
203
204
|
from spectra import plot3, scatter3, surf
|
|
@@ -247,7 +248,7 @@ class TestAPISurface:
|
|
|
247
248
|
def test_all_in_all(self):
|
|
248
249
|
import spectra
|
|
249
250
|
expected = [
|
|
250
|
-
"plot", "scatter", "stem", "hist", "bar", "hline", "vline",
|
|
251
|
+
"plot", "scatter", "stem", "hist", "bar", "hline", "vline", "fplot",
|
|
251
252
|
"plot3", "scatter3", "surf", "plotn", "subplots",
|
|
252
253
|
"figure", "subplot", "gcf", "gca",
|
|
253
254
|
"title", "xlabel", "ylabel", "xlim", "ylim", "grid", "legend",
|
|
@@ -6,8 +6,8 @@ import tempfile
|
|
|
6
6
|
|
|
7
7
|
# Skip render tests if libspectra_embed.so is not built.
|
|
8
8
|
try:
|
|
9
|
-
from spectra._embed import
|
|
10
|
-
|
|
9
|
+
from spectra._embed import _load_lib
|
|
10
|
+
_load_lib()
|
|
11
11
|
_EMBED_AVAILABLE = True
|
|
12
12
|
except (ImportError, FileNotFoundError, OSError):
|
|
13
13
|
_EMBED_AVAILABLE = False
|
|
@@ -8,7 +8,7 @@ import ctypes
|
|
|
8
8
|
# Use a flag + @pytest.mark.skipif on each test class instead.
|
|
9
9
|
try:
|
|
10
10
|
from spectra._embed import (
|
|
11
|
-
|
|
11
|
+
_load_lib,
|
|
12
12
|
EmbedSurface,
|
|
13
13
|
EmbedFigure,
|
|
14
14
|
EmbedAxes,
|
|
@@ -22,7 +22,7 @@ try:
|
|
|
22
22
|
KEY_R,
|
|
23
23
|
KEY_ESCAPE,
|
|
24
24
|
)
|
|
25
|
-
|
|
25
|
+
_load_lib() # probe load (not just path lookup) so missing deps skip cleanly
|
|
26
26
|
_EMBED_AVAILABLE = True
|
|
27
27
|
except (ImportError, FileNotFoundError, OSError):
|
|
28
28
|
_EMBED_AVAILABLE = False
|
|
@@ -259,7 +259,7 @@ class TestConvenienceAPI:
|
|
|
259
259
|
def test_version_exists(self):
|
|
260
260
|
import spectra as sp
|
|
261
261
|
assert hasattr(sp, "__version__")
|
|
262
|
-
assert sp.__version__ == "0.2.
|
|
262
|
+
assert sp.__version__ == "0.2.1"
|
|
263
263
|
|
|
264
264
|
def test_session_class_exported(self):
|
|
265
265
|
from spectra import Session
|
spectra_plot-0.2.7/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.2.7
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/AckStatePayload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/DiffOpType.py
RENAMED
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/EvtInputPayload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/HelloPayload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqSetDataPayload.py
RENAMED
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/ReqShowPayload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespErrPayload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/RespOkPayload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/SnapshotAxisState.py
RENAMED
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/SnapshotKnobState.py
RENAMED
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/StateDiffPayload.py
RENAMED
|
File without changes
|
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/TopicInfoEntry.py
RENAMED
|
File without changes
|
{spectra_plot-0.2.7 → spectra_plot-0.3.0}/spectra/_fb_generated/spectra/ipc/fb/WelcomePayload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|