未分類

        else:
if model_name == "MSM_GUID":
elements = [
("卓越\n天気", "wea", 1),
("最小\n視程\n(km)", "vis", 1),
("3時間\n降水量", "precip", 1),
("6時間\n降水量", "precip6", 2),
("12時間\n降水量", "precip12", 4),
("24時間\n降水量", "precip24", 8),
("1時間\n最大降水", "precip1max", 1),
("3時間\n最大降水", "precip3max", 1),
("24時間\n最大降水", "precip24max", 8),
("3時間\n降雪量", "snow3", 1),
("6時間\n降雪量", "snow6", 2),
("12時間\n降雪量", "snow12", 4),
("24時間\n降雪量", "snow24", 8),
("6時間雨\n確率(%)", "prob_precip6", 2),
("発雷\n確率(%)", "thund", 1)
]
else: # GSM_GUID (最小視程なし)
elements = [
("卓越\n天気", "wea", 1),
("3時間\n降水量", "precip", 1),
("6時間\n降水量", "precip6", 2),
("12時間\n降水量", "precip12", 4),
("24時間\n降水量", "precip24", 8),
("1時間\n最大降水", "precip1max", 1),
("3時間\n最大降水", "precip3max", 1),
("24時間\n最大降水", "precip24max", 8),
("3時間\n降雪量", "snow3", 1),
("6時間\n降雪量", "snow6", 2),
("12時間\n降雪量", "snow12", 4),
("24時間\n降雪量", "snow24", 8),
("6時間雨\n確率(%)", "prob_precip6", 2),
("発雷\n確率(%)", "thund", 1)
]

max_ft = self.tab_ui[model_name]['slider'].maximum()
min_ft = 3 if model_name == "MSM_GUID" else 6
fts = list(range(min_ft, max_ft + 1, 3))

data_dict = {elem[1]: {} for elem in elements}

for ft in fts:
guid_file = os.path.join(self.cache_dir, f"{model_name}_{it_str}_FT{ft:02d}.npz")
if os.path.exists(guid_file):
try:
with np.load(guid_file) as d:
for e_name, e_key, span in elements:
search_keys = []
span_h = span * 3 if span < 8 else 24

if e_key == "wea":
search_keys = ['wea', 'weather', 'wx', 'var_-1_-1_-1', 'var_0_19_192']
val = self.extract_val_robust(d, search_keys, stat_lon, stat_lat)
if not np.isnan(val): data_dict[e_key][ft] = {1:"晴", 2:"曇", 3:"雨", 4:"雪"}.get(int(val), "不明")
elif e_key == "vis":
search_keys = ['vis', 'visib', 'visibility']
val = self.extract_val_robust(d, search_keys, stat_lon, stat_lat)
if not np.isnan(val): data_dict[e_key][ft] = val / 1000.0
elif e_key == "prob_precip6":
search_keys = ['prob_precip6']
val = self.extract_val_robust(d, search_keys, stat_lon, stat_lat)
if not np.isnan(val): data_dict[e_key][ft] = val
elif e_key == "thund":
search_keys = ['thund', 'pol', 'lig', 'thunder', 'tstm', 'var_0_19_193']
val = self.extract_val_robust(d, search_keys, stat_lon, stat_lat)
if not np.isnan(val): data_dict[e_key][ft] = val
else:
if "降水量" in e_name or "最大降水" in e_name:
if "最大" in e_name:
span_h = 1 if "1時間" in e_name else (3 if "3時間" in e_name else 24)
search_keys.extend([e_key] + [k for k in d.files if k.startswith("tp_") and k.endswith(f"_{max(0, ft-span_h)}_{ft}")])
else:
search_keys.extend([e_key, 'precip', 'tp', 'tprate'] + [k for k in d.files if k.startswith("tp_") and k.endswith(f"_{max(0, ft-span_h)}_{ft}")])
elif "降雪" in e_name:
if span > 1:
search_keys.append(e_key)
else:
search_keys.extend([e_key, 'snow3', 'asnow', 'tsrate'] + [k for k in d.files if k.startswith("asnow_") and k.endswith(f"_{max(0, ft-3)}_{ft}")])

val = self.extract_val_robust(d, search_keys, stat_lon, stat_lat)
if not np.isnan(val): data_dict[e_key][ft] = val
except: pass

fig = Figure(figsize=(16, 8.5)); fig.patch.set_facecolor('white')
fig.subplots_adjust(left=0.01, right=0.99, top=0.92, bottom=0.01)
ax = fig.add_subplot(111); ax.axis('off')

n_rows = len(elements) + 3
n_cols = 1 + len(fts)

ax.set_xlim(0, n_cols)
ax.set_ylim(0, n_rows)

def draw_cell(x, y, w, h, text, bg_color='white', font_weight='normal', text_color='black', fontsize=10):
rect = plt.Rectangle((x, y), w, h, facecolor=bg_color, edgecolor='black', linewidth=0.5)
ax.add_patch(rect)
ax.text(x + w/2.0, y + h/2.0, text, color=text_color, ha='center', va='center', weight=font_weight, fontsize=fontsize)

current_y = n_rows - 1
draw_cell(0, current_y - 2, 1, 3, "要素 / 日時", bg_color='#1D3557', font_weight='bold', text_color='white', fontsize=10)

for i, ft in enumerate(fts):
target_jst = dt_utc + timedelta(hours=9+ft)
draw_cell(1 + i, current_y, 1, 1, target_jst.strftime("%m/%d"), bg_color='#1D3557', font_weight='bold', text_color='white', fontsize=8)
draw_cell(1 + i, current_y - 2, 1, 2, f"{target_jst.strftime('%H')}時\n(FT{ft:02d})", bg_color='#457B9D', font_weight='bold', text_color='white', fontsize=8)

current_y -= 3

for s_idx, (e_name, e_key, span) in enumerate(elements):
row_y = current_y - s_idx
draw_cell(0, row_y, 1, 1, e_name, bg_color='#F1FAEE', font_weight='bold', fontsize=9)

col_idx = 0
while col_idx < len(fts):
ft = fts[col_idx]
target_ft = ft + (span - 1) * 3

# 結合セルのアライメント(区切り位置)調整
skip_cell = False
if e_key == "prob_precip6" and span == 2:
if target_ft % 6 != 3: skip_cell = True
elif span == 2 and target_ft % 6 != 0:
skip_cell = True
elif span == 4 and target_ft % 12 != 0:
skip_cell = True
elif span == 8 and target_ft % 24 != 0:
skip_cell = True

if skip_cell:
bg_c = 'white' if s_idx % 2 != 0 else '#F8F9FA'
draw_cell(1 + col_idx, row_y, 1, 1, "-", bg_color=bg_c, fontsize=10)
col_idx += 1
continue

incomplete = False
if span > 1 and "降水" in e_name and "最大" not in e_name and "確率" not in e_name:
val = 0
v_count = 0
for step in range(span):
v = data_dict[e_key].get(ft + step * 3, np.nan)
if not np.isnan(v):
val += v
v_count += 1
if v_count == 0: val = np.nan
elif v_count < span: incomplete = True
else:
val = data_dict[e_key].get(target_ft, np.nan)

bg_c = 'white' if s_idx % 2 != 0 else '#F8F9FA'

if e_key == "wea":
val_str = val if isinstance(val, str) else "-"
else:
val_str = f"{val:.1f}" if not np.isnan(val) else "-"
if e_key == "thund" or e_key == "prob_precip6":
if not np.isnan(val): val_str = f"{val:.0f}"

if val_str == "0.0": val_str = "0"
if incomplete and val_str != "-":
val_str += "*"

if not np.isnan(val) and val > 0:
if e_key == "thund" or e_key == "prob_precip6":
if val >= 50: bg_c = '#FFCDD2'
elif val >= 20: bg_c = '#FFF9C4'
elif "降水" in e_name or "降雪" in e_name:
if val >= 20: bg_c = '#FFCDD2'
elif val >= 10: bg_c = '#FFF9C4'
elif val >= 1: bg_c = '#E3F2FD'
elif e_key == "vis":
if val < 1.0: bg_c = '#FFCDD2'
elif val < 5.0: bg_c = '#FFF9C4'

w = min(span, len(fts) - col_idx)
draw_cell(1 + col_idx, row_y, w, 1, val_str, bg_color=bg_c, fontsize=10)
col_idx += span

fig.suptitle(f"{stat_name} 統合ガイダンス時系列表 (初期時: {dt_utc.strftime('%m/%d %H:00Z')})", fontsize=16, weight='bold', y=0.98)
fig.text(0.5, 0.945, "※6/12/24時間降水量は3時間値の合算(近似)。*は欠測を含む合算。降雪6/12/24hは期間別の統計値。", ha='center', va='center', fontsize=10, color='#555555')
canvas = FigureCanvas(fig)
win = SingleImageWindow(self, f"GUID_{stat_name}", model_name, stat_name, dt_utc.strftime("%m%d%H") + "Z", canvas)
win.exec()