|
1 | | -import os |
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +import copy |
| 4 | +import sys |
2 | 5 | from typing import Callable |
3 | 6 |
|
4 | 7 | import matplotlib.colors as pltc |
|
8 | 11 | from plotpy.mathutils.colormap import ( |
9 | 12 | DEFAULT_COLORMAPS, |
10 | 13 | DEFAULT_COLORMAPS_PATH, |
| 14 | + CmapDictType, |
11 | 15 | EditableColormap, |
12 | 16 | save_colormaps, |
13 | 17 | ) |
14 | 18 |
|
| 19 | +PERCEPTUALLY_UNIFORM_CMAPS = ["viridis", "plasma", "inferno", "magma", "cividis"] |
| 20 | +SEQUENTIAL_CMAPS = [ |
| 21 | + "Greys", |
| 22 | + "Purples", |
| 23 | + "Blues", |
| 24 | + "Greens", |
| 25 | + "Oranges", |
| 26 | + "Reds", |
| 27 | + "YlOrBr", |
| 28 | + "YlOrRd", |
| 29 | + "OrRd", |
| 30 | + "PuRd", |
| 31 | + "RdPu", |
| 32 | + "BuPu", |
| 33 | + "GnBu", |
| 34 | + "PuBu", |
| 35 | + "YlGnBu", |
| 36 | + "PuBuGn", |
| 37 | + "BuGn", |
| 38 | + "YlGn", |
| 39 | +] |
| 40 | +SEQUENTIAL_CMAPS2 = [ |
| 41 | + "binary", |
| 42 | + "gist_yarg", |
| 43 | + "gist_gray", |
| 44 | + "gray", |
| 45 | + "bone", |
| 46 | + "pink", |
| 47 | + "spring", |
| 48 | + "summer", |
| 49 | + "autumn", |
| 50 | + "winter", |
| 51 | + "cool", |
| 52 | + "Wistia", |
| 53 | + "hot", |
| 54 | + "afmhot", |
| 55 | + "gist_heat", |
| 56 | + "copper", |
| 57 | +] |
| 58 | +DIVERGING_CMAPS = [ |
| 59 | + "PiYG", |
| 60 | + "PRGn", |
| 61 | + "BrBG", |
| 62 | + "PuOr", |
| 63 | + "RdGy", |
| 64 | + "RdBu", |
| 65 | + "RdYlBu", |
| 66 | + "RdYlGn", |
| 67 | + "Spectral", |
| 68 | + "coolwarm", |
| 69 | + "bwr", |
| 70 | + "seismic", |
| 71 | +] |
| 72 | +CYCLIC_CMAPS = ["twilight", "twilight_shifted", "hsv"] |
| 73 | +QUALITATIVE_CMAPS = [ |
| 74 | + "Pastel1", |
| 75 | + "Pastel2", |
| 76 | + "Paired", |
| 77 | + "Accent", |
| 78 | + "Dark2", |
| 79 | + "Set1", |
| 80 | + "Set2", |
| 81 | + "Set3", |
| 82 | + "tab10", |
| 83 | + "tab20", |
| 84 | + "tab20b", |
| 85 | + "tab20c", |
| 86 | +] |
| 87 | +MISCELLANEOUS_CMAPS = [ |
| 88 | + "flag", |
| 89 | + "prism", |
| 90 | + "ocean", |
| 91 | + "gist_earth", |
| 92 | + "terrain", |
| 93 | + "gist_stern", |
| 94 | + "gnuplot", |
| 95 | + "gnuplot2", |
| 96 | + "CMRmap", |
| 97 | + "cubehelix", |
| 98 | + "brg", |
| 99 | + "gist_rainbow", |
| 100 | + "rainbow", |
| 101 | + "jet", |
| 102 | + "turbo", |
| 103 | + "nipy_spectral", |
| 104 | + "gist_ncar", |
| 105 | +] |
| 106 | + |
| 107 | +SORTED_MATPLOTLIB_COLORMAPS: list[str] = [ |
| 108 | + *PERCEPTUALLY_UNIFORM_CMAPS, |
| 109 | + *SEQUENTIAL_CMAPS, |
| 110 | + *SEQUENTIAL_CMAPS2, |
| 111 | + *DIVERGING_CMAPS, |
| 112 | + *CYCLIC_CMAPS, |
| 113 | + *QUALITATIVE_CMAPS, |
| 114 | + *MISCELLANEOUS_CMAPS, |
| 115 | +] |
| 116 | + |
15 | 117 |
|
16 | 118 | def rgb_colors_to_hex_list( |
17 | 119 | colors: list[tuple[int, int, int]] |
@@ -112,15 +214,53 @@ def continuous_to_descrete_cmap(cmap: EditableColormap) -> EditableColormap: |
112 | 214 | prev_pos, prev_color = raw_cmap[i] |
113 | 215 | curr_pos, curr_color = pos, color |
114 | 216 | new_pos = curr_pos * coeff |
115 | | - print(curr_pos, new_pos, coeff) |
116 | 217 | new_raw_cmap.append((new_pos, prev_color)) |
117 | 218 | new_raw_cmap.append((new_pos, curr_color)) |
118 | 219 | new_raw_cmap.append(raw_cmap[-1]) |
119 | 220 |
|
120 | 221 | return EditableColormap.from_iterable(new_raw_cmap, name=cmap.name) |
121 | 222 |
|
122 | 223 |
|
123 | | -def main(): |
| 224 | +def sort_mpl_colormaps(colormaps: CmapDictType) -> CmapDictType: |
| 225 | + """Filter and sort input colormaps to follow the same order (by category) as in the |
| 226 | + matplotlib colormaps documentation. Colormaps not found in the matplotlib |
| 227 | + are filtered out. |
| 228 | +
|
| 229 | + Args: |
| 230 | + colormaps: Dictionnary of colormaps to extract and order |
| 231 | +
|
| 232 | + Returns: |
| 233 | + Filtered and sorted colormaps dictionnary |
| 234 | + """ |
| 235 | + ordered_colormaps: CmapDictType = {} |
| 236 | + lower_cmap_names = [cm.lower() for cm in SORTED_MATPLOTLIB_COLORMAPS] |
| 237 | + for lower_name in lower_cmap_names: |
| 238 | + cmap = colormaps.get(lower_name, None) |
| 239 | + if lower_name.endswith("_r"): |
| 240 | + continue |
| 241 | + if cmap is None: |
| 242 | + print(f"Colormap {lower_name} not found in input colormaps.") |
| 243 | + continue |
| 244 | + ordered_colormaps[lower_name] = cmap |
| 245 | + return ordered_colormaps |
| 246 | + |
| 247 | + |
| 248 | +def append_non_mpl_colormaps(mpl_colormaps: CmapDictType, colormaps: CmapDictType): |
| 249 | + """Append colormaps not found in the matplotlib colormaps to the input colormaps. |
| 250 | + Mutate the input in place. |
| 251 | +
|
| 252 | + Args: |
| 253 | + mpl_colormaps: dictionnary of matplotlib colormaps. Mutated in place. |
| 254 | + colormaps: dictionnary of colormaps to append to the matplotlib colormaps |
| 255 | + """ |
| 256 | + colormap_names = set(SORTED_MATPLOTLIB_COLORMAPS) |
| 257 | + for colormap in colormaps.values(): |
| 258 | + if colormap.name not in colormap_names: |
| 259 | + print(f"{colormap} not in matplotlib colormaps.") |
| 260 | + mpl_colormaps[colormap.name.lower()] = colormap |
| 261 | + |
| 262 | + |
| 263 | +def main(cmaps: CmapDictType, out_json_path: str = DEFAULT_COLORMAPS_PATH): |
124 | 264 |
|
125 | 265 | new_cmaps: dict[str, list[tuple[float, str]]] = {} |
126 | 266 |
|
@@ -179,13 +319,14 @@ def main(): |
179 | 319 | new_cmaps[cm_name] = func_segmented_cmap_to_hex_list(n, cmap) |
180 | 320 |
|
181 | 321 | for name, raw_cm in new_cmaps.items(): |
182 | | - DEFAULT_COLORMAPS[name.lower()] = EditableColormap.from_iterable( |
183 | | - raw_cm, name=name |
184 | | - ) |
| 322 | + cmaps[name.lower()] = EditableColormap.from_iterable(raw_cm, name=name) |
185 | 323 |
|
186 | | - json_file = os.path.join(os.path.dirname(__file__), "new_colormaps.json") |
187 | | - save_colormaps(json_file, DEFAULT_COLORMAPS_PATH) |
| 324 | + ordered_cmaps = sort_mpl_colormaps(cmaps) |
| 325 | + append_non_mpl_colormaps(ordered_cmaps, cmaps) |
| 326 | + save_colormaps(out_json_path, ordered_cmaps) |
188 | 327 |
|
189 | 328 |
|
190 | 329 | if __name__ == "__main__": |
191 | | - main() |
| 330 | + cmaps = copy.deepcopy(DEFAULT_COLORMAPS) |
| 331 | + out_json = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_COLORMAPS_PATH |
| 332 | + main(cmaps, out_json) |
0 commit comments