Coverage for graphica/core/color_palettes.py: 75.8%
23 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"""
2組み込みの配色パレット(読み取り専用)と、利用者のパレットの検証。
3利用者のパレットは QSettings の custom_color_palettes_json に保存する(gui/mixins/dataset_mixin.py)。
4"""
6from graphica.core.named_colors import normalize_color
7from typing import Any
9# パレット管理の先頭にある「matplotlib の既定の色」の名前。設定に保存される値でもあるので変えない
10DEFAULT_PALETTE_NAME = "Matplotlib既定"
12# 出典: Tableau 10、ColorBrewer(Set2/Dark2/Paired、パブリックドメイン)、
13# Okabe & Ito (2008) Color Universal Design(1型/2型色覚でも判別しやすい8色)。
14BUILTIN_PALETTES = {
15 'Okabe-Ito(色覚多様性対応)': [
16 '#000000', '#e69f00', '#56b4e9', '#009e73',
17 '#f0e442', '#0072b2', '#d55e00', '#cc79a7',
18 ],
19 'Tableau 10': [
20 '#4e79a7', '#f28e2b', '#e15759', '#76b7b2', '#59a14f',
21 '#edc949', '#af7aa1', '#ff9da7', '#9c755f', '#bab0ab',
22 ],
23 'ColorBrewer Set2': [
24 '#66c2a5', '#fc8d62', '#8da0cb', '#e78ac3', '#a6d854',
25 '#ffd92f', '#e5c494', '#b3b3b3',
26 ],
27 'ColorBrewer Dark2': [
28 '#1b9e77', '#d95f02', '#7570b3', '#e7298a', '#66a61e',
29 '#e6ab02', '#a6761d', '#666666',
30 ],
31 'ColorBrewer Paired': [
32 '#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99',
33 '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a',
34 ],
35}
38def normalize_palettes(palettes: Any) -> dict[str, list[str]]:
39 """利用者のパレット {名前: [色, ...]} を検証し、色を小文字の #rrggbb にしたコピーを返す。"""
40 if not isinstance(palettes, dict): 40 ↛ 41line 40 didn't jump to line 41 because the condition on line 40 was never true
41 raise ValueError("パレットは {名前: [色, ...]} の形で渡してください。")
42 result = {}
43 for name, colors in palettes.items():
44 if not isinstance(name, str) or not name.strip(): 44 ↛ 45line 44 didn't jump to line 45 because the condition on line 44 was never true
45 raise ValueError("パレット名が空です。")
46 if name in BUILTIN_PALETTES: 46 ↛ 47line 46 didn't jump to line 47 because the condition on line 46 was never true
47 raise ValueError(f"「{name}」は組み込みのパレットと同じ名前です。")
48 if not isinstance(colors, (list, tuple)): 48 ↛ 49line 48 didn't jump to line 49 because the condition on line 48 was never true
49 raise ValueError(f"パレット「{name}」の色はリストで渡してください。")
50 result[name] = [normalize_color(c) for c in colors]
51 return result
54def known_palette_names(user_palettes: dict[str, list[str]]) -> set[str]:
55 """いま使うパレットに選べる名前(既定・組み込み・利用者のパレット)。"""
56 return {DEFAULT_PALETTE_NAME, *BUILTIN_PALETTES, *user_palettes}
59def default_color_cycle() -> list[str]:
60 """matplotlib の既定の色の並びを #rrggbb で返す。3.11 からは RGB の組で返り、QColor などに渡せない。"""
61 import matplotlib as mpl
62 from matplotlib.colors import to_hex
64 return [to_hex(color) for color in mpl.rcParams['axes.prop_cycle'].by_key()['color']]