|
256 | 256 | gamma1 : float, optional |
257 | 257 | If >1, makes low saturation colors more prominent. If <1, |
258 | 258 | makes high saturation colors more prominent. Similar to the |
259 | | - `HCLWizard <http://hclwizard.org:64230/hclwizard/>`_ option. |
| 259 | + `HCLWizard <http://hclwizard.org:64230/hclwizard/>`__ option. |
260 | 260 | See `make_mapping_array` for details. |
261 | 261 | gamma2 : float, optional |
262 | 262 | If >1, makes high luminance colors more prominent. If <1, |
263 | 263 | makes low luminance colors more prominent. Similar to the |
264 | | - `HCLWizard <http://hclwizard.org:64230/hclwizard/>`_ option. |
| 264 | + `HCLWizard <http://hclwizard.org:64230/hclwizard/>`__ option. |
265 | 265 | See `make_mapping_array` for details. |
266 | 266 | gamma : float, optional |
267 | 267 | Use this to identically set `gamma1` and `gamma2` at once. |
@@ -611,6 +611,16 @@ def make_mapping_array(N, data, gamma=1.0, inverse=False): |
611 | 611 | :math:`w_i` ranges from 0 to 1 between rows ``i`` and ``i+1``. |
612 | 612 | If `gamma` is float, it applies to every transition. Otherwise, |
613 | 613 | its length must equal ``data.shape[0]-1``. |
| 614 | +
|
| 615 | + This is like the `gamma` used with matplotlib's |
| 616 | + `~matplotlib.colors.makeMappingArray`, except it controls the |
| 617 | + weighting for transitions *between* each segment data coordinate rather |
| 618 | + than the coordinates themselves. This makes more sense for |
| 619 | + `PerceptuallyUniformColormap`\\ s because they usually consist of just |
| 620 | + one linear transition for *sequential* colormaps and two linear |
| 621 | + transitions for *diverging* colormaps -- and in the latter case, it |
| 622 | + is often desirable to modify both "halves" of the colormap in the |
| 623 | + same way. |
614 | 624 | inverse : bool, optional |
615 | 625 | If ``True``, :math:`w_i^{\gamma_i}` is replaced with |
616 | 626 | :math:`1 - (1 - w_i)^{\gamma_i}` -- that is, when `gamma` is greater |
@@ -698,7 +708,6 @@ def make_mapping_array(N, data, gamma=1.0, inverse=False): |
698 | 708 |
|
699 | 709 | class _Colormap(): |
700 | 710 | """Mixin class used to add some helper methods.""" |
701 | | - |
702 | 711 | def _get_data(self, ext): |
703 | 712 | """ |
704 | 713 | Returns a string containing the colormap colors for saving. |
@@ -1048,13 +1057,29 @@ def save(self, path=None): |
1048 | 1057 | # Save channel segment data in json file |
1049 | 1058 | _, ext = os.path.splitext(filename) |
1050 | 1059 | if ext[1:] == 'json': |
| 1060 | + # Sanitize segmentdata values |
| 1061 | + # Convert np.float to builtin float, np.array to list of lists, |
| 1062 | + # and callable to list of lists. We tried encoding func.__code__ |
| 1063 | + # with base64 and marshal instead, but when cmap.concatenate() |
| 1064 | + # embeds functions as keyword arguments, this seems to make it |
| 1065 | + # *impossible* to load back up the function with FunctionType |
| 1066 | + # (error message: arg 5 (closure) must be tuple). Instead use |
| 1067 | + # this brute force workaround. |
1051 | 1068 | data = {} |
1052 | 1069 | for key, value in self._segmentdata.items(): |
1053 | | - # from np.float to builtin float, and to list of lists |
1054 | | - data[key] = np.array(value).astype(float).tolist() |
| 1070 | + if callable(value): |
| 1071 | + x = np.linspace(0, 1, 256) # just save the transitions |
| 1072 | + y = np.array([value(_) for _ in x]).squeeze() |
| 1073 | + value = np.vstack((x, y, y)).T |
| 1074 | + data[key] = np.asarray(value).astype(float).tolist() |
| 1075 | + # Add critical attributes to the dictionary |
| 1076 | + keys = () |
1055 | 1077 | if isinstance(self, PerceptuallyUniformColormap): |
1056 | | - for key in ('space', 'gamma1', 'gamma2'): |
1057 | | - data[key] = getattr(self, '_' + key) |
| 1078 | + keys = ('cyclic', 'gamma1', 'gamma2', 'space') |
| 1079 | + elif isinstance(self, LinearSegmentedColormap): |
| 1080 | + keys = ('cyclic', 'gamma') |
| 1081 | + for key in keys: |
| 1082 | + data[key] = getattr(self, '_' + key) |
1058 | 1083 | with open(filename, 'w') as file: |
1059 | 1084 | json.dump(data, file, indent=4) |
1060 | 1085 | # Save lookup table colors |
@@ -2681,12 +2706,12 @@ def _load_cmap_cycle(filename, cmap=False): |
2681 | 2706 | if ext == 'json': |
2682 | 2707 | with open(filename, 'r') as f: |
2683 | 2708 | data = json.load(f) |
| 2709 | + kw = {} |
| 2710 | + for key in ('cyclic', 'gamma', 'gamma1', 'gamma2', 'space'): |
| 2711 | + kw[key] = data.pop(key, None) |
2684 | 2712 | if 'red' in data: |
2685 | 2713 | data = LinearSegmentedColormap(name, data, N=N) |
2686 | 2714 | else: |
2687 | | - kw = {} |
2688 | | - for key in ('space', 'gamma1', 'gamma2'): |
2689 | | - kw[key] = data.pop(key, None) |
2690 | 2715 | data = PerceptuallyUniformColormap(name, data, N=N, **kw) |
2691 | 2716 | if name[-2:] == '_r': |
2692 | 2717 | data = data.reversed(name[:-2]) |
|
0 commit comments