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

1"""マーカーの塗りと枠線(Dataset の marker_fill など)を matplotlib の引数にする。描画と Python スクリプトの書き出しが共有する。 

2 

3既定の値では空の辞書を返し、今までと同じ呼び出しのまま描く(保存済みのプロジェクトの見た目を変えない)。 

4""" 

5from typing import Any 

6 

7MARKER_FILL_SOLID = 'solid' 

8MARKER_FILL_HOLLOW = 'hollow' 

9MARKER_FILL_COLOR = 'color' 

10 

11# 'same' は系列の色(値で色分けする種類では塗りと同じ色) 

12MARKER_EDGE_SAME = 'same' 

13MARKER_EDGE_COLOR = 'color' 

14 

15# matplotlib の既定(lines.markeredgewidth。scatter の枠線も同じ 1.0) 

16DEFAULT_MARKER_EDGE_WIDTH = 1.0 

17 

18# 線だけでできた形。塗りが無く、scatter は枠線の色を無視して塗りの色で線を引く(白抜きにすると消える) 

19UNFILLED_MARKERS = frozenset({'+', 'x', '1', '2', '3', '4', '|', '_'}) 

20 

21 

22def marker_is_unfilled(marker: Any) -> bool: 

23 return marker in UNFILLED_MARKERS 

24 

25 

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 

45 

46 

47def mapped_scatter_marker_kwargs(ds: Any) -> tuple[dict[str, Any], bool]: 

48 """値で色分けする ax.scatter(c=..., ...) の引数と、描いたあとに白抜きにするか。 

49 

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 

60 

61 

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) 

67 

68 

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