qubitclient 0.1.4__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 (81) hide show
  1. qubitclient/__init__.py +5 -0
  2. qubitclient/draw/__init__.py +0 -0
  3. qubitclient/draw/optpipulsepltplotter.py +75 -0
  4. qubitclient/draw/optpipulseplyplotter.py +114 -0
  5. qubitclient/draw/pltmanager.py +50 -0
  6. qubitclient/draw/pltplotter.py +20 -0
  7. qubitclient/draw/plymanager.py +57 -0
  8. qubitclient/draw/plyplotter.py +21 -0
  9. qubitclient/draw/powershiftpltplotter.py +108 -0
  10. qubitclient/draw/powershiftplyplotter.py +194 -0
  11. qubitclient/draw/rabicospltplotter.py +74 -0
  12. qubitclient/draw/rabicosplyplotter.py +90 -0
  13. qubitclient/draw/rabipltplotter.py +66 -0
  14. qubitclient/draw/rabiplyplotter.py +86 -0
  15. qubitclient/draw/s21peakpltplotter.py +67 -0
  16. qubitclient/draw/s21peakplyplotter.py +124 -0
  17. qubitclient/draw/s21vfluxpltplotter.py +84 -0
  18. qubitclient/draw/s21vfluxplyplotter.py +163 -0
  19. qubitclient/draw/singleshotpltplotter.py +149 -0
  20. qubitclient/draw/singleshotplyplotter.py +324 -0
  21. qubitclient/draw/spectrum2dpltplotter.py +107 -0
  22. qubitclient/draw/spectrum2dplyplotter.py +244 -0
  23. qubitclient/draw/spectrum2dscopepltplotter.py +72 -0
  24. qubitclient/draw/spectrum2dscopeplyplotter.py +195 -0
  25. qubitclient/draw/spectrumpltplotter.py +106 -0
  26. qubitclient/draw/spectrumplyplotter.py +133 -0
  27. qubitclient/draw/t1fitpltplotter.py +76 -0
  28. qubitclient/draw/t1fitplyplotter.py +109 -0
  29. qubitclient/draw/t2fitpltplotter.py +70 -0
  30. qubitclient/draw/t2fitplyplotter.py +111 -0
  31. qubitclient/nnscope/nnscope.py +51 -0
  32. qubitclient/nnscope/nnscope_api/curve/__init__.py +0 -0
  33. qubitclient/nnscope/nnscope_api/curve/curve_type.py +15 -0
  34. qubitclient/nnscope/task.py +170 -0
  35. qubitclient/nnscope/utils/data_convert.py +114 -0
  36. qubitclient/nnscope/utils/data_parser.py +41 -0
  37. qubitclient/nnscope/utils/request_tool.py +41 -0
  38. qubitclient/nnscope/utils/result_parser.py +55 -0
  39. qubitclient/scope/scope.py +50 -0
  40. qubitclient/scope/scope_api/__init__.py +8 -0
  41. qubitclient/scope/scope_api/api/__init__.py +1 -0
  42. qubitclient/scope/scope_api/api/defined_tasks/__init__.py +1 -0
  43. qubitclient/scope/scope_api/api/defined_tasks/get_task_result_api_v1_tasks_demo_pk_get.py +155 -0
  44. qubitclient/scope/scope_api/api/defined_tasks/get_task_result_api_v1_tasks_scope_pk_get.py +155 -0
  45. qubitclient/scope/scope_api/api/defined_tasks/optpipulse_api_v1_tasks_scope_optpipulse_post.py +218 -0
  46. qubitclient/scope/scope_api/api/defined_tasks/powershift_api_v1_tasks_scope_powershift_post.py +218 -0
  47. qubitclient/scope/scope_api/api/defined_tasks/rabi_api_v1_tasks_scope_rabi_post.py +218 -0
  48. qubitclient/scope/scope_api/api/defined_tasks/rabicos_api_v1_tasks_scope_rabicospeak_post.py +218 -0
  49. qubitclient/scope/scope_api/api/defined_tasks/s21peak_api_v1_tasks_scope_s21peak_post.py +218 -0
  50. qubitclient/scope/scope_api/api/defined_tasks/s21vflux_api_v1_tasks_scope_s21vflux_post.py +218 -0
  51. qubitclient/scope/scope_api/api/defined_tasks/singleshot_api_v1_tasks_scope_singleshot_post.py +218 -0
  52. qubitclient/scope/scope_api/api/defined_tasks/spectrum2d_api_v1_tasks_scope_spectrum2d_post.py +218 -0
  53. qubitclient/scope/scope_api/api/defined_tasks/spectrum_api_v1_tasks_scope_spectrum_post.py +218 -0
  54. qubitclient/scope/scope_api/api/defined_tasks/t1fit_api_v1_tasks_scope_t1fit_post.py +218 -0
  55. qubitclient/scope/scope_api/api/defined_tasks/t1fit_api_v1_tasks_scope_t2fit_post.py +218 -0
  56. qubitclient/scope/scope_api/client.py +268 -0
  57. qubitclient/scope/scope_api/errors.py +16 -0
  58. qubitclient/scope/scope_api/models/__init__.py +31 -0
  59. qubitclient/scope/scope_api/models/body_optpipulse_api_v1_tasks_scope_optpipulse_post.py +83 -0
  60. qubitclient/scope/scope_api/models/body_powershift_api_v1_tasks_scope_powershift_post.py +83 -0
  61. qubitclient/scope/scope_api/models/body_rabi_api_v1_tasks_scope_rabi_post.py +83 -0
  62. qubitclient/scope/scope_api/models/body_rabicos_api_v1_tasks_scope_rabicospeak_post.py +83 -0
  63. qubitclient/scope/scope_api/models/body_s21_peak_api_v1_tasks_scope_s21_peak_post.py +83 -0
  64. qubitclient/scope/scope_api/models/body_s21_vflux_api_v1_tasks_scope_s21_vflux_post.py +83 -0
  65. qubitclient/scope/scope_api/models/body_singleshot_api_v1_tasks_scope_singleshot_post.py +83 -0
  66. qubitclient/scope/scope_api/models/body_spectrum_2d_api_v1_tasks_scope_spectrum_2d_post.py +83 -0
  67. qubitclient/scope/scope_api/models/body_spectrum_api_v1_tasks_scope_spectrum_post.py +83 -0
  68. qubitclient/scope/scope_api/models/body_t1_fit_api_v1_tasks_scope_t1_fit_post.py +83 -0
  69. qubitclient/scope/scope_api/models/body_t1_fit_api_v1_tasks_scope_t2_fit_post.py +83 -0
  70. qubitclient/scope/scope_api/models/http_validation_error.py +75 -0
  71. qubitclient/scope/scope_api/models/validation_error.py +88 -0
  72. qubitclient/scope/scope_api/types.py +54 -0
  73. qubitclient/scope/task.py +163 -0
  74. qubitclient/scope/utils/__init__.py +0 -0
  75. qubitclient/scope/utils/data_parser.py +20 -0
  76. qubitclient-0.1.4.dist-info/METADATA +173 -0
  77. qubitclient-0.1.4.dist-info/RECORD +81 -0
  78. qubitclient-0.1.4.dist-info/WHEEL +5 -0
  79. qubitclient-0.1.4.dist-info/licenses/LICENSE +674 -0
  80. qubitclient-0.1.4.dist-info/top_level.txt +1 -0
  81. qubitclient-0.1.4.dist-info/zip-safe +1 -0
@@ -0,0 +1,106 @@
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from .pltplotter import QuantumDataPltPlotter
4
+
5
+ class SpectrumDataPltPlotter(QuantumDataPltPlotter):
6
+
7
+ def __init__(self):
8
+ super().__init__("spectrum")
9
+
10
+ def plot_result_npy(self, **kwargs):
11
+ result = kwargs.get('result')
12
+ dict_param = kwargs.get('dict_param')
13
+
14
+ data = dict_param.item()
15
+ image = data["image"]
16
+ q_list = list(image.keys()) # 确保q_list是列表形式,便于索引
17
+ num_qubits = len(q_list)
18
+
19
+ # 数据提取
20
+ x_list = []
21
+ amp_list = []
22
+ q_name_list = []
23
+
24
+ for q_name in q_list:
25
+ image_q = image[q_name]
26
+ x = image_q[0] # 假设这里是x轴数据(如频率)
27
+ amp = image_q[1] # 假设这里是幅度数据
28
+
29
+ x_list.append(x)
30
+ amp_list.append(amp)
31
+ q_name_list.append(q_name)
32
+
33
+ # 结果数据
34
+ peaks_list = result['peaks_list']
35
+ confidences_list = result['confidences_list']
36
+
37
+ max_cols = 5
38
+ cols = min(num_qubits, max_cols) # 列数不超过max_cols
39
+ rows = (num_qubits + cols - 1) // cols # 计算需要的行数(向上取整)
40
+
41
+ fig_width = 6 * cols
42
+ fig_height = 4 * rows
43
+ fig, axes = plt.subplots(rows, cols, figsize=(fig_width, fig_height))
44
+
45
+ # 处理单元素或一维数组的axes,统一转为二维数组便于索引
46
+ if num_qubits == 1:
47
+ axes = np.array([[axes]])
48
+ elif rows == 1 or cols == 1:
49
+ axes = axes.reshape(rows, cols)
50
+
51
+ # 为每个 qubit 绘制子图
52
+ for idx, (x, amp, q_name) in enumerate(zip(x_list, amp_list, q_name_list)):
53
+ row = idx // cols # 计算当前子图所在行
54
+ col = idx % cols # 计算当前子图所在列
55
+ ax = axes[row, col]
56
+
57
+ # 绘制信号曲线
58
+ ax.plot(x, amp, label='Signal', color='blue')
59
+
60
+ # 获取当前 qubit 的峰值和置信度
61
+ peaks = peaks_list[idx] if idx < len(peaks_list) else []
62
+ confidences = confidences_list[idx] if idx < len(confidences_list) else None
63
+
64
+ # 绘制峰值
65
+ if peaks:
66
+ if confidences is None:
67
+ confidences = [None] * len(peaks)
68
+ elif len(confidences) != len(peaks):
69
+ raise ValueError(f"q_name {q_name} 的peaks和confidences长度不一致")
70
+
71
+ # 计算峰值对应的幅度(找到最接近的x值)
72
+ peak_amps = [amp[np.argmin(np.abs(x - p))] for p in peaks]
73
+ ax.scatter(peaks, peak_amps, color='red', s=50, zorder=3, label='Peak')
74
+
75
+ # 添加置信度标注
76
+ for peak, conf in zip(peaks, confidences):
77
+ amp_val = amp[np.argmin(np.abs(x - peak))]
78
+ if conf is not None:
79
+ ax.annotate(f'conf: {conf:.4f}',
80
+ xy=(peak, amp_val),
81
+ xytext=(5, 5),
82
+ textcoords='offset points',
83
+ fontsize=8,
84
+ bbox=dict(boxstyle="round,pad=0.3", fc="yellow", alpha=0.5))
85
+ else:
86
+ ax.annotate(f'{peak:.4f}',
87
+ xy=(peak, amp_val),
88
+ xytext=(5, 5),
89
+ textcoords='offset points')
90
+
91
+ # 设置子图标题和坐标轴标签
92
+ ax.set_title(f'Spectrum for {q_name}')
93
+ ax.set_xlabel('Frequency')
94
+ ax.set_ylabel('Amplitude')
95
+ ax.grid(True, linestyle='--', alpha=0.7)
96
+ ax.legend()
97
+
98
+ # 移除多余的子图(当 qubit 数量不足行列乘积时)
99
+ for idx in range(num_qubits, rows * cols):
100
+ row = idx // cols
101
+ col = idx % cols
102
+ fig.delaxes(axes[row, col])
103
+
104
+ # 调整子图间距
105
+ plt.tight_layout()
106
+ return fig
@@ -0,0 +1,133 @@
1
+ import numpy as np
2
+ import plotly.graph_objects as go
3
+ from plotly.subplots import make_subplots
4
+ from .plyplotter import QuantumDataPlyPlotter
5
+
6
+ class SpectrumDataPlyPlotter(QuantumDataPlyPlotter):
7
+
8
+ def __init__(self):
9
+ super().__init__("spectrum")
10
+
11
+ def plot_result_npy(self, **kwargs):
12
+ result = kwargs.get('result')
13
+ dict_param = kwargs.get('dict_param')
14
+
15
+ data = dict_param.item()
16
+ image = data["image"]
17
+ q_list = list(image.keys()) # 确保q_list是列表形式,便于索引
18
+ num_qubits = len(q_list)
19
+
20
+ # 数据提取
21
+ x_list = []
22
+ amp_list = []
23
+ q_name_list = []
24
+
25
+ for q_name in q_list:
26
+ image_q = image[q_name]
27
+ x = image_q[0] # 假设这里是x轴数据(如频率)
28
+ amp = image_q[1] # 假设这里是幅度数据
29
+
30
+ x_list.append(x)
31
+ amp_list.append(amp)
32
+ q_name_list.append(q_name)
33
+
34
+ # 结果数据
35
+ peaks_list = result['peaks_list']
36
+ confidences_list = result['confidences_list']
37
+
38
+ max_cols = 5
39
+ cols = min(num_qubits, max_cols) # 列数不超过max_cols
40
+ rows = (num_qubits + cols - 1) // cols # 计算需要的行数(向上取整)
41
+
42
+ # 创建子图
43
+ fig = make_subplots(
44
+ rows=rows,
45
+ cols=cols,
46
+ subplot_titles=[f'Spectrum for {q_name}' for q_name in q_name_list],
47
+ vertical_spacing=0.1,
48
+ horizontal_spacing=0.05
49
+ )
50
+
51
+ # 为每个 qubit 绘制子图
52
+ for idx, (x, amp, q_name) in enumerate(zip(x_list, amp_list, q_name_list)):
53
+ row = (idx // cols) + 1 # Plotly的行列索引从1开始
54
+ col = (idx % cols) + 1
55
+
56
+ # 绘制信号曲线
57
+ fig.add_trace(
58
+ go.Scatter(
59
+ x=x,
60
+ y=amp,
61
+ mode='lines',
62
+ name='Signal',
63
+ line=dict(color='blue'),
64
+ showlegend=(idx == 0) # 只在第一个子图显示图例
65
+ ),
66
+ row=row,
67
+ col=col
68
+ )
69
+
70
+ # 获取当前 qubit 的峰值和置信度
71
+ peaks = peaks_list[idx] if idx < len(peaks_list) else []
72
+ confidences = confidences_list[idx] if idx < len(confidences_list) else None
73
+
74
+ # 绘制峰值
75
+ if peaks:
76
+ if confidences is None:
77
+ confidences = [None] * len(peaks)
78
+ elif len(confidences) != len(peaks):
79
+ raise ValueError(f"q_name {q_name} 的peaks和confidences长度不一致")
80
+
81
+ # 计算峰值对应的幅度(找到最接近的x值)
82
+ peak_amps = [amp[np.argmin(np.abs(x - p))] for p in peaks]
83
+
84
+ # 添加峰值散点
85
+ fig.add_trace(
86
+ go.Scatter(
87
+ x=peaks,
88
+ y=peak_amps,
89
+ mode='markers',
90
+ name='Peak',
91
+ marker=dict(color='red', size=8),
92
+ showlegend=(idx == 0) # 只在第一个子图显示图例
93
+ ),
94
+ row=row,
95
+ col=col
96
+ )
97
+
98
+ # 添加置信度标注
99
+ for peak, conf, amp_val in zip(peaks, confidences, peak_amps):
100
+ annotation_text = f'conf: {conf:.4f}' if conf is not None else f'{peak:.4f}'
101
+ fig.add_annotation(
102
+ x=peak,
103
+ y=amp_val,
104
+ text=annotation_text,
105
+ xanchor='left',
106
+ yanchor='bottom',
107
+ showarrow=True,
108
+ arrowhead=1,
109
+ font=dict(size=8),
110
+ bgcolor='yellow',
111
+ opacity=0.5,
112
+ row=row,
113
+ col=col
114
+ )
115
+
116
+ # 设置坐标轴标签
117
+ fig.update_xaxes(title_text='Frequency', row=row, col=col)
118
+ fig.update_yaxes(title_text='Amplitude', row=row, col=col)
119
+
120
+ # 调整布局
121
+ fig.update_layout(
122
+ height=400 * rows, # 每个子图大致400高度
123
+ width=600 * cols, # 每个子图大致600宽度
124
+ legend=dict(
125
+ orientation="h",
126
+ yanchor="bottom",
127
+ y=1.02,
128
+ xanchor="right",
129
+ x=1
130
+ )
131
+ )
132
+
133
+ return fig
@@ -0,0 +1,76 @@
1
+ # src/draw/t1fitpltplotter.py
2
+ from .pltplotter import QuantumDataPltPlotter
3
+ import matplotlib.pyplot as plt
4
+ import numpy as np
5
+
6
+
7
+ class T1FitDataPltPlotter(QuantumDataPltPlotter):
8
+ def __init__(self):
9
+ super().__init__("t1fit")
10
+
11
+ def plot_result_npy(self, **kwargs):
12
+ result = kwargs.get('result')
13
+ dict_param = kwargs.get('dict_param') # 唯一原始数据参数
14
+
15
+ if not result or not dict_param:
16
+ fig, ax = plt.subplots()
17
+ ax.text(0.5, 0.5, "No data", ha='center', transform=ax.transAxes)
18
+ plt.close(fig)
19
+ return fig
20
+
21
+ data = dict_param.item() if isinstance(dict_param, np.ndarray) else dict_param
22
+ image_dict = data.get("image", {})
23
+ qubit_names = list(image_dict.keys())
24
+ if not qubit_names:
25
+ fig, ax = plt.subplots()
26
+ ax.text(0.5, 0.5, "No qubits", ha='center', transform=ax.transAxes)
27
+ plt.close(fig)
28
+ return fig
29
+
30
+ cols = min(3, len(qubit_names))
31
+ rows = (len(qubit_names) + cols - 1) // cols
32
+
33
+ fig = plt.figure(figsize=(5.8 * cols, 4.5 * rows))
34
+ fig.suptitle("T1-Fit", fontsize=14, y=0.96)
35
+
36
+ params_list = result.get("params_list", [])
37
+ r2_list = result.get("r2_list", [])
38
+ fit_data_list = result.get("fit_data_list", [])
39
+
40
+ for q_idx, q_name in enumerate(qubit_names):
41
+ ax = fig.add_subplot(rows, cols, q_idx + 1)
42
+ item = image_dict[q_name]
43
+ if not isinstance(item, (list, tuple)) or len(item) < 2:
44
+ continue
45
+
46
+ x_raw = np.asarray(item[0])
47
+ y_raw = np.asarray(item[1])
48
+
49
+ # 原始数据点
50
+ ax.plot(x_raw, y_raw, 'o', color='orange', markersize=4,
51
+ label='Data', alpha=0.7)
52
+
53
+ # 拟合曲线
54
+ if q_idx < len(fit_data_list):
55
+ fit_y = np.asarray(fit_data_list[q_idx])
56
+ ax.plot(x_raw, fit_y, '-', color='blue', linewidth=2,
57
+ label='Fit')
58
+
59
+ # 参数文字
60
+ if q_idx < len(params_list):
61
+ A, T1, B = params_list[q_idx]
62
+ r2 = r2_list[q_idx] if q_idx < len(r2_list) else 0.0
63
+ txt = f"A={A:.3f}\nT1={T1:.1f}µs\nB={B:.3f}\nR²={r2:.3f}"
64
+ ax.text(0.05, 0.95, txt, transform=ax.transAxes,
65
+ verticalalignment='top', fontsize=8,
66
+ bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
67
+
68
+ ax.set_title(q_name, fontsize=11, pad=10)
69
+ ax.set_xlabel("Time")
70
+ ax.set_ylabel("Amp")
71
+ ax.grid(True, linestyle='--', alpha=0.5)
72
+ ax.legend(fontsize=8, loc='upper right', framealpha=0.9)
73
+
74
+ plt.tight_layout(rect=[0, 0, 1, 0.94])
75
+ plt.close(fig)
76
+ return fig
@@ -0,0 +1,109 @@
1
+ # src/draw/t1fitplyplotter.py
2
+ from .plyplotter import QuantumDataPlyPlotter
3
+ import plotly.graph_objects as go
4
+ from plotly.subplots import make_subplots
5
+ import numpy as np
6
+
7
+
8
+ class T1FitDataPlyPlotter(QuantumDataPlyPlotter):
9
+ def __init__(self):
10
+ super().__init__("t1fit")
11
+
12
+ def plot_result_npy(self, **kwargs):
13
+ result = kwargs.get('result')
14
+ dict_param = kwargs.get('dict_param')
15
+
16
+ if not result or not dict_param:
17
+ fig = go.Figure()
18
+ fig.add_annotation(text="Missing data", xref="paper", yref="paper",
19
+ x=0.5, y=0.5, showarrow=False)
20
+ return fig
21
+
22
+ data = dict_param.item() if isinstance(dict_param, np.ndarray) else dict_param
23
+ image_dict = data.get("image", {})
24
+ if not image_dict:
25
+ fig = go.Figure()
26
+ fig.add_annotation(text="No image data", xref="paper", yref="paper",
27
+ x=0.5, y=0.5, showarrow=False)
28
+ return fig
29
+
30
+ qubit_names = list(image_dict.keys())
31
+ cols = min(3, len(qubit_names))
32
+ rows = (len(qubit_names) + cols - 1) // cols
33
+
34
+ fig = make_subplots(
35
+ rows=rows, cols=cols,
36
+ subplot_titles=qubit_names,
37
+ vertical_spacing=0.08,
38
+ horizontal_spacing=0.08,
39
+ )
40
+
41
+ params_list = result.get("params_list", [])
42
+ r2_list = result.get("r2_list", [])
43
+ fit_data_list = result.get("fit_data_list", [])
44
+
45
+ data_legend = False
46
+ fit_legend = False
47
+
48
+ for q_idx, q_name in enumerate(qubit_names):
49
+ row = q_idx // cols + 1
50
+ col = q_idx % cols + 1
51
+
52
+ item = image_dict[q_name]
53
+ if not isinstance(item, (list, tuple)) or len(item) < 2:
54
+ continue
55
+
56
+ x_raw = np.asarray(item[0])
57
+ y_raw = np.asarray(item[1])
58
+
59
+ # 原始数据点
60
+ fig.add_trace(
61
+ go.Scatter(x=x_raw, y=y_raw, mode='markers',
62
+ marker=dict(color='orange', size=6),
63
+ name='Data', legendgroup='data',
64
+ showlegend=not data_legend),
65
+ row=row, col=col
66
+ )
67
+ if not data_legend:
68
+ data_legend = True
69
+
70
+ # 拟合曲线
71
+ if q_idx < len(fit_data_list):
72
+ fit_y = np.asarray(fit_data_list[q_idx])
73
+ fig.add_trace(
74
+ go.Scatter(x=x_raw, y=fit_y, mode='lines',
75
+ line=dict(color='blue', width=2),
76
+ name='Fit', legendgroup='fit',
77
+ showlegend=not fit_legend),
78
+ row=row, col=col
79
+ )
80
+ if not fit_legend:
81
+ fit_legend = True
82
+
83
+ # 参数标注
84
+ if q_idx < len(params_list):
85
+ A, T1, B = params_list[q_idx]
86
+ r2 = r2_list[q_idx] if q_idx < len(r2_list) else 0.0
87
+ txt = f"A={A:.3f}<br>T1={T1:.1f}µs<br>B={B:.3f}<br>R²={r2:.3f}"
88
+ fig.add_annotation(
89
+ x=x_raw[0], y=max(y_raw) * 1.05,
90
+ text=txt, showarrow=False,
91
+ font=dict(size=9), align="left",
92
+ bgcolor="rgba(255,255,255,0.8)", bordercolor="gray",
93
+ row=row, col=col
94
+ )
95
+
96
+ if row == rows:
97
+ fig.update_xaxes(title_text="Time", row=row, col=col)
98
+ if col == 1:
99
+ fig.update_yaxes(title_text="Amp", row=row, col=col)
100
+
101
+ fig.update_layout(
102
+ height=420 * rows,
103
+ width=520 * cols,
104
+ title_text="T1-Fit",
105
+ title_x=0.5,
106
+ legend=dict(font=dict(size=10), bgcolor="rgba(255,255,255,0.8)"),
107
+ margin=dict(l=60, r=60, t=80, b=60)
108
+ )
109
+ return fig
@@ -0,0 +1,70 @@
1
+ # src/draw/t2fitpltplotter.py
2
+ from .pltplotter import QuantumDataPltPlotter
3
+ import matplotlib.pyplot as plt
4
+ import numpy as np
5
+
6
+
7
+ class T2FitDataPltPlotter(QuantumDataPltPlotter):
8
+ def __init__(self):
9
+ super().__init__("t2fit")
10
+
11
+ def plot_result_npy(self, **kwargs):
12
+ result = kwargs.get('result')
13
+ dict_param = kwargs.get('dict_param') # 统一使用 dict_param
14
+
15
+ if not result or not dict_param:
16
+ fig, ax = plt.subplots()
17
+ ax.text(0.5, 0.5, "No data", ha='center', transform=ax.transAxes)
18
+ return fig
19
+
20
+ data = dict_param.item() if isinstance(dict_param, np.ndarray) else dict_param
21
+ image_dict = data.get("image", {})
22
+ qubit_names = list(image_dict.keys())
23
+ n_qubits = len(qubit_names)
24
+ cols = min(3, n_qubits)
25
+ rows = (n_qubits + cols - 1) // cols
26
+
27
+ fig = plt.figure(figsize=(5.8 * cols, 4.8 * rows))
28
+ fig.suptitle("T2 Ramsey / Echo Fit", fontsize=14, y=0.96)
29
+
30
+ params_list = result.get("params_list", [])
31
+ r2_list = result.get("r2_list", [])
32
+ fit_data_list = result.get("fit_data_list", [])
33
+
34
+ for q_idx, q_name in enumerate(qubit_names):
35
+ ax = fig.add_subplot(rows, cols, q_idx + 1)
36
+ item = image_dict[q_name]
37
+ if not isinstance(item, (list, tuple)) or len(item) < 2:
38
+ continue
39
+
40
+ x_raw = np.asarray(item[0])
41
+ y_raw = np.asarray(item[1])
42
+
43
+ ax.plot(x_raw, y_raw, 'o', color='orange', markersize=5, label='Data', alpha=0.8)
44
+
45
+ if q_idx < len(fit_data_list):
46
+ y_fit = np.asarray(fit_data_list[q_idx])
47
+ if len(y_fit) != len(x_raw):
48
+ x_fit = np.linspace(x_raw.min(), x_raw.max(), len(y_fit))
49
+ else:
50
+ x_fit = x_raw
51
+ ax.plot(x_fit, y_fit, '-', color='blue', linewidth=2.2, label='Fit')
52
+
53
+ if q_idx < len(params_list):
54
+ A, B, T1, T2, w, phi = params_list[q_idx]
55
+ r2 = r2_list[q_idx] if q_idx < len(r2_list) else 0.0
56
+ text = (f"A={A:.3f}\nB={B:.3f}\nT1={T1:.1f}µs\n"
57
+ f"T2={T2:.1f}µs\nω={w/1e6:.2f}MHz\nφ={phi:.3f}\nR²={r2:.4f}")
58
+ ax.text(0.04, 0.96, text, transform=ax.transAxes,
59
+ verticalalignment='top', fontsize=8,
60
+ bbox=dict(boxstyle="round,pad=0.4", facecolor="white", alpha=0.9))
61
+
62
+ ax.set_title(q_name, fontsize=11, pad=10)
63
+ ax.set_xlabel("Time")
64
+ ax.set_ylabel("Amp")
65
+ ax.grid(True, linestyle='--', alpha=0.5)
66
+ ax.legend(fontsize=8, loc='upper right')
67
+
68
+ plt.tight_layout(rect=[0, 0, 1, 0.94])
69
+ plt.close(fig)
70
+ return fig
@@ -0,0 +1,111 @@
1
+ # src/draw/t2fitplyplotter.py
2
+ from .plyplotter import QuantumDataPlyPlotter
3
+ import plotly.graph_objects as go
4
+ from plotly.subplots import make_subplots
5
+ import numpy as np
6
+
7
+
8
+ class T2FitDataPlyPlotter(QuantumDataPlyPlotter):
9
+ def __init__(self):
10
+ super().__init__("t2fit")
11
+
12
+ def plot_result_npy(self, **kwargs):
13
+ result = kwargs.get('result')
14
+ dict_param = kwargs.get('dict_param') # 统一使用 dict_param
15
+
16
+ if not result or not dict_param:
17
+ fig = go.Figure()
18
+ fig.add_annotation(text="Missing data", xref="paper", yref="paper", x=0.5, y=0.5, showarrow=False)
19
+ return fig
20
+
21
+ data = dict_param.item() if isinstance(dict_param, np.ndarray) else dict_param
22
+ image_dict = data.get("image", {})
23
+ if not image_dict:
24
+ fig = go.Figure()
25
+ fig.add_annotation(text="No image data", xref="paper", yref="paper", x=0.5, y=0.5, showarrow=False)
26
+ return fig
27
+
28
+ qubit_names = list(image_dict.keys())
29
+ n_qubits = len(qubit_names)
30
+ cols = min(3, n_qubits)
31
+ rows = (n_qubits + cols - 1) // cols
32
+
33
+ fig = make_subplots(
34
+ rows=rows, cols=cols,
35
+ subplot_titles=[f"{q}" for q in qubit_names],
36
+ vertical_spacing=0.09,
37
+ horizontal_spacing=0.09,
38
+ )
39
+
40
+ params_list = result.get("params_list", [])
41
+ r2_list = result.get("r2_list", [])
42
+ fit_data_list = result.get("fit_data_list", [])
43
+
44
+ data_legend = False
45
+ fit_legend = False
46
+
47
+ for q_idx, q_name in enumerate(qubit_names):
48
+ row = q_idx // cols + 1
49
+ col = q_idx % cols + 1
50
+
51
+ item = image_dict[q_name]
52
+ if not isinstance(item, (list, tuple)) or len(item) < 2:
53
+ continue
54
+
55
+ x_raw = np.asarray(item[0])
56
+ y_raw = np.asarray(item[1])
57
+
58
+ fig.add_trace(go.Scatter(
59
+ x=x_raw, y=y_raw,
60
+ mode='markers',
61
+ marker=dict(color='orange', size=7),
62
+ name='Data', legendgroup='data',
63
+ showlegend=not data_legend
64
+ ), row=row, col=col)
65
+ if not data_legend:
66
+ data_legend = True
67
+
68
+ if q_idx < len(fit_data_list):
69
+ y_fit = np.asarray(fit_data_list[q_idx])
70
+ if len(y_fit) != len(x_raw):
71
+ x_fit = np.linspace(x_raw.min(), x_raw.max(), len(y_fit))
72
+ else:
73
+ x_fit = x_raw
74
+
75
+ fig.add_trace(go.Scatter(
76
+ x=x_fit, y=y_fit,
77
+ mode='lines',
78
+ line=dict(color='blue', width=2.5),
79
+ name='Fit', legendgroup='fit',
80
+ showlegend=not fit_legend
81
+ ), row=row, col=col)
82
+ if not fit_legend:
83
+ fit_legend = True
84
+
85
+ if q_idx < len(params_list):
86
+ A, B, T1, T2, w, phi = params_list[q_idx]
87
+ r2 = r2_list[q_idx] if q_idx < len(r2_list) else 0.0
88
+ txt = (f"A={A:.3f}<br>B={B:.3f}<br>T1={T1:.1f}µs<br>"
89
+ f"T2={T2:.1f}µs<br>ω={w/1e6:.2f}MHz<br>φ={phi:.3f}<br>R²={r2:.4f}")
90
+ fig.add_annotation(
91
+ x=x_raw[0], y=max(y_raw) * 1.08,
92
+ text=txt, showarrow=False,
93
+ font=dict(size=9), align="left",
94
+ bgcolor="rgba(255,255,255,0.8)", bordercolor="gray",
95
+ row=row, col=col
96
+ )
97
+
98
+ if row == rows:
99
+ fig.update_xaxes(title_text="Time", row=row, col=col)
100
+ if col == 1:
101
+ fig.update_yaxes(title_text="Amp", row=row, col=col)
102
+
103
+ fig.update_layout(
104
+ height=440 * rows,
105
+ width=540 * cols,
106
+ title_text="T2 Ramsey / Echo Fit",
107
+ title_x=0.5,
108
+ legend=dict(font=dict(size=10)),
109
+ margin=dict(l=60, r=60, t=90, b=60)
110
+ )
111
+ return fig
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (c) 2025 yaqiang.sun.
3
+ # This source code is licensed under the license found in the LICENSE file
4
+ # in the root directory of this source tree.
5
+ #########################################################################
6
+ # Author: yaqiangsun
7
+ # Created Time: 2025/10/20 18:13:37
8
+ ########################################################################
9
+
10
+
11
+ import os
12
+ # import cv2
13
+ import numpy as np
14
+ import sys
15
+ # 获取当前文件的绝对路径,向上两层就是项目根目录
16
+ project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
17
+ if project_root not in sys.path:
18
+ sys.path.insert(0, project_root)
19
+ #
20
+ # `scope_api_client`: this package is generated by `openapi-python-client`
21
+
22
+ from .task import run_task
23
+ import logging
24
+ import numpy as np
25
+
26
+
27
+
28
+ logging.basicConfig(level=logging.INFO)
29
+
30
+
31
+ class QubitNNScopeClient(object):
32
+ def __init__(self, url, api_key):
33
+ self.url = url
34
+ self.api_key = api_key
35
+
36
+ def request(self, file_list:list[str|dict[str,np.ndarray]|np.ndarray],task_type:str="s21peak",*args,**kwargs):
37
+ if len(file_list)>0:
38
+ response = run_task(file_list=file_list,url=self.url,api_key=self.api_key,task_type=task_type,*args,**kwargs)
39
+ else:
40
+ raise ValueError("file_list must not be empty")
41
+ return response
42
+ def get_result(self,response):
43
+ if response.status_code == 200:
44
+ logging.info("Result: %s", response.json())
45
+ result = response.json()
46
+ result = result["result"]
47
+ return result
48
+ else:
49
+ logging.error("Error: %s %s", response.status_code, response.text)
50
+ return []
51
+
File without changes
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (c) 2025 yaqiang.sun.
3
+ # This source code is licensed under the license found in the LICENSE file
4
+ # in the root directory of this source tree.
5
+ #########################################################################
6
+ # Author: yaqiangsun
7
+ # Created Time: 2025/06/06 16:52:53
8
+ ########################################################################
9
+
10
+
11
+ from enum import Enum
12
+
13
+ class CurveType(str, Enum):
14
+ COSINE = "cosin"
15
+ POLY = "poly"