Coverage for graphica/core/marker_style.py: 96.1%
50 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
1"""マーカーの塗りと枠線(Dataset の marker_fill など)を matplotlib の引数にする。描画と Python スクリプトの書き出しが共有する。
3既定の値では空の辞書を返し、今までと同じ呼び出しのまま描く(保存済みのプロジェクトの見た目を変えない)。
4"""
5from typing import Any
7MARKER_FILL_SOLID = 'solid'
8MARKER_FILL_HOLLOW = 'hollow'
9MARKER_FILL_COLOR = 'color'
11# 'same' は系列の色(値で色分けする種類では塗りと同じ色)
12MARKER_EDGE_SAME = 'same'
13MARKER_EDGE_COLOR = 'color'
15# matplotlib の既定(lines.markeredgewidth。scatter の枠線も同じ 1.0)
16DEFAULT_MARKER_EDGE_WIDTH = 1.0
18# 線だけでできた形。塗りが無く、scatter は枠線の色を無視して塗りの色で線を引く(白抜きにすると消える)
19UNFILLED_MARKERS = frozenset({'+', 'x', '1', '2', '3', '4', '|', '_'})
22def marker_is_unfilled(marker: Any) -> bool:
23 return marker in UNFILLED_MARKERS
26def scatter_marker_kwargs(ds: Any) -> dict[str, Any]:
27 """単色の ax.scatter(color=ds.color, ...) の上に重ねる引数。"""
28 kwargs: dict[str, Any] = {}
29 edge_color = ds.marker_edge_color if ds.marker_edge == MARKER_EDGE_COLOR else None
30 if marker_is_unfilled(ds.marker):
31 if edge_color is not None: 31 ↛ 42line 31 didn't jump to line 42 because the condition on line 31 was always true
32 kwargs['color'] = edge_color
33 else:
34 if ds.marker_fill == MARKER_FILL_HOLLOW:
35 kwargs['facecolors'] = 'none'
36 kwargs['edgecolors'] = ds.color
37 elif ds.marker_fill == MARKER_FILL_COLOR:
38 kwargs['facecolors'] = ds.marker_face_color
39 kwargs['edgecolors'] = ds.color
40 if edge_color is not None:
41 kwargs['edgecolors'] = edge_color
42 if ds.marker_edge_width != DEFAULT_MARKER_EDGE_WIDTH:
43 kwargs['linewidths'] = ds.marker_edge_width
44 return kwargs
47def mapped_scatter_marker_kwargs(ds: Any) -> tuple[dict[str, Any], bool]:
48 """値で色分けする ax.scatter(c=..., ...) の引数と、描いたあとに白抜きにするか。
50 塗りは色の対応が受け持つので「色を指定」は使わない。c と facecolors を一緒に渡すと c が勝つため、
51 白抜きは描いたあとに apply_mapped_hollow で塗りを消す。
52 """
53 kwargs: dict[str, Any] = {}
54 unfilled = marker_is_unfilled(ds.marker)
55 if ds.marker_edge == MARKER_EDGE_COLOR and not unfilled:
56 kwargs['edgecolors'] = ds.marker_edge_color
57 if ds.marker_edge_width != DEFAULT_MARKER_EDGE_WIDTH: 57 ↛ 58line 57 didn't jump to line 58 because the condition on line 57 was never true
58 kwargs['linewidths'] = ds.marker_edge_width
59 return kwargs, ds.marker_fill == MARKER_FILL_HOLLOW and not unfilled
62def apply_mapped_hollow(artist: Any, ds: Any) -> None:
63 """塗りを消す。枠線が系列の色なら、色の対応を枠線へ移す(元の枠線の色が None だと対応が枠線に付く)。"""
64 artist.set_facecolor('none')
65 if ds.marker_edge != MARKER_EDGE_COLOR:
66 artist.set_edgecolor(None)
69def line_marker_kwargs(ds: Any) -> dict[str, Any]:
70 """マーカー付きの ax.plot(...) の引数。Line2D は線だけの形も枠線の色で引くので、形で分けなくてよい。"""
71 kwargs: dict[str, Any] = {}
72 if ds.marker_fill == MARKER_FILL_HOLLOW:
73 kwargs['markerfacecolor'] = 'none'
74 elif ds.marker_fill == MARKER_FILL_COLOR:
75 kwargs['markerfacecolor'] = ds.marker_face_color
76 if ds.marker_edge == MARKER_EDGE_COLOR:
77 kwargs['markeredgecolor'] = ds.marker_edge_color
78 if ds.marker_edge_width != DEFAULT_MARKER_EDGE_WIDTH:
79 kwargs['markeredgewidth'] = ds.marker_edge_width
80 return kwargs