Coverage for graphica/gui/log_axis_notes.py: 96.6%

42 statements  

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

1"""対数軸で表示されない値(0 以下)を、対数のチェックの下で知らせる。 

2 

3matplotlib は対数軸の 0 以下の点を黙って消し、0 以下の最小値も黙って無視するので、何も描かれない理由が分からなくなる。 

4""" 

5import numpy as np 

6import pandas as pd 

7 

8from graphica.core.axis_settings import axis_setting, manual_axis_range 

9from graphica.core.i18n import tr 

10 

11# 軸のキー -> (対数の設定, 説明の欄の名前) 

12_AXES = { 

13 'x': ('x_log', 'x_log_note'), 

14 'y': ('y_log', 'y_log_note'), 

15 'y2': ('y2_log', 'y2_log_note'), 

16} 

17 

18 

19def _numbers(values): 

20 return pd.to_numeric(pd.Series(np.asarray(values).ravel()), errors='coerce').to_numpy(dtype=float) 

21 

22 

23def nonpositive_point_count(canvas, datasets, axis_index, axis_key): 

24 """axis_index のサブプロットで、axis_key の軸に描く値が 0 以下の点の数(描かれる位置で数える)。""" 

25 count = 0 

26 for ds in datasets: 

27 if not ds.visible or ds.data_kind == '2d_grid' or ds.subplot_target != axis_index: 

28 continue 

29 if axis_key == 'y' and ds.use_secondary_y or axis_key == 'y2' and not ds.use_secondary_y: 

30 continue 

31 # 文字の X(カテゴリ軸)は数にならないので数えない 

32 x, y = _numbers(ds.x_data), _numbers(ds.y_data) 

33 x, y = canvas.data_to_display(ds, x, y) 

34 values = np.asarray(x if axis_key == 'x' else y, dtype=float) 

35 count += int(np.count_nonzero(values <= 0)) 

36 return count 

37 

38 

39def log_note_text(count, min_ignored): 

40 """説明の文。知らせることが無ければ空。""" 

41 lines = [] 

42 if count: 

43 lines.append(tr("0 以下の値の点が {count} 個あり、対数軸では表示されません。").format(count=f"{count:,}")) 

44 if min_ignored: 

45 lines.append(tr("最小値が 0 以下なので、対数軸では無視されます。")) 

46 return "\n".join(lines) 

47 

48 

49def update_log_axis_notes(app, _event=None): 

50 """表示中の軸の設定で、X・Y・第 2 Y 軸の説明を出し入れする。描くたびと、表示中の軸を切り替えたときに呼ぶ。""" 

51 settings_list = app.project.all_plot_settings 

52 index = app.project.active_axis_index 

53 settings = settings_list[index] if 0 <= index < len(settings_list) else None 

54 for axis_key, (log_key, note_name) in _AXES.items(): 

55 note = getattr(app, note_name, None) 

56 if note is None: 56 ↛ 57line 56 didn't jump to line 57 because the condition on line 56 was never true

57 continue 

58 text = "" 

59 if settings is not None and axis_setting(settings, log_key): 

60 manual = manual_axis_range(settings, axis_key) 

61 min_ignored = manual is not None and manual[0] <= 0 

62 count = nonpositive_point_count(app.canvas, app.project.datasets, index, axis_key) 

63 text = log_note_text(count, min_ignored) 

64 note.setText(text) 

65 note.setVisible(bool(text))