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
« 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
6logger = logging.getLogger(__name__)
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']
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, :]
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 )
38 mode = ds.map_display_mode if ds.map_display_mode in canvas._VALID_MAP_DISPLAY_MODES else 'heatmap'
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
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