@@ -107,3 +107,164 @@ def lighten(cmapin, alpha):
107
107
108
108
# set the alpha value while retaining the number of rows in original cmap
109
109
return cmap (cmapin (np .linspace (0 ,1 ,cmapin .N ), alpha ))
110
+
111
+
112
+ def crop (cmapin , vmin , vmax , pivot , N = None , dmax = None ):
113
+ '''Crop end or ends of a diverging colormap by vmin/vmax values.
114
+
115
+ :param cmap: A colormap object, like cmocean.cm.matter.
116
+ :param vmin/vmax: vmin/vmax for use in plot with colormap.
117
+ :param pivot: center point to be used in plot with diverging colormap.
118
+ :param N=None: User can specify the number of rows for the outgoing colormap.
119
+ If unspecified, N from incoming colormap will be used and values will
120
+ be interpolated as needed to fill in rows.
121
+ :param dmax=None: dmax is the highest number to be included in a plot with
122
+ the colormap; values higher in magnitude than dmax are removed from both
123
+ ends of colormap. It should be less than abs(vmin) and abs(vmax), which
124
+ should be equal for this parameter to be used.
125
+
126
+ Outputs resultant colormap object.
127
+
128
+ This function can be used for sequential and other non-diverging colormaps
129
+ but it is easier to use that way through crop_by_percent().
130
+ This should be useful for plotting bathymetry and topography data with the
131
+ topo colormap when max bathymetry value is different from max topography.
132
+
133
+ Example usage:
134
+ # example for crop on min end of diverging colormap
135
+ vmin = -2; vmax = 5; pivot = 0
136
+ newcmap = crop(cmocean.cm.curl, vmin, vmax, pivot)
137
+ A = np.random.randint(vmin, vmax, (5,5))
138
+ plt.pcolormesh(A, vmin=vmin, vmax=vmax, cmap=newcmap)
139
+ plt.colorbar()
140
+
141
+ # example for crop on max end of diverging colormap
142
+ vmin = -10; vmax = 8; pivot = 0
143
+ newcmap = crop(cmocean.cm.delta, vmin, vmax, pivot)
144
+ A = np.random.randint(vmin, vmax, (5,5))
145
+ plt.pcolormesh(A, vmin=vmin, vmax=vmax, cmap=newcmap)
146
+ plt.colorbar()
147
+
148
+ '''
149
+
150
+ assert pivot >= vmin and pivot <= vmax
151
+
152
+ # dmax used if and only if ends are equal
153
+ if vmax - pivot == pivot - vmin :
154
+ assert dmax is not None
155
+
156
+ # allow user to input N, but otherwise use N for incoming colormap
157
+ if N is None :
158
+ N = cmapin .N
159
+ else :
160
+ N = N
161
+
162
+ # ratio of the colormap to remove
163
+ below = pivot - vmin # below pivot
164
+ above = vmax - pivot # above pivot
165
+
166
+ ranges = (above , below )
167
+ half_range = max (ranges )
168
+ full_range = half_range * 2
169
+ reduced_range = min (ranges )
170
+ range_to_keep = half_range + reduced_range
171
+
172
+ ratio = (full_range - range_to_keep )/ full_range
173
+
174
+
175
+ if below < above : # reducing colormap on side below pivot
176
+ # start colormap partway through
177
+ shortcmap = cmapin (np .linspace (0 ,1 ,N ))[int (np .ceil (N * ratio )):]
178
+
179
+ elif above < below : # reducing colormap on side above pivot
180
+ # end colormap early
181
+ shortcmap = cmapin (np .linspace (0 ,1 ,N ))[:- int (np .ceil (N * ratio ))]
182
+
183
+ elif (below == above ) and (dmax is not None ): # equal
184
+ ratio = dmax / full_range
185
+ shortcmap = cmapin (np .linspace (0 ,1 ,N ))[int (np .ceil (N * ratio )):- int (np .ceil (N * ratio ))]
186
+
187
+ # interpolate to original number of rows in colormap
188
+ newrgb = np .zeros ((N , 4 ))
189
+ shnum = shortcmap .shape [0 ]
190
+ for i in range (4 ): # loop through each column of cmap
191
+ newrgb [:,i ] = np .interp (np .linspace (0 ,shnum ,N ), np .arange (0 ,shnum ), shortcmap [:,i ])
192
+
193
+ newcmap = cmap (newrgb )
194
+
195
+ return newcmap
196
+
197
+
198
+ def crop_by_percent (cmap , per , which = 'both' , N = None ):
199
+ '''Crop end or ends of a colormap by per percent.
200
+
201
+ :param cmap: A colormap object, like cmocean.cm.matter.
202
+ :param per: Percent of colormap to remove. If which=='both', take this
203
+ percent off both ends of colormap. If which=='min' or which=='max',
204
+ take percent only off the specified end of colormap.
205
+ :param which='both': which end or ends of colormap to cut off. which='both'
206
+ removes from both ends, which='min' from bottom end, and which='max'
207
+ from top end.
208
+ :param N=None: User can specify the number of rows for the outgoing colormap.
209
+ If unspecified, N from incoming colormap will be used and values will
210
+ be interpolated as needed to fill in rows.
211
+
212
+ Outputs resultant colormap object.
213
+
214
+ This is a wrapper around crop() to make it easier to use for cropping
215
+ based on percent.
216
+
217
+ Examples:
218
+ # example with oxy map: cut off yellow part which is top 20%
219
+ # compare with full colormap
220
+ vmin = 0; vmax = 10; pivot = 5
221
+ A = np.random.randint(vmin, vmax, (5,5))
222
+ fig, axes = plt.subplots(1, 2)
223
+ mappable = axes[0].pcolormesh(A, vmin=vmin, vmax=vmax, cmap=cmocean.cm.oxy)
224
+ fig.colorbar(mappable, ax=axes[0])
225
+ vmin = 0; vmax = 8; pivot = 5
226
+ newcmap = crop_by_percent(cmocean.cm.oxy, 20, which='max', N=None)
227
+ plt.figure()
228
+ plt.pcolormesh(A, vmin=vmin, vmax=vmax, cmap=newcmap)
229
+ plt.colorbar()
230
+
231
+ # example with oxy map: cut off red part which is bottom 20%
232
+ # compare with full colormap
233
+ vmin = 0; vmax = 10; pivot = 5
234
+ A = np.random.randint(vmin, vmax, (5,5))
235
+ fig, axes = plt.subplots(1, 2)
236
+ mappable = axes[0].pcolormesh(A, vmin=vmin, vmax=vmax, cmap=cmocean.cm.oxy)
237
+ fig.colorbar(mappable, ax=axes[0])
238
+ vmin = 2; vmax = 10; pivot = 5
239
+ A = np.random.randint(vmin, vmax, (5,5))
240
+ newcmap = crop_by_percent(cmocean.cm.oxy, 20, which='min', N=None)
241
+ plt.figure()
242
+ plt.pcolormesh(A, vmin=vmin, vmax=vmax, cmap=newcmap)
243
+ plt.colorbar()
244
+
245
+ # crop both dark ends off colormap to reduce range
246
+ newcmap = crop_by_percent(cmocean.cm.balance, 10, which='both', N=None)
247
+ plt.figure()
248
+ A = np.random.randint(-5, 5, (5,5))
249
+ plt.pcolormesh(A, vmin=vmin, vmax=vmax, cmap=newcmap)
250
+ plt.colorbar()
251
+
252
+ '''
253
+
254
+ if which == 'both' : # take percent off both ends of cmap
255
+ vmin = - 100 ; vmax = 100 ; pivot = 0
256
+ dmax = per
257
+
258
+ elif which == 'min' : # take percent off bottom of cmap
259
+ vmax = 10 ; pivot = 5
260
+ vmin = (0 + per / 100 )* 2 * pivot
261
+ dmax = None
262
+
263
+ elif which == 'max' : # take percent off top of cmap
264
+ vmin = 0 ; pivot = 5
265
+ vmax = (1 - per / 100 )* 2 * pivot
266
+ dmax = None
267
+
268
+ newcmap = crop (cmap , vmin , vmax , pivot , dmax = dmax , N = N )
269
+
270
+ return newcmap
0 commit comments