rsplotlib 0.2.6__tar.gz → 0.2.8__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.
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/.gitignore +2 -1
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/Cargo.lock +5 -3
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/Cargo.toml +5 -1
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/PKG-INFO +1 -1
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/pyproject.toml +1 -1
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/__init__.py +1 -1
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/pyplot.py +166 -44
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/core/elements.rs +10 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axes.rs +389 -53
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axes_bounds.rs +54 -25
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axes_render_elements.rs +532 -82
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axis.rs +76 -6
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/figure.rs +50 -30
- rsplotlib-0.2.8/src/fonts/DejaVuSans.ttf +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/lib.rs +112 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/utils/font_stack.rs +51 -5
- rsplotlib-0.2.8/src/utils/glyph_cache.rs +229 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/utils/mod.rs +2 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/utils/pyfuncs.rs +45 -3
- rsplotlib-0.2.8/src/utils/rgb_backend.rs +232 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/.github/workflows/ci.yml +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/.github/workflows/release.yml +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/.github/workflows/rust.yml +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/LICENSE +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/README.md +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/README_zh.md +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/build_wheel.sh +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/ci/smoke_test.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/_font_resolver.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/colors.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/core/__init__.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/core/api.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/dates.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/figure/__init__.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/figure/_defaults.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/gridspec.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/layout/__init__.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/layout/gridspec.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/pylab.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/ticker.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/ticks/__init__.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/ticks/ticker.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/utils/__init__.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/utils/_font_resolver.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/utils/_rcparams.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/python/rsplotlib/utils/style.py +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/rust-toolchain.toml +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/core/colormap.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/core/colors.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/core/marker.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/core/mod.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axes_colorbar.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axes_grid.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axes_legend.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axes_mesh.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axes_secondary.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/axes_title.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/figure/mod.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/layout/gridspec.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/layout/mod.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/ticks/mod.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/ticks/ticker.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/utils/font_resolver.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/utils/mathtext.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/src/utils/style.rs +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/tutorial.css +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/tutorial.html +0 -0
- {rsplotlib-0.2.6 → rsplotlib-0.2.8}/tutorial.js +0 -0
|
@@ -50,9 +50,9 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
|
|
50
50
|
|
|
51
51
|
[[package]]
|
|
52
52
|
name = "bytemuck"
|
|
53
|
-
version = "1.25.
|
|
53
|
+
version = "1.25.1"
|
|
54
54
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
55
|
-
checksum = "
|
|
55
|
+
checksum = "d6aedf8ae72766347502cf3cb4f41cf5e9cc37d28bee90f1fdaaae15f9cf9424"
|
|
56
56
|
|
|
57
57
|
[[package]]
|
|
58
58
|
name = "byteorder"
|
|
@@ -417,12 +417,14 @@ dependencies = [
|
|
|
417
417
|
|
|
418
418
|
[[package]]
|
|
419
419
|
name = "rsplotlib"
|
|
420
|
-
version = "0.2.
|
|
420
|
+
version = "0.2.8"
|
|
421
421
|
dependencies = [
|
|
422
|
+
"ab_glyph",
|
|
422
423
|
"jpeg-decoder",
|
|
423
424
|
"jpeg-encoder",
|
|
424
425
|
"owned_ttf_parser",
|
|
425
426
|
"plotters",
|
|
427
|
+
"plotters-backend",
|
|
426
428
|
"png 0.18.1",
|
|
427
429
|
"pyo3",
|
|
428
430
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rsplotlib"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.8"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
|
|
@@ -15,6 +15,10 @@ png = "0.18.1"
|
|
|
15
15
|
owned_ttf_parser = "0.25.1"
|
|
16
16
|
jpeg-encoder = "0.7.0"
|
|
17
17
|
jpeg-decoder = "0.3.2"
|
|
18
|
+
# 与 plotters 0.3.7 相同版本的 ab_glyph / plotters-backend(均已在 Cargo.lock 锁定,
|
|
19
|
+
# 不引入新下载):glyph 缓存需直接引用 ab_glyph 光栅化器与后端 trait 类型。
|
|
20
|
+
ab_glyph = "0.2.32"
|
|
21
|
+
plotters-backend = "0.3.7"
|
|
18
22
|
|
|
19
23
|
[profile.release]
|
|
20
24
|
lto = "fat"
|
|
@@ -49,20 +49,44 @@ def _to_list_recursive(obj):
|
|
|
49
49
|
return obj
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
def _buffer_kind(obj):
|
|
53
|
+
"""返回 obj 的 dtype kind 字符(numpy 约定 'f'/'i'/'u'/'b'/'M'/'S'/'U'/'c'…),
|
|
54
|
+
无法判定时返回 None。
|
|
55
|
+
|
|
56
|
+
优先读廉价的 obj.dtype.kind:rsnumpy 的 __array_interface__ 属性每次访问都会即时把
|
|
57
|
+
整个缓冲区序列化成 bytes(百万点约 2.6ms/次,随后被丢弃),而 dtype 访问是 O(1)。
|
|
58
|
+
仅当对象没有 dtype(如 Python list、标量、或 numpy 之外仅实现数组接口的第三方缓冲)
|
|
59
|
+
时,才回退读取 __array_interface__ 的 typestr。真实 numpy 的 __array_interface__ 为
|
|
60
|
+
指针形式、开销极小,不受此影响。
|
|
61
|
+
"""
|
|
62
|
+
dt = None
|
|
63
|
+
try:
|
|
64
|
+
dt = getattr(obj, 'dtype', None)
|
|
65
|
+
except Exception:
|
|
66
|
+
# rsnumpy 对 datetime64[h]/timedelta64 等 dtype 的 .dtype 属性会抛 TypeError
|
|
67
|
+
# (非 AttributeError,getattr 默认值挡不住)。此处按"无法判定"处理,落到
|
|
68
|
+
# __array_interface__ 回退——这些非数值 dtype 本就应返回非 fiub kind。
|
|
69
|
+
dt = None
|
|
70
|
+
if dt is not None:
|
|
71
|
+
kind = getattr(dt, 'kind', None)
|
|
72
|
+
if isinstance(kind, str) and len(kind) == 1:
|
|
73
|
+
return kind
|
|
74
|
+
ai = getattr(obj, '__array_interface__', None)
|
|
75
|
+
if isinstance(ai, dict):
|
|
76
|
+
typestr = ai.get('typestr', '')
|
|
77
|
+
return typestr[1:2] if len(typestr) >= 2 else None
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
52
81
|
def _is_numeric_buffer(obj):
|
|
53
|
-
"""obj
|
|
82
|
+
"""obj 是否为纯数值缓冲数组(float/int/uint/bool)。
|
|
54
83
|
|
|
55
84
|
这类数组可零拷贝下沉给 Rust,且不可能是字符串类别或日期,故可跳过 .tolist()
|
|
56
|
-
全量物化(plot/scatter 热路径最大收益)。
|
|
57
|
-
|
|
58
|
-
|
|
85
|
+
全量物化(plot/scatter 热路径最大收益)。dtype kind 为 datetime64('M')、字符串
|
|
86
|
+
('U'/'S')、复数('c')、timedelta('m')、object('O') 均需 Python 侧特殊处理,返回
|
|
87
|
+
False 交回原有 .tolist() 路径。
|
|
59
88
|
"""
|
|
60
|
-
|
|
61
|
-
if not isinstance(ai, dict):
|
|
62
|
-
return False
|
|
63
|
-
typestr = ai.get('typestr', '')
|
|
64
|
-
kind = typestr[1:2] if len(typestr) >= 2 else ''
|
|
65
|
-
return kind in ('f', 'i', 'u', 'b')
|
|
89
|
+
return _buffer_kind(obj) in ('f', 'i', 'u', 'b')
|
|
66
90
|
|
|
67
91
|
|
|
68
92
|
def _numeric_buffer_1d_len(obj):
|
|
@@ -71,14 +95,13 @@ def _numeric_buffer_1d_len(obj):
|
|
|
71
95
|
用于 scatter 数值 c 的快路径:一维数值缓冲不可能是颜色字符串或 RGB(A) 行数组,
|
|
72
96
|
可零拷贝直传 Rust 经 colormap 上色,跳过 .tolist() / 逐元素类别检查 / [float(v)] 物化。
|
|
73
97
|
"""
|
|
74
|
-
|
|
75
|
-
if not isinstance(ai, dict):
|
|
76
|
-
return None
|
|
77
|
-
typestr = ai.get('typestr', '')
|
|
78
|
-
kind = typestr[1:2] if len(typestr) >= 2 else ''
|
|
79
|
-
if kind not in ('f', 'i', 'u', 'b'):
|
|
98
|
+
if _buffer_kind(obj) not in ('f', 'i', 'u', 'b'):
|
|
80
99
|
return None
|
|
81
|
-
shape =
|
|
100
|
+
shape = getattr(obj, 'shape', None)
|
|
101
|
+
if shape is None:
|
|
102
|
+
ai = getattr(obj, '__array_interface__', None)
|
|
103
|
+
if isinstance(ai, dict):
|
|
104
|
+
shape = ai.get('shape')
|
|
82
105
|
if not (isinstance(shape, tuple) and len(shape) == 1):
|
|
83
106
|
return None
|
|
84
107
|
return shape[0]
|
|
@@ -421,6 +444,7 @@ def _map_aliases(kwargs):
|
|
|
421
444
|
kwargs.pop(alias)
|
|
422
445
|
# 规范化 linestyle 词形 ('solid'/'dotted'/'dashed'/'dashdot') 与空值到简写,
|
|
423
446
|
# 与 matplotlib 一致:既可写 linestyle='dotted' 也可写 linestyle=':'。
|
|
447
|
+
# 元组形式 (offset, onoffseq)(参数化 dash 图案)编码为 "dashes=..." 串下沉到 Rust。
|
|
424
448
|
ls = kwargs.get('linestyle')
|
|
425
449
|
if isinstance(ls, str):
|
|
426
450
|
key = ls.strip().lower()
|
|
@@ -429,6 +453,35 @@ def _map_aliases(kwargs):
|
|
|
429
453
|
elif key in _LINESTYLE_ALIASES:
|
|
430
454
|
kwargs['linestyle'] = _LINESTYLE_ALIASES[key]
|
|
431
455
|
# 已是简写 ('-' / '--' / ':' / '-.') 时保持不变
|
|
456
|
+
elif isinstance(ls, (tuple, list)):
|
|
457
|
+
enc = _encode_dash_linestyle(ls)
|
|
458
|
+
if enc is not None:
|
|
459
|
+
kwargs['linestyle'] = enc
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
def _encode_dash_linestyle(ls):
|
|
463
|
+
"""matplotlib 元组 linestyle ``(offset, onoffseq)`` -> ``"dashes=<offset>;<v0>,<v1>,..."`` 编码串。
|
|
464
|
+
|
|
465
|
+
- 空 / None 的 onoffseq 视为实线 ('-')。
|
|
466
|
+
- 结构非法时返回 None(交由下游忽略, 保持原值)。
|
|
467
|
+
"""
|
|
468
|
+
if len(ls) != 2:
|
|
469
|
+
return None
|
|
470
|
+
offset, seq = ls
|
|
471
|
+
if seq is None:
|
|
472
|
+
return '-'
|
|
473
|
+
try:
|
|
474
|
+
seq = list(seq)
|
|
475
|
+
except TypeError:
|
|
476
|
+
return None
|
|
477
|
+
if len(seq) == 0:
|
|
478
|
+
return '-'
|
|
479
|
+
if offset is None:
|
|
480
|
+
offset = 0
|
|
481
|
+
try:
|
|
482
|
+
return "dashes=%g;%s" % (float(offset), ",".join("%g" % float(v) for v in seq))
|
|
483
|
+
except (TypeError, ValueError):
|
|
484
|
+
return None
|
|
432
485
|
|
|
433
486
|
|
|
434
487
|
# linestyle 词形 -> 简写。空串 / 'None' 在 _map_aliases 中单独处理为 ' '(不画线)。
|
|
@@ -942,6 +995,28 @@ def _parse_fmt(fmt):
|
|
|
942
995
|
return result
|
|
943
996
|
|
|
944
997
|
|
|
998
|
+
def _implicit_x(y):
|
|
999
|
+
"""plot(y) 的隐式横坐标 = [0, 1, ..., len(y)-1]。
|
|
1000
|
+
|
|
1001
|
+
优先用 rsnumpy.arange(n, dtype=float) 生成 float64 数组:可经 PEP 3118 缓冲协议
|
|
1002
|
+
零拷贝下沉 Rust,并让 _categorical/_maybe_dates_to_num/_to_seq 走数值缓冲快路径,
|
|
1003
|
+
跳过对 list(range(n)) 的逐元素扫描与百万级 Python int 提取(大数据热路径)。
|
|
1004
|
+
值 0.0..n-1 与 range 完全一致(n ≤ 2^53 精确),渲染输出逐字节不变。
|
|
1005
|
+
|
|
1006
|
+
rsnumpy 不可用(ImportError)或 arange 异常时回退到 list(range(n));y 无 len 时
|
|
1007
|
+
沿用原逻辑(可迭代取 list(y),否则空)。
|
|
1008
|
+
"""
|
|
1009
|
+
try:
|
|
1010
|
+
n = len(y)
|
|
1011
|
+
except Exception:
|
|
1012
|
+
return list(y) if hasattr(y, '__iter__') else []
|
|
1013
|
+
try:
|
|
1014
|
+
import rsnumpy as _rsnp
|
|
1015
|
+
return _rsnp.arange(n, dtype=float)
|
|
1016
|
+
except Exception:
|
|
1017
|
+
return list(range(n))
|
|
1018
|
+
|
|
1019
|
+
|
|
945
1020
|
def _parse_plot_args(args, kwargs):
|
|
946
1021
|
"""解析 plot() 的位置参数为 [(x, y, fmt_or_none), ...] 对列表 + kwargs
|
|
947
1022
|
|
|
@@ -965,10 +1040,7 @@ def _parse_plot_args(args, kwargs):
|
|
|
965
1040
|
|
|
966
1041
|
if len(group) == 1:
|
|
967
1042
|
y = group[0]
|
|
968
|
-
|
|
969
|
-
x = list(range(len(y)))
|
|
970
|
-
except Exception:
|
|
971
|
-
x = list(y) if hasattr(y, '__iter__') else []
|
|
1043
|
+
x = _implicit_x(y)
|
|
972
1044
|
pairs.append((x, y, fmt))
|
|
973
1045
|
else:
|
|
974
1046
|
pairs.append((group[0], group[1], fmt))
|
|
@@ -1193,21 +1265,29 @@ def hist(x, bins=None, range=None, density=False, weights=None,
|
|
|
1193
1265
|
if bins is None:
|
|
1194
1266
|
bins = 10
|
|
1195
1267
|
|
|
1196
|
-
#
|
|
1197
|
-
|
|
1198
|
-
if x
|
|
1199
|
-
x_list =
|
|
1268
|
+
# 数据规整为“组的列表”。一维纯数值缓冲直接下沉给 Rust 零拷贝读取,避免
|
|
1269
|
+
# _to_list_recursive + [list(x)] 把百万级数据点物化成 Python 对象(hist 大数据热路径)。
|
|
1270
|
+
if _numeric_buffer_1d_len(x) is not None:
|
|
1271
|
+
x_list = x
|
|
1272
|
+
n_datasets = 1
|
|
1200
1273
|
else:
|
|
1201
|
-
|
|
1202
|
-
|
|
1274
|
+
x = _to_list_recursive(x)
|
|
1275
|
+
if x and isinstance(x[0], (list, tuple)):
|
|
1276
|
+
x_list = [list(v) for v in x]
|
|
1277
|
+
else:
|
|
1278
|
+
x_list = [list(x)]
|
|
1279
|
+
n_datasets = len(x_list)
|
|
1203
1280
|
|
|
1204
|
-
# weights 规整为与 x
|
|
1281
|
+
# weights 规整为与 x 平行的结构(一维数值缓冲同样直传,Rust 侧零拷贝读取)
|
|
1205
1282
|
if weights is not None:
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
weights_arg = [list(v) for v in w]
|
|
1283
|
+
if _numeric_buffer_1d_len(weights) is not None:
|
|
1284
|
+
weights_arg = weights
|
|
1209
1285
|
else:
|
|
1210
|
-
|
|
1286
|
+
w = _to_list_recursive(weights)
|
|
1287
|
+
if w and isinstance(w[0], (list, tuple)):
|
|
1288
|
+
weights_arg = [list(v) for v in w]
|
|
1289
|
+
else:
|
|
1290
|
+
weights_arg = [list(w)]
|
|
1211
1291
|
else:
|
|
1212
1292
|
weights_arg = None
|
|
1213
1293
|
|
|
@@ -1293,7 +1373,11 @@ def boxplot(x, labels=None, vert=True, **kwargs):
|
|
|
1293
1373
|
labels: 每个箱的标签列表
|
|
1294
1374
|
vert: 是否垂直绘制 (默认 True)
|
|
1295
1375
|
"""
|
|
1296
|
-
|
|
1376
|
+
# 纯数值缓冲数组直接下沉给 Rust 零拷贝读取(py_to_vec_vec_f64:一维→单箱,
|
|
1377
|
+
# 二维→按行拆多箱,与旧 _to_list_recursive 语义一致),避免物化百万级数据点。
|
|
1378
|
+
# Python list(含 list of arrays)、含字符串等非缓冲对象保持原路径。
|
|
1379
|
+
if not _is_numeric_buffer(x):
|
|
1380
|
+
x = _to_list_recursive(x)
|
|
1297
1381
|
return _route_to_ax('boxplot', _rsplotlib.boxplot, x, labels, vert)
|
|
1298
1382
|
|
|
1299
1383
|
|
|
@@ -1385,10 +1469,10 @@ def stackplot(x, *args, labels=None, colors=None, alpha=1.0, **kwargs):
|
|
|
1385
1469
|
colors: 每个数据集的颜色列表
|
|
1386
1470
|
alpha: 透明度 (默认 1.0)
|
|
1387
1471
|
"""
|
|
1388
|
-
x =
|
|
1389
|
-
y_data = [
|
|
1472
|
+
x = _to_seq(x)
|
|
1473
|
+
y_data = [_to_seq(a) for a in args if a is not None]
|
|
1390
1474
|
if not y_data and 'y' in kwargs:
|
|
1391
|
-
y_data = [
|
|
1475
|
+
y_data = [_to_seq(kwargs['y'])]
|
|
1392
1476
|
return _route_to_ax('stackplot', _rsplotlib.stackplot, x, *y_data,
|
|
1393
1477
|
labels=labels, colors=colors, alpha=alpha)
|
|
1394
1478
|
|
|
@@ -1632,15 +1716,15 @@ def annotate(text, xy, xytext=None, fontsize=None, color='black', arrowprops=Non
|
|
|
1632
1716
|
xytext 绘制箭头指向 xy。支持简单箭头 (width/headwidth/headlength/
|
|
1633
1717
|
shrink) 与花式箭头 (arrowstyle/connectionstyle/mutation_scale/
|
|
1634
1718
|
shrinkA/shrinkB 等)。
|
|
1635
|
-
**kwargs: 其他关键字参数 (如 xycoords/textcoords
|
|
1719
|
+
**kwargs: 其他关键字参数 (如 xycoords/textcoords/ha/family),转发给 Axes.annotate
|
|
1636
1720
|
"""
|
|
1637
1721
|
text = _render_mathtext(text)
|
|
1638
1722
|
ax = _get_axes()
|
|
1639
1723
|
if ax is not None and hasattr(ax, 'annotate'):
|
|
1640
|
-
ax.annotate(text, xy, xytext, fontsize, color, arrowprops)
|
|
1724
|
+
ax.annotate(text, xy, xytext, fontsize, color, arrowprops, **kwargs)
|
|
1641
1725
|
return _get_figure()
|
|
1642
1726
|
fig, ax = _rsplotlib.subplots()
|
|
1643
|
-
ax.annotate(text, xy, xytext, fontsize, color, arrowprops)
|
|
1727
|
+
ax.annotate(text, xy, xytext, fontsize, color, arrowprops, **kwargs)
|
|
1644
1728
|
return fig, ax
|
|
1645
1729
|
|
|
1646
1730
|
|
|
@@ -1989,12 +2073,23 @@ def subplots(nrows=1, ncols=1, figsize=None, dpi=None, squeeze=True, **kwargs):
|
|
|
1989
2073
|
- 1xN 或 Nx1: (Figure, 一维 ndarray[Axes])
|
|
1990
2074
|
- MxN: (Figure, 二维 ndarray[Axes]), 支持 axs[i, j] 索引
|
|
1991
2075
|
"""
|
|
1992
|
-
|
|
2076
|
+
# width_ratios/height_ratios 可作为 subplots 的直接关键字,或经 gridspec_kw 传入
|
|
2077
|
+
# (与 matplotlib 一致,直接关键字优先)。传给 Rust 侧 subplots 以按比例分配行/列尺寸。
|
|
2078
|
+
gridspec_kw = kwargs.get('gridspec_kw') or {}
|
|
2079
|
+
width_ratios = kwargs.get('width_ratios')
|
|
2080
|
+
if width_ratios is None:
|
|
2081
|
+
width_ratios = gridspec_kw.get('width_ratios')
|
|
2082
|
+
height_ratios = kwargs.get('height_ratios')
|
|
2083
|
+
if height_ratios is None:
|
|
2084
|
+
height_ratios = gridspec_kw.get('height_ratios')
|
|
2085
|
+
width_ratios = _to_list(width_ratios) if width_ratios is not None else None
|
|
2086
|
+
height_ratios = _to_list(height_ratios) if height_ratios is not None else None
|
|
2087
|
+
|
|
2088
|
+
result = _rsplotlib.subplots(nrows, ncols, figsize, dpi, width_ratios, height_ratios)
|
|
1993
2089
|
fig = result[0]
|
|
1994
2090
|
|
|
1995
2091
|
# gridspec_kw={'wspace':.., 'hspace':..} 与 matplotlib 一致地控制子图间距,
|
|
1996
2092
|
# 复用 subplots_adjust 的存储路径(在渲染阶段覆盖默认/启发式间距)。
|
|
1997
|
-
gridspec_kw = kwargs.get('gridspec_kw')
|
|
1998
2093
|
if gridspec_kw:
|
|
1999
2094
|
ws = gridspec_kw.get('wspace')
|
|
2000
2095
|
hs = gridspec_kw.get('hspace')
|
|
@@ -2924,6 +3019,20 @@ def _patch_axes():
|
|
|
2924
3019
|
_rs.Axes.set_xticks = _set_xticks
|
|
2925
3020
|
_rs.Axes.set_yticks = _set_yticks
|
|
2926
3021
|
|
|
3022
|
+
# set_xticklabels / set_yticklabels: 归一为字符串 list,吸收 rotation/ha/fontsize 等
|
|
3023
|
+
# 未支持的样式 kwargs。须在 set_xticks/set_yticks 固定刻度位置后调用(matplotlib 语义)。
|
|
3024
|
+
_orig_set_xticklabels = _rs.Axes.set_xticklabels
|
|
3025
|
+
_orig_set_yticklabels = _rs.Axes.set_yticklabels
|
|
3026
|
+
|
|
3027
|
+
def _set_xticklabels(self, labels, **kwargs):
|
|
3028
|
+
return _orig_set_xticklabels(self, [str(x) for x in _to_list(labels)])
|
|
3029
|
+
|
|
3030
|
+
def _set_yticklabels(self, labels, **kwargs):
|
|
3031
|
+
return _orig_set_yticklabels(self, [str(x) for x in _to_list(labels)])
|
|
3032
|
+
|
|
3033
|
+
_rs.Axes.set_xticklabels = _set_xticklabels
|
|
3034
|
+
_rs.Axes.set_yticklabels = _set_yticklabels
|
|
3035
|
+
|
|
2927
3036
|
# axis: 支持序列 [xmin,xmax,ymin,ymax] 设定轴限,及 'off'/'on'/'equal' 等字符串。
|
|
2928
3037
|
_orig_axis = _rs.Axes.axis
|
|
2929
3038
|
|
|
@@ -2982,15 +3091,28 @@ def _patch_axes():
|
|
|
2982
3091
|
_orig_annotate = _rs.Axes.annotate
|
|
2983
3092
|
|
|
2984
3093
|
def _annotate(self, text, xy, xytext=None, fontsize=None,
|
|
2985
|
-
color="black", arrowprops=None,
|
|
2986
|
-
|
|
3094
|
+
color="black", arrowprops=None, xycoords='data',
|
|
3095
|
+
textcoords=None, ha=None, family=None, **kwargs):
|
|
3096
|
+
# 支持坐标系 (xycoords/textcoords)、水平对齐 (ha/horizontalalignment)、
|
|
3097
|
+
# 字体族 (family/fontfamily);其余未支持参数 (如 va) 被 **kwargs 吸收后丢弃。
|
|
2987
3098
|
if isinstance(text, str):
|
|
2988
3099
|
text = _render_mathtext(text)
|
|
2989
3100
|
# 未显式指定 fontsize 时,默认字号随其余默认字号一并放大 DEFAULT_FONT_SCALE 倍;
|
|
2990
3101
|
# 用户显式传入 fontsize 则保持原值不放大。
|
|
2991
3102
|
if fontsize is None:
|
|
2992
3103
|
fontsize = _DEFAULT_ANNOTATE_FONTSIZE
|
|
2993
|
-
|
|
3104
|
+
if ha is None:
|
|
3105
|
+
ha = kwargs.get('horizontalalignment', 'center')
|
|
3106
|
+
if family is None:
|
|
3107
|
+
family = kwargs.get('fontfamily', None)
|
|
3108
|
+
# xycoords 可能是 get_xaxis_transform / get_yaxis_transform 返回的标记字符串;
|
|
3109
|
+
# 若传入的是其它非字符串的 transform 对象则回退到 'data'。
|
|
3110
|
+
if not isinstance(xycoords, str):
|
|
3111
|
+
xycoords = 'data'
|
|
3112
|
+
if textcoords is not None and not isinstance(textcoords, str):
|
|
3113
|
+
textcoords = None
|
|
3114
|
+
return _orig_annotate(self, text, xy, xytext, fontsize, color,
|
|
3115
|
+
arrowprops, xycoords, textcoords, ha, family)
|
|
2994
3116
|
|
|
2995
3117
|
_rs.Axes.annotate = _annotate
|
|
2996
3118
|
|
|
@@ -202,6 +202,16 @@ pub enum PlotElement {
|
|
|
202
202
|
color: String,
|
|
203
203
|
/// 箭头参数;None 表示不画箭头(仅放置文本)。
|
|
204
204
|
arrow: Option<ArrowSpec>,
|
|
205
|
+
/// `xy` 的坐标系:"data" / "axes fraction" / "yaxis_transform"
|
|
206
|
+
/// (x 轴取 axes 分数, y 轴取 data) / "xaxis_transform" (x 取 data, y 取 axes 分数)。
|
|
207
|
+
xycoords: String,
|
|
208
|
+
/// `xytext` 的坐标系:"data" / "offset points" / "axes fraction" 等;
|
|
209
|
+
/// 未显式指定时与 `xycoords` 一致 (matplotlib 语义)。
|
|
210
|
+
textcoords: String,
|
|
211
|
+
/// 文本水平对齐:"left" / "center" / "right"。
|
|
212
|
+
ha: String,
|
|
213
|
+
/// 字体族 (family / fontfamily),None 表示用默认族。
|
|
214
|
+
family: Option<String>,
|
|
205
215
|
},
|
|
206
216
|
Stack {
|
|
207
217
|
x: Vec<f64>,
|