Coverage for graphica/gui/rendering/data_2d.py: 92.5%

37 statements  

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

1"""2D マップ(ヒートマップ・等高線)の描画。""" 

2import logging 

3import numpy as np 

4from graphica.gui.rendering.common import GRID_2D_MAX_DISPLAY_POINTS_PER_AXIS 

5 

6logger = logging.getLogger(__name__) 

7 

8 

9def draw_2d_data(canvas, ax, axis_index, datasets_2d, full_resolution=False): 

10 """ 

11 2Dマップを描く。規則格子でも補間した格子でも同じ形の z_grid なので、等間隔を前提にする imshow ではなく 

12 pcolormesh を使う。map_display_mode: 'heatmap' / 'contour'(線だけ、色と太さはデータセットの線) / 

13 'contour_filled' / 'heatmap_contour'。カラーバーの対象は塗りのある方式だけ(線だけの等高線には付けない慣習)。 

14 """ 

15 canvas._axis_2d_mappables.pop(axis_index, None) 

16 for ds in datasets_2d: 

17 grid = ds.z_grid 

18 if grid is None: 

19 continue 

20 x_grid, y_grid, z_grid = grid['x_grid'], grid['y_grid'], grid['z_grid'] 

21 

22 if not full_resolution and len(x_grid) > GRID_2D_MAX_DISPLAY_POINTS_PER_AXIS: 

23 step = int(np.ceil(len(x_grid) / GRID_2D_MAX_DISPLAY_POINTS_PER_AXIS)) 

24 x_grid = x_grid[::step] 

25 z_grid = z_grid[:, ::step] 

26 if not full_resolution and len(y_grid) > GRID_2D_MAX_DISPLAY_POINTS_PER_AXIS: 26 ↛ 27line 26 didn't jump to line 27 because the condition on line 26 was never true

27 step = int(np.ceil(len(y_grid) / GRID_2D_MAX_DISPLAY_POINTS_PER_AXIS)) 

28 y_grid = y_grid[::step] 

29 z_grid = z_grid[::step, :] 

30 

31 vmin = ds.vmin if ds.vmin is not None else ( 

32 float(np.nanmin(z_grid)) if np.any(~np.isnan(z_grid)) else None 

33 ) 

34 vmax = ds.vmax if ds.vmax is not None else ( 

35 float(np.nanmax(z_grid)) if np.any(~np.isnan(z_grid)) else None 

36 ) 

37 

38 mode = ds.map_display_mode if ds.map_display_mode in canvas._VALID_MAP_DISPLAY_MODES else 'heatmap' 

39 

40 try: 

41 mappable = None 

42 contour_set = None 

43 # label は付けない。QuadMesh/ContourSet は凡例に載らず、凡例を作るたびに警告が出る 

44 if mode in ('heatmap', 'heatmap_contour'): 

45 mappable = ax.pcolormesh( 

46 x_grid, y_grid, z_grid, cmap=ds.colormap, vmin=vmin, vmax=vmax, 

47 shading='auto', alpha=ds.alpha, 

48 ) 

49 elif mode == 'contour_filled': 

50 mappable = ax.contourf( 

51 x_grid, y_grid, z_grid, levels=ds.contour_levels, cmap=ds.colormap, 

52 vmin=vmin, vmax=vmax, alpha=ds.alpha, 

53 ) 

54 if mode in ('contour', 'heatmap_contour'): 

55 contour_set = ax.contour( 

56 x_grid, y_grid, z_grid, levels=ds.contour_levels, colors=ds.color, 

57 alpha=ds.alpha, linewidths=ds.linewidth, 

58 ) 

59 except ValueError as e: 

60 # 知らないカラーマップ名など。このデータセットだけ飛ばす 

61 logger.warning("2Dマップの描画に失敗しました(%s): %s", ds.name, e) 

62 continue 

63 

64 ds.artist = mappable if mappable is not None else contour_set 

65 if mappable is not None: 

66 canvas._axis_2d_mappables[axis_index] = mappable