Coverage for graphica/gui/plot_type_drawers.py: 97.8%

71 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-12 16:38 +0000

1""" 

2組み込みの plot_type ごとの描き方。プラグインの register_plot_type と同じく「種類名 → 描画関数」の表で引く。 

3 

4描画関数は (canvas, ax, ds, x, y, plot_kwargs, axis_index) を受け取り、ds.artist にする artist を返す。 

5x, y はウォーターフォールのずらし・欠損値の処理・表示用の間引きを済ませた点列。 

6plot_kwargs(ウォーターフォールの zorder)はグラデーションの線には渡さない。 

7""" 

8import logging 

9 

10import numpy as np 

11from scipy.stats import gaussian_kde 

12 

13from graphica.core.dataset import COLOR_BY_COLUMN_PLOT_TYPE, legend_text 

14from graphica.core.marker_style import ( 

15 apply_mapped_hollow, line_marker_kwargs, mapped_scatter_marker_kwargs, scatter_marker_kwargs) 

16 

17logger = logging.getLogger(__name__) 

18 

19 

20def _uses_line_gradient(ds): 

21 return ds.gradient_enabled and ds.gradient_target in ('line', 'both') 

22 

23 

24def _gradient_line(canvas, ax, ds, x, y): 

25 return canvas._add_gradient_line( 

26 ax, x, y, ds.color, ds.gradient_color2, ds.linewidth, ds.alpha, ds.linestyle, label=legend_text(ds)) 

27 

28 

29def _plain_line(ax, ds, x, y, plot_kwargs, **extra): 

30 (artist,) = ax.plot(x, y, color=ds.color, linestyle=ds.linestyle, linewidth=ds.linewidth, 

31 alpha=ds.alpha, label=legend_text(ds), **extra, **plot_kwargs) 

32 return artist 

33 

34 

35def _markers(ax, ds, x, y, plot_kwargs, **extra): 

36 style = {'color': ds.color, **scatter_marker_kwargs(ds)} 

37 return ax.scatter(x, y, marker=ds.marker, s=ds.markersize**2, alpha=ds.alpha, **style, **extra, **plot_kwargs) 

38 

39 

40def _mapped_markers(ax, ds, x, y, plot_kwargs, **mapping): 

41 """値で色分けするマーカー。mapping は c・cmap など色の対応。""" 

42 style, hollow = mapped_scatter_marker_kwargs(ds) 

43 artist = ax.scatter(x, y, marker=ds.marker, s=ds.markersize**2, alpha=ds.alpha, label=legend_text(ds), 

44 **mapping, **style, **plot_kwargs) 

45 if hollow: 

46 apply_mapped_hollow(artist, ds) 

47 return artist 

48 

49 

50def draw_line(canvas, ax, ds, x, y, plot_kwargs, axis_index): 

51 if _uses_line_gradient(ds): 

52 return _gradient_line(canvas, ax, ds, x, y) 

53 return _plain_line(ax, ds, x, y, plot_kwargs) 

54 

55 

56def draw_scatter(canvas, ax, ds, x, y, plot_kwargs, axis_index): 

57 return _markers(ax, ds, x, y, plot_kwargs, label=legend_text(ds)) 

58 

59 

60def draw_line_and_scatter(canvas, ax, ds, x, y, plot_kwargs, axis_index): 

61 if _uses_line_gradient(ds): 

62 # LineCollection はマーカーを描けないので、マーカーは単色で重ねる 

63 artist = _gradient_line(canvas, ax, ds, x, y) 

64 _markers(ax, ds, x, y, plot_kwargs) 

65 return artist 

66 (artist,) = ax.plot(x, y, color=ds.color, linestyle=ds.linestyle, linewidth=ds.linewidth, 

67 marker=ds.marker, markersize=ds.markersize, alpha=ds.alpha, label=legend_text(ds), 

68 **line_marker_kwargs(ds), **plot_kwargs) 

69 return artist 

70 

71 

72def draw_area(canvas, ax, ds, x, y, plot_kwargs, axis_index): 

73 """0 との間を塗り、輪郭が分かるよう上端に線も重ねる。""" 

74 if not ds.gradient_enabled: 

75 artist = ax.fill_between(x, y, 0, color=ds.color, alpha=ds.alpha * 0.4, label=legend_text(ds), **plot_kwargs) 

76 ax.plot(x, y, color=ds.color, linestyle=ds.linestyle, linewidth=ds.linewidth, alpha=ds.alpha, **plot_kwargs) 

77 return artist 

78 if ds.gradient_target in ('fill', 'both'): 

79 artist = canvas._add_gradient_fill(ax, x, y, ds.color, ds.gradient_color2, ds.alpha * 0.4) 

80 else: 

81 artist = ax.fill_between(x, y, 0, color=ds.color, alpha=ds.alpha * 0.4, **plot_kwargs) 

82 if ds.gradient_target in ('line', 'both'): 

83 _gradient_line(canvas, ax, ds, x, y) 

84 else: 

85 _plain_line(ax, ds, x, y, plot_kwargs) 

86 return artist 

87 

88 

89def draw_bar(canvas, ax, ds, x, y, plot_kwargs, axis_index): 

90 return ax.bar(x, y, color=ds.color, alpha=ds.alpha, label=legend_text(ds), **plot_kwargs) 

91 

92 

93def draw_step(canvas, ax, ds, x, y, plot_kwargs, axis_index): 

94 # 区間の左端の値を右端まで保つ(サンプリング・イベントデータの慣習) 

95 return _plain_line(ax, ds, x, y, plot_kwargs, drawstyle='steps-post') 

96 

97 

98def draw_density_scatter(canvas, ax, ds, x, y, plot_kwargs, axis_index): 

99 """各点の位置での2次元カーネル密度を色にする。点が少ない・全点が同じ座標だと KDE が失敗するので単色にする。""" 

100 try: 

101 if len(x) < 3: 

102 raise ValueError("点数不足") 

103 xy = np.vstack([x, y]) 

104 density = gaussian_kde(xy)(xy) 

105 return _mapped_markers(ax, ds, x, y, plot_kwargs, c=density, cmap=ds.colormap) 

106 except (np.linalg.LinAlgError, ValueError): 

107 return _markers(ax, ds, x, y, plot_kwargs, label=legend_text(ds)) 

108 

109 

110def draw_color_by_column(canvas, ax, ds, x, y, plot_kwargs, axis_index): 

111 """ 

112 z_col_name の列の値で点を色分けする。z は visible_df 経由(ds.z_data)で取る 

113 (df から取ると、行を除外したとたん点と色が1つずつずれる)。 

114 """ 

115 z_values = ds.z_data 

116 if z_values is not None and len(z_values) == len(x): 

117 artist = _mapped_markers(ax, ds, x, y, plot_kwargs, c=z_values, cmap=ds.colormap, vmin=ds.vmin, vmax=ds.vmax) 

118 # カラーバーは1軸に1つ。2Dマップが先に登録していればそちらを優先する 

119 if axis_index not in canvas._axis_2d_mappables: 

120 canvas._axis_2d_mappables[axis_index] = artist 

121 return artist 

122 if z_values is not None: 122 ↛ 124line 122 didn't jump to line 124 because the condition on line 122 was never true

123 # 欠損値の方針 'drop' で点が減ったときなど。黙って単色になると理由が分からないのでログに残す 

124 logger.warning( 

125 "'%s' のZ列の長さ(%d)がプロット点数(%d)と一致しないため、" 

126 "単色のScatterとして描画します(欠損値の方針'drop'等で" 

127 "配列が短くなっている可能性があります)。", 

128 ds.name, len(z_values), len(x), 

129 ) 

130 return _markers(ax, ds, x, y, plot_kwargs, label=legend_text(ds)) 

131 

132 

133BUILTIN_PLOT_TYPE_DRAWERS = { 

134 'Line': draw_line, 

135 'Scatter': draw_scatter, 

136 'Line+Scatter': draw_line_and_scatter, 

137 'Area': draw_area, 

138 'Bar': draw_bar, 

139 'Step': draw_step, 

140 'Density Scatter': draw_density_scatter, 

141 COLOR_BY_COLUMN_PLOT_TYPE: draw_color_by_column, 

142}