Skip to content

Commit 0e28e2e

Browse files
committed
added tools to cropcolormap
1 parent a01e740 commit 0e28e2e

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed

cmocean/tools.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,164 @@ def lighten(cmapin, alpha):
107107

108108
# set the alpha value while retaining the number of rows in original cmap
109109
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

Comments
 (0)