xlin 0.1.34__tar.gz → 0.1.36__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xlin
3
- Version: 0.1.34
3
+ Version: 0.1.36
4
4
  Summary: toolbox for LinXueyuan
5
5
  License: MIT
6
6
  Author: LinXueyuanStdio
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "xlin"
3
- version = "0.1.34"
3
+ version = "0.1.36"
4
4
  description = "toolbox for LinXueyuan"
5
5
  authors = ["LinXueyuanStdio <23211526+LinXueyuanStdio@users.noreply.github.com>"]
6
6
  license = "MIT"
@@ -1,3 +1,4 @@
1
+ import sys
1
2
  from typing import List, Optional
2
3
  from collections import defaultdict
3
4
 
@@ -108,12 +109,119 @@ Kurtosis: {float((data - mean).mean()**4 / std**4):.4f}\
108
109
 
109
110
  # 显示图形
110
111
  plt.tight_layout()
111
- plt.show()
112
112
  if fig_save_path is not None:
113
113
  plt.savefig(fig_save_path, dpi=300)
114
+ plt.show()
114
115
 
116
+ def draw_radar(categories: list[str],
117
+ data: dict[str, list[float]],
118
+ ranges=(0, 5),
119
+ title: str = "Radar Chart",
120
+ size: tuple[float, float] = (6, 6),
121
+ colors: list[str] = None,
122
+ annotation_offset: float = 0.03,
123
+ annotation_kwargs: dict = None,
124
+ chinese_font: bool = False,
125
+ font_name: str = 'Heiti TC',
126
+ font_path: str = None,
127
+ fig_save_path: str = None):
128
+ import numpy as np
129
+ import matplotlib.pyplot as plt
130
+ from matplotlib.font_manager import FontProperties
131
+ """
132
+ Draw a radar chart with optional Chinese font support and configurable annotations.
133
+
134
+ Parameters:
135
+ - categories: list of dimension names.
136
+ - data: dict mapping series name -> list of values (same length as categories).
137
+ - ranges: tuple (min, max) for radial axis.
138
+ - title: chart title.
139
+ - size: figure size tuple.
140
+ - colors: list of color hex strings.
141
+ - annotation_offset: fraction of (max-min) to offset text.
142
+ - annotation_kwargs: additional kwargs for plt.text (font size, bbox, etc).
143
+ - chinese_font: whether to enable Chinese font support.
144
+ - font_name: name of a system font to use (overrides defaults).
145
+ - font_path: path to a .ttf font file (used if provided).
146
+ - fig_save_path: if set, saves figure to this path (PNG at 300dpi).
147
+ """
148
+ # Validate data
149
+ N = len(categories)
150
+ for label, values in data.items():
151
+ if len(values) != N:
152
+ raise ValueError(f"Values for '{label}' must have length {N}")
153
+
154
+ # Font configuration
155
+ if font_path:
156
+ prop = FontProperties(fname=font_path)
157
+ plt.rcParams['font.family'] = prop.get_name()
158
+ elif font_name:
159
+ plt.rcParams['font.family'] = font_name
160
+ elif chinese_font:
161
+ if sys.platform == "darwin":
162
+ plt.rcParams['font.family'] = ['Heiti TC', 'Arial Unicode MS']
163
+ elif sys.platform.startswith("win"):
164
+ plt.rcParams['font.family'] = ['SimHei', 'Microsoft YaHei']
165
+ else:
166
+ # Fallback to Arial Unicode
167
+ plt.rcParams['font.family'] = ['Arial Unicode MS']
168
+ else:
169
+ plt.rcParams['font.family'] = ['Arial']
170
+
171
+ plt.rcParams['axes.unicode_minus'] = False
172
+
173
+ # Prepare angles
174
+ angles = np.linspace(0, 2 * np.pi, N, endpoint=False).tolist()
175
+ angles += angles[:1]
176
+
177
+ # Colors
178
+ default_colors = ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f"]
179
+ colors = colors or default_colors
180
+
181
+ max_value = max(max(values) for values in data.values())
182
+ min_value = min(min(values) for values in data.values())
183
+ if ranges[0] > min_value or ranges[1] < max_value:
184
+ ranges = (min_value, max_value + 1)
185
+
186
+ # Create plot
187
+ fig, ax = plt.subplots(figsize=size, subplot_kw=dict(polar=True))
188
+ ax.set_theta_offset(np.pi / 2)
189
+ ax.set_theta_direction(-1)
190
+ ax.set_xticks(angles[:-1])
191
+ ax.set_xticklabels(categories, fontsize=12)
192
+ ax.set_ylim(ranges)
193
+ ax.set_rlabel_position(180 / N)
194
+ ax.grid(color='gray', linestyle='--', linewidth=0.5)
195
+
196
+ # Plot each series
197
+ for idx, (label, values) in enumerate(data.items()):
198
+ vals = values + values[:1]
199
+ color = colors[idx % len(colors)]
200
+ ax.plot(angles, vals, color=color, linewidth=2, label=label)
201
+ ax.fill(angles, vals, color=color, alpha=0.25)
202
+
203
+ # Annotate points
204
+ for angle, val in zip(angles, vals):
205
+ offset = (ranges[1] - ranges[0]) * annotation_offset
206
+ ha = 'left' if np.cos(angle) >= 0 else 'right'
207
+ va = 'bottom' if np.sin(angle) >= 0 else 'top'
208
+ txt_kwargs = dict(fontsize=10, ha=ha, va=va, bbox=dict(boxstyle="round,pad=0.3", edgecolor=color, facecolor='white', alpha=0.8))
209
+ if annotation_kwargs:
210
+ txt_kwargs.update(annotation_kwargs)
211
+ ax.text(angle, val + offset, f"{val}", **txt_kwargs)
212
+
213
+ ax.set_title(title, va='bottom', fontsize=16)
214
+ ax.legend(loc='upper right', bbox_to_anchor=(1.15, 1.05))
215
+ plt.tight_layout()
115
216
 
116
- def draw_preds_labels(preds: list[str], labels: list[str], title="Pred and Label Class Distribution", fig_save_path: Optional[str]=None):
217
+ if fig_save_path:
218
+ plt.savefig(fig_save_path, dpi=300, bbox_inches='tight')
219
+ plt.show()
220
+
221
+
222
+ def draw_preds_labels(preds: list[str], labels: list[str],
223
+ title="Pred and Label Class Distribution",
224
+ fig_save_path: Optional[str]=None):
117
225
  from collections import Counter
118
226
  import matplotlib.pyplot as plt
119
227
 
@@ -159,9 +267,9 @@ def draw_preds_labels(preds: list[str], labels: list[str], title="Pred and Label
159
267
  plt.suptitle(title)
160
268
 
161
269
  plt.tight_layout()
162
- plt.show()
163
270
  if fig_save_path is not None:
164
271
  plt.savefig(fig_save_path, dpi=300)
272
+ plt.show()
165
273
 
166
274
 
167
275
  def generate_classification_report(predictions: List[str], labels: List[str]) -> dict:
@@ -328,4 +436,17 @@ if __name__ == "__main__":
328
436
  preds = ["cat", "dog", "cat", "dog", "extra1", "extra2"]
329
437
  truth = ["cat", "cat", "dog", "dog", "dog", "dog"]
330
438
 
331
- print_classification_report(preds, truth)
439
+ print_classification_report(preds, truth)
440
+ draw_preds_labels(preds, truth, title="Pred and Label Class Distribution", fig_save_path="assets/pred_label_distribution.png")
441
+
442
+ import random
443
+
444
+ lengths = [random.randint(0, 100) for _ in range(100)]
445
+ draw_histogram(lengths, bins=50, title="Length Distribution", fig_save_path="assets/length_distribution.png")
446
+
447
+ categories = ['速度', '可靠性', '舒适度', '安全性', '效率', '风格', '性价比']
448
+ data = {
449
+ '产品 A': [4, 3, 2, 5, 4, 3, -1],
450
+ '产品 B': [3, 4, 5, 3, 3, 4, 8]
451
+ }
452
+ draw_radar(categories, data, title="产品对比雷达图", chinese_font=True, fig_save_path="assets/radar_chart.png")
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