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.
Files changed (119) hide show
  1. qplot/__init__.py +46 -0
  2. qplot/__main__.py +232 -0
  3. qplot/_auxiliary_paths.py +63 -0
  4. qplot/_metadata.py +12 -0
  5. qplot/_repair.py +14 -0
  6. qplot/_shutdown_supervisor.py +4049 -0
  7. qplot/_version.py +12 -0
  8. qplot/_windows_shutdown_job.py +1166 -0
  9. qplot/configuration/__init__.py +3 -0
  10. qplot/configuration/config.py +573 -0
  11. qplot/configuration/config_schema.json +319 -0
  12. qplot/configuration/scripts.py +255 -0
  13. qplot/configuration/themes/__init__.py +13 -0
  14. qplot/configuration/themes/_base.py +579 -0
  15. qplot/configuration/themes/blank.py +17 -0
  16. qplot/configuration/themes/dark.py +54 -0
  17. qplot/configuration/themes/light.py +54 -0
  18. qplot/datahandling/LoadFromDB.py +224 -0
  19. qplot/datahandling/__init__.py +47 -0
  20. qplot/datahandling/_trusted_live_helper.py +812 -0
  21. qplot/datahandling/_trusted_live_protocol.py +1745 -0
  22. qplot/datahandling/database.py +2330 -0
  23. qplot/datahandling/dimensions.py +43 -0
  24. qplot/datahandling/file_identity.py +461 -0
  25. qplot/datahandling/parameter_data.py +149 -0
  26. qplot/datahandling/plot_progress.py +17 -0
  27. qplot/datahandling/qcodes_cache.py +277 -0
  28. qplot/datahandling/qcodes_compat.py +14 -0
  29. qplot/datahandling/readSQL.py +2442 -0
  30. qplot/datahandling/readonly.py +2561 -0
  31. qplot/datahandling/source_activity.py +21 -0
  32. qplot/datahandling/trusted_array_preview.py +127 -0
  33. qplot/datahandling/trusted_derived_cache.py +1605 -0
  34. qplot/datahandling/trusted_derived_rendering.py +868 -0
  35. qplot/datahandling/trusted_heatmap.py +241 -0
  36. qplot/datahandling/trusted_live.py +2808 -0
  37. qplot/datahandling/trusted_live_queries.py +5907 -0
  38. qplot/datahandling/trusted_live_service.py +1894 -0
  39. qplot/datahandling/trusted_live_supervisor.py +2161 -0
  40. qplot/datahandling/trusted_plot.py +283 -0
  41. qplot/datahandling/trusted_presentation.py +1065 -0
  42. qplot/datahandling/trusted_snapshot.py +1132 -0
  43. qplot/datahandling/trusted_work_coordinator.py +2157 -0
  44. qplot/datahandling/trusted_work_scheduler.py +1204 -0
  45. qplot/diagnostics.py +241 -0
  46. qplot/resources/testdata/qplot_test_db_01_10mb.csv +11 -0
  47. qplot/resources/testdata/qplot_test_db_02_25mb.csv +14 -0
  48. qplot/resources/testdata/qplot_test_db_03_50mb.csv +17 -0
  49. qplot/resources/testdata/qplot_test_db_04_100mb.csv +20 -0
  50. qplot/resources/testdata/qplot_test_db_05_250mb.csv +23 -0
  51. qplot/resources/testdata/qplot_test_db_06_500mb.csv +26 -0
  52. qplot/resources/testdata/qplot_test_db_07_1gb.csv +29 -0
  53. qplot/resources/testdata/qplot_test_db_08_5gb.csv +32 -0
  54. qplot/resources/testdata/qplot_test_db_09_10gb.csv +35 -0
  55. qplot/resources/testdata/qplot_test_db_10_30gb.csv +38 -0
  56. qplot/testdata.py +1733 -0
  57. qplot/tools/__init__.py +13 -0
  58. qplot/tools/finite_means.py +114 -0
  59. qplot/tools/general.py +134 -0
  60. qplot/tools/heatmap_geometry.py +381 -0
  61. qplot/tools/operation_registry.py +179 -0
  62. qplot/tools/plot_tools.py +625 -0
  63. qplot/tools/sample_statistics.py +56 -0
  64. qplot/tools/worker.py +2787 -0
  65. qplot/windows/__init__.py +9 -0
  66. qplot/windows/_colorbar.py +422 -0
  67. qplot/windows/_commands.py +523 -0
  68. qplot/windows/_config_persistence.py +123 -0
  69. qplot/windows/_database_actions.py +4904 -0
  70. qplot/windows/_dataset_handle.py +221 -0
  71. qplot/windows/_dragdrop.py +71 -0
  72. qplot/windows/_export_paths.py +1167 -0
  73. qplot/windows/_help.py +169 -0
  74. qplot/windows/_native_averaging.py +173 -0
  75. qplot/windows/_native_transforms.py +389 -0
  76. qplot/windows/_plot1d_snap.py +608 -0
  77. qplot/windows/_plot1d_traces.py +2183 -0
  78. qplot/windows/_plot2d_colorbar.py +1126 -0
  79. qplot/windows/_plot2d_colorbar_dialog.py +786 -0
  80. qplot/windows/_plot2d_layers.py +2197 -0
  81. qplot/windows/_plot2d_sweeps.py +712 -0
  82. qplot/windows/_plotWin.py +1993 -0
  83. qplot/windows/_plot_actions.py +2695 -0
  84. qplot/windows/_plot_appearance.py +276 -0
  85. qplot/windows/_plot_axis_scaling.py +1485 -0
  86. qplot/windows/_plot_export.py +1445 -0
  87. qplot/windows/_plot_feedback.py +110 -0
  88. qplot/windows/_plot_marquee.py +656 -0
  89. qplot/windows/_plot_refresh.py +942 -0
  90. qplot/windows/_plot_state.py +239 -0
  91. qplot/windows/_plot_transform_labels.py +60 -0
  92. qplot/windows/_preferences.py +635 -0
  93. qplot/windows/_refresh_interval.py +70 -0
  94. qplot/windows/_run_controls.py +828 -0
  95. qplot/windows/_shortcuts.py +47 -0
  96. qplot/windows/_subplots/__init__.py +8 -0
  97. qplot/windows/_subplots/subplot1d.py +531 -0
  98. qplot/windows/_subplots/subplot2d.py +918 -0
  99. qplot/windows/_svg_export.py +209 -0
  100. qplot/windows/_trusted_derived_qt.py +1759 -0
  101. qplot/windows/_widgets/__init__.py +23 -0
  102. qplot/windows/_widgets/_run_formatting.py +387 -0
  103. qplot/windows/_widgets/details_tables.py +1119 -0
  104. qplot/windows/_widgets/dropbox.py +290 -0
  105. qplot/windows/_widgets/operations.py +460 -0
  106. qplot/windows/_widgets/preview.py +2997 -0
  107. qplot/windows/_widgets/run_list_items.py +488 -0
  108. qplot/windows/_widgets/toolbar.py +111 -0
  109. qplot/windows/_widgets/treeWidgets.py +2572 -0
  110. qplot/windows/_window_controls.py +413 -0
  111. qplot/windows/main.py +1635 -0
  112. qplot/windows/plot1d.py +311 -0
  113. qplot/windows/plot2d.py +1901 -0
  114. qplotter-1.6.0b3.dist-info/METADATA +318 -0
  115. qplotter-1.6.0b3.dist-info/RECORD +119 -0
  116. qplotter-1.6.0b3.dist-info/WHEEL +5 -0
  117. qplotter-1.6.0b3.dist-info/entry_points.txt +4 -0
  118. qplotter-1.6.0b3.dist-info/licenses/LICENSE +21 -0
  119. 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())