qplotter 1.6.0b3__py3-none-any.whl
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.
- qplot/__init__.py +46 -0
- qplot/__main__.py +232 -0
- qplot/_auxiliary_paths.py +63 -0
- qplot/_metadata.py +12 -0
- qplot/_repair.py +14 -0
- qplot/_shutdown_supervisor.py +4049 -0
- qplot/_version.py +12 -0
- qplot/_windows_shutdown_job.py +1166 -0
- qplot/configuration/__init__.py +3 -0
- qplot/configuration/config.py +573 -0
- qplot/configuration/config_schema.json +319 -0
- qplot/configuration/scripts.py +255 -0
- qplot/configuration/themes/__init__.py +13 -0
- qplot/configuration/themes/_base.py +579 -0
- qplot/configuration/themes/blank.py +17 -0
- qplot/configuration/themes/dark.py +54 -0
- qplot/configuration/themes/light.py +54 -0
- qplot/datahandling/LoadFromDB.py +224 -0
- qplot/datahandling/__init__.py +47 -0
- qplot/datahandling/_trusted_live_helper.py +812 -0
- qplot/datahandling/_trusted_live_protocol.py +1745 -0
- qplot/datahandling/database.py +2330 -0
- qplot/datahandling/dimensions.py +43 -0
- qplot/datahandling/file_identity.py +461 -0
- qplot/datahandling/parameter_data.py +149 -0
- qplot/datahandling/plot_progress.py +17 -0
- qplot/datahandling/qcodes_cache.py +277 -0
- qplot/datahandling/qcodes_compat.py +14 -0
- qplot/datahandling/readSQL.py +2442 -0
- qplot/datahandling/readonly.py +2561 -0
- qplot/datahandling/source_activity.py +21 -0
- qplot/datahandling/trusted_array_preview.py +127 -0
- qplot/datahandling/trusted_derived_cache.py +1605 -0
- qplot/datahandling/trusted_derived_rendering.py +868 -0
- qplot/datahandling/trusted_heatmap.py +241 -0
- qplot/datahandling/trusted_live.py +2808 -0
- qplot/datahandling/trusted_live_queries.py +5907 -0
- qplot/datahandling/trusted_live_service.py +1894 -0
- qplot/datahandling/trusted_live_supervisor.py +2161 -0
- qplot/datahandling/trusted_plot.py +283 -0
- qplot/datahandling/trusted_presentation.py +1065 -0
- qplot/datahandling/trusted_snapshot.py +1132 -0
- qplot/datahandling/trusted_work_coordinator.py +2157 -0
- qplot/datahandling/trusted_work_scheduler.py +1204 -0
- qplot/diagnostics.py +241 -0
- qplot/resources/testdata/qplot_test_db_01_10mb.csv +11 -0
- qplot/resources/testdata/qplot_test_db_02_25mb.csv +14 -0
- qplot/resources/testdata/qplot_test_db_03_50mb.csv +17 -0
- qplot/resources/testdata/qplot_test_db_04_100mb.csv +20 -0
- qplot/resources/testdata/qplot_test_db_05_250mb.csv +23 -0
- qplot/resources/testdata/qplot_test_db_06_500mb.csv +26 -0
- qplot/resources/testdata/qplot_test_db_07_1gb.csv +29 -0
- qplot/resources/testdata/qplot_test_db_08_5gb.csv +32 -0
- qplot/resources/testdata/qplot_test_db_09_10gb.csv +35 -0
- qplot/resources/testdata/qplot_test_db_10_30gb.csv +38 -0
- qplot/testdata.py +1733 -0
- qplot/tools/__init__.py +13 -0
- qplot/tools/finite_means.py +114 -0
- qplot/tools/general.py +134 -0
- qplot/tools/heatmap_geometry.py +381 -0
- qplot/tools/operation_registry.py +179 -0
- qplot/tools/plot_tools.py +625 -0
- qplot/tools/sample_statistics.py +56 -0
- qplot/tools/worker.py +2787 -0
- qplot/windows/__init__.py +9 -0
- qplot/windows/_colorbar.py +422 -0
- qplot/windows/_commands.py +523 -0
- qplot/windows/_config_persistence.py +123 -0
- qplot/windows/_database_actions.py +4904 -0
- qplot/windows/_dataset_handle.py +221 -0
- qplot/windows/_dragdrop.py +71 -0
- qplot/windows/_export_paths.py +1167 -0
- qplot/windows/_help.py +169 -0
- qplot/windows/_native_averaging.py +173 -0
- qplot/windows/_native_transforms.py +389 -0
- qplot/windows/_plot1d_snap.py +608 -0
- qplot/windows/_plot1d_traces.py +2183 -0
- qplot/windows/_plot2d_colorbar.py +1126 -0
- qplot/windows/_plot2d_colorbar_dialog.py +786 -0
- qplot/windows/_plot2d_layers.py +2197 -0
- qplot/windows/_plot2d_sweeps.py +712 -0
- qplot/windows/_plotWin.py +1993 -0
- qplot/windows/_plot_actions.py +2695 -0
- qplot/windows/_plot_appearance.py +276 -0
- qplot/windows/_plot_axis_scaling.py +1485 -0
- qplot/windows/_plot_export.py +1445 -0
- qplot/windows/_plot_feedback.py +110 -0
- qplot/windows/_plot_marquee.py +656 -0
- qplot/windows/_plot_refresh.py +942 -0
- qplot/windows/_plot_state.py +239 -0
- qplot/windows/_plot_transform_labels.py +60 -0
- qplot/windows/_preferences.py +635 -0
- qplot/windows/_refresh_interval.py +70 -0
- qplot/windows/_run_controls.py +828 -0
- qplot/windows/_shortcuts.py +47 -0
- qplot/windows/_subplots/__init__.py +8 -0
- qplot/windows/_subplots/subplot1d.py +531 -0
- qplot/windows/_subplots/subplot2d.py +918 -0
- qplot/windows/_svg_export.py +209 -0
- qplot/windows/_trusted_derived_qt.py +1759 -0
- qplot/windows/_widgets/__init__.py +23 -0
- qplot/windows/_widgets/_run_formatting.py +387 -0
- qplot/windows/_widgets/details_tables.py +1119 -0
- qplot/windows/_widgets/dropbox.py +290 -0
- qplot/windows/_widgets/operations.py +460 -0
- qplot/windows/_widgets/preview.py +2997 -0
- qplot/windows/_widgets/run_list_items.py +488 -0
- qplot/windows/_widgets/toolbar.py +111 -0
- qplot/windows/_widgets/treeWidgets.py +2572 -0
- qplot/windows/_window_controls.py +413 -0
- qplot/windows/main.py +1635 -0
- qplot/windows/plot1d.py +311 -0
- qplot/windows/plot2d.py +1901 -0
- qplotter-1.6.0b3.dist-info/METADATA +318 -0
- qplotter-1.6.0b3.dist-info/RECORD +119 -0
- qplotter-1.6.0b3.dist-info/WHEEL +5 -0
- qplotter-1.6.0b3.dist-info/entry_points.txt +4 -0
- qplotter-1.6.0b3.dist-info/licenses/LICENSE +21 -0
- qplotter-1.6.0b3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Filesystem evidence of acquisition activity, without opening SQLite files."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import stat
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def source_activity_timestamp(database_path):
|
|
8
|
+
"""Return the latest main/WAL modification time; never use SHM or the clock.
|
|
9
|
+
|
|
10
|
+
This is a database-wide estimate for unfinished runs, not a recorded run
|
|
11
|
+
completion time. Merely viewing an idle database cannot advance it.
|
|
12
|
+
"""
|
|
13
|
+
timestamps = []
|
|
14
|
+
for path in (os.fspath(database_path), f"{os.fspath(database_path)}-wal"):
|
|
15
|
+
try:
|
|
16
|
+
observation = os.stat(path)
|
|
17
|
+
except OSError:
|
|
18
|
+
continue
|
|
19
|
+
if stat.S_ISREG(observation.st_mode) and observation.st_size:
|
|
20
|
+
timestamps.append(observation.st_mtime)
|
|
21
|
+
return max(timestamps, default=None)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""Bounded QCoDeS array previews using stored coordinates within each record."""
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import math
|
|
5
|
+
from bisect import bisect_left
|
|
6
|
+
from dataclasses import replace
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from .trusted_live_queries import TRUSTED_DERIVED_MAX_SAMPLE_ROWS
|
|
11
|
+
|
|
12
|
+
MAX_SAMPLES = 131_072
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _decode(value):
|
|
16
|
+
from .trusted_derived_rendering import _UnsupportedNumericData
|
|
17
|
+
|
|
18
|
+
if not isinstance(value, bytes):
|
|
19
|
+
return np.asarray([value])
|
|
20
|
+
try:
|
|
21
|
+
stream = io.BytesIO(value)
|
|
22
|
+
version = np.lib.format.read_magic(stream)
|
|
23
|
+
if version not in {(1, 0), (2, 0), (3, 0)}:
|
|
24
|
+
raise ValueError("Unsupported NPY version")
|
|
25
|
+
# Numeric headers are ASCII in both v2 and QCoDeS' v3; the latter
|
|
26
|
+
# changes only the encoding of structured dtype field names, which
|
|
27
|
+
# this renderer rejects below.
|
|
28
|
+
reader = (np.lib.format.read_array_header_1_0 if version == (1, 0)
|
|
29
|
+
else np.lib.format.read_array_header_2_0)
|
|
30
|
+
shape, fortran, dtype = reader(stream)
|
|
31
|
+
count = math.prod(shape)
|
|
32
|
+
if dtype.kind not in "biuf" or not 0 <= count <= MAX_SAMPLES:
|
|
33
|
+
raise ValueError("Unsupported array dtype or size")
|
|
34
|
+
if len(value) - stream.tell() != count * dtype.itemsize:
|
|
35
|
+
raise ValueError("Invalid array payload size")
|
|
36
|
+
# Validate the header and exact payload length before allocating. Never
|
|
37
|
+
# load pickled object arrays or allocate from an unchecked NPY shape.
|
|
38
|
+
return np.frombuffer(value, dtype=dtype, offset=stream.tell()).reshape(
|
|
39
|
+
shape, order="F" if fortran else "C",
|
|
40
|
+
).ravel()
|
|
41
|
+
except (ValueError, KeyError, EOFError, OverflowError) as error:
|
|
42
|
+
raise _UnsupportedNumericData("The array sample cannot be decoded safely.") from error
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def render_array_preview(observation, dependencies, dependent, width, height, check):
|
|
46
|
+
from .trusted_derived_rendering import (
|
|
47
|
+
_MISSING_CELL_RGBA,
|
|
48
|
+
_finite_number,
|
|
49
|
+
_pixel,
|
|
50
|
+
_render_1d,
|
|
51
|
+
_UnsupportedNumericData,
|
|
52
|
+
_viridis_rgba,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
indexes = [observation.sample_columns.index(name)
|
|
56
|
+
for name in (*dependencies, dependent)]
|
|
57
|
+
points = []
|
|
58
|
+
expanded_count = 0
|
|
59
|
+
for row in observation.sample_rows:
|
|
60
|
+
check()
|
|
61
|
+
if any(row[index] is None for index in indexes):
|
|
62
|
+
continue
|
|
63
|
+
columns = [_decode(row[index]) for index in indexes]
|
|
64
|
+
size = max(column.size for column in columns)
|
|
65
|
+
if any(column.size != (size if isinstance(row[source], bytes) else 1)
|
|
66
|
+
for source, column in zip(indexes, columns, strict=True)):
|
|
67
|
+
raise _UnsupportedNumericData("Array measurement and setpoint sizes differ.")
|
|
68
|
+
expanded_count += size
|
|
69
|
+
if expanded_count > MAX_SAMPLES:
|
|
70
|
+
raise _UnsupportedNumericData("The array preview exceeds its sample budget.")
|
|
71
|
+
for index in range(size):
|
|
72
|
+
if index % 128 == 0:
|
|
73
|
+
check()
|
|
74
|
+
values = tuple(_finite_number(column[0 if column.size == 1 else index].item())
|
|
75
|
+
for column in columns)
|
|
76
|
+
if all(value is not None for value in values[:-1]):
|
|
77
|
+
points.append(values)
|
|
78
|
+
if not points:
|
|
79
|
+
raise _UnsupportedNumericData("No bounded numeric array samples are available.")
|
|
80
|
+
if len(dependencies) == 1:
|
|
81
|
+
# Keep both endpoints while limiting the ordinary line renderer's input.
|
|
82
|
+
selected = np.linspace(0, len(points) - 1,
|
|
83
|
+
min(len(points), TRUSTED_DERIVED_MAX_SAMPLE_ROWS), dtype=int)
|
|
84
|
+
rows = tuple((i + 1, *points[index]) for i, index in enumerate(selected))
|
|
85
|
+
sampled = replace(observation, sample_columns=("id", *dependencies, dependent),
|
|
86
|
+
sample_rows=rows, validated_2d_layouts=())
|
|
87
|
+
return _render_1d(sampled, dependencies[0], dependent, width, height, check)
|
|
88
|
+
|
|
89
|
+
# Build cells from actual paired coordinates, never from planned shapes or
|
|
90
|
+
# physical row IDs (one QCoDeS row can contain an entire oscilloscope trace).
|
|
91
|
+
vertical = sorted({point[0] for point in points})
|
|
92
|
+
horizontal = sorted({point[1] for point in points})
|
|
93
|
+
if len(vertical) * len(horizontal) > MAX_SAMPLES:
|
|
94
|
+
raise _UnsupportedNumericData("The array preview grid exceeds its cell budget.")
|
|
95
|
+
cells = {}
|
|
96
|
+
for y, x, z in points:
|
|
97
|
+
if z is not None:
|
|
98
|
+
cells.setdefault((y, x), []).append(z)
|
|
99
|
+
if not cells:
|
|
100
|
+
raise _UnsupportedNumericData("No finite array measurements are available.")
|
|
101
|
+
values = {}
|
|
102
|
+
for key, samples in cells.items():
|
|
103
|
+
check()
|
|
104
|
+
scale = max(abs(value) for value in samples)
|
|
105
|
+
values[key] = (math.fsum(value / scale / len(samples) for value in samples)
|
|
106
|
+
* scale if scale else 0.)
|
|
107
|
+
low, high = min(values.values()), max(values.values())
|
|
108
|
+
|
|
109
|
+
def pixel_axis(axis, count):
|
|
110
|
+
span = axis[-1] - axis[0]
|
|
111
|
+
if not math.isfinite(span):
|
|
112
|
+
raise _UnsupportedNumericData("Array coordinates exceed the finite range.")
|
|
113
|
+
normalized = [(value - axis[0]) / (span or 1.) for value in axis]
|
|
114
|
+
edges = [(left + right) / 2
|
|
115
|
+
for left, right in zip(normalized, normalized[1:], strict=False)]
|
|
116
|
+
return [axis[bisect_left(edges, index / max(1, count - 1))]
|
|
117
|
+
for index in range(count)]
|
|
118
|
+
|
|
119
|
+
xs, ys = pixel_axis(horizontal, width), pixel_axis(vertical, height)[::-1]
|
|
120
|
+
rgba = bytearray(width * height * 4)
|
|
121
|
+
for py, y in enumerate(ys):
|
|
122
|
+
check()
|
|
123
|
+
for px, x in enumerate(xs):
|
|
124
|
+
value = values.get((y, x))
|
|
125
|
+
color = _MISSING_CELL_RGBA if value is None else _viridis_rgba(value, low, high)
|
|
126
|
+
_pixel(rgba, width, px, py, color)
|
|
127
|
+
return rgba, sum(len(samples) for samples in cells.values())
|