{{ message }}

Instantly share code, notes, and snippets.

endolith/Manja Lehmann example.png

Last active Feb 3, 2021
Bipolar colormap translated from Matlab into Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 #!/usr/bin/env python """ Copyright 2012 endolith at gmail com Copyright 2009 Ged Ridgway at gmail com Translation and modification of http://www.mathworks.com/matlabcentral/fileexchange/26026-bipolar-colormap Based on Manja Lehmann's hand-crafted colormap for cortical visualisation """ from __future__ import division import scipy from matplotlib import cm def bipolar(lutsize=256, n=0.333, interp=[]): """ Bipolar hot/cold colormap, with neutral central color. This colormap is meant for visualizing diverging data; positive and negative deviations from a central value. It is similar to a blackbody colormap for positive values, but with a complementary "cold" colormap for negative values. Parameters ---------- lutsize : int The number of elements in the colormap lookup table. (Default is 256.) n : float The gray value for the neutral middle of the colormap. (Default is 1/3.) The colormap goes from cyan-blue-neutral-red-yellow if neutral is < 0.5, and from blue-cyan-neutral-yellow-red if neutral > 0.5. For shaded 3D surfaces, an `n` near 0.5 is better, because it minimizes luminance changes that would otherwise obscure shading cues for determining 3D structure. For 2D heat maps, an `n` near the 0 or 1 extremes is better, for maximizing luminance change and showing details of the data. interp : str or int, optional Specifies the type of interpolation. ('linear', 'nearest', 'zero', 'slinear', 'quadratic, 'cubic') or as an integer specifying the order of the spline interpolator to use. Default is 'linear'. See `scipy.interpolate.interp1d`. Returns ------- out : matplotlib.colors.LinearSegmentedColormap The resulting colormap object Notes ----- If neutral is exactly 0.5, then a map which yields a linear increase in intensity when converted to grayscale is produced. This colormap should also be reasonably good for colorblind viewers, as it avoids green and is predominantly based on the purple-yellow pairing which is easily discriminated by the two common types of colorblindness. [2]_ Examples -------- >>> from mpl_toolkits.mplot3d import Axes3D >>> from matplotlib import cm >>> import matplotlib.pyplot as plt >>> import numpy as np >>> fig = plt.figure() >>> ax = fig.gca(projection='3d') >>> x = y = np.arange(-4, 4, 0.15) >>> x, y = np.meshgrid(x, y) >>> z = (1- x/2 + x**5 + y**3)*exp(-x**2-y**2) >>> surf = ax.plot_surface(x, y, z, rstride=1, cstride=1, linewidth=0.1, >>> vmax=abs(z).max(), vmin=-abs(z).max()) >>> fig.colorbar(surf) >>> plt.show() >>> set_cmap(bipolar(201)) >>> waitforbuttonpress() >>> set_cmap(bipolar(201, 0.1)) # dark gray as neutral >>> waitforbuttonpress() >>> set_cmap(bipolar(201, 0.9)) # light gray as neutral >>> waitforbuttonpress() >>> set_cmap(bipolar(201, 0.5)) # grayscale-friendly colormap References ---------- .. [1] Lehmann Manja, Crutch SJ, Ridgway GR et al. "Cortical thickness and voxel-based morphometry in posterior cortical atrophy and typical Alzheimer's disease", Neurobiology of Aging, 2009, doi:10.1016/j.neurobiolaging.2009.08.017 .. [2] Brewer, Cynthia A., "Guidelines for Selecting Colors for Diverging Schemes on Maps", The Cartographic Journal, Volume 33, Number 2, December 1996, pp. 79-86(8) http://www.ingentaconnect.com/content/maney/caj/1996/00000033/00000002/art00002 """ if n < 0.5: if not interp: interp = 'linear' # seems to work well with dark neutral colors cyan-blue-dark-red-yellow _data = ( (0, 1, 1), # cyan (0, 0, 1), # blue (n, n, n), # dark neutral (1, 0, 0), # red (1, 1, 0), # yellow ) elif n >= 0.5: if not interp: interp = 'cubic' # seems to work better with bright neutral colors blue-cyan-light-yellow-red # produces bright yellow or cyan rings otherwise _data = ( (0, 0, 1), # blue (0, 1, 1), # cyan (n, n, n), # light neutral (1, 1, 0), # yellow (1, 0, 0), # red ) else: raise ValueError('n must be 0.0 < n < 1.0') xi = linspace(0, 1, size(_data, 0)) cm_interp = scipy.interpolate.interp1d(xi, _data, axis=0, kind=interp) xnew = linspace(0, 1, lutsize) ynew = cm_interp(xnew) # No form of interpolation works without this, but that means the interpolations are not working right. ynew = clip(ynew, 0, 1) return cm.colors.LinearSegmentedColormap.from_list('bipolar', ynew, lutsize) if __name__ == "__main__": from pylab import * def func3(x,y): return (1- x/2 + x**5 + y**3)*exp(-x**2-y**2) # make these smaller to increase the resolution dx, dy = 0.05, 0.05 x = arange(-3.0, 3.0001, dx) y = arange(-3.0, 3.0001, dy) X,Y = meshgrid(x, y) Z = func3(X, Y) pcolor(X, Y, Z, cmap=bipolar(n=1./3, interp='linear'), vmax=abs(Z).max(), vmin=-abs(Z).max()) colorbar() axis([-3,3,-3,3]) show()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 # -*- coding: utf-8 -*- """ Created on Thu Feb 28 14:28:50 2013 Translation of http://www.mathworks.com/matlabcentral/fileexchange/11037-lab-color-scale Based on https://code.google.com/p/python-colormath/ """ from __future__ import division from numpy import pi, linspace, cos, sin, vstack from colormath.color_objects import LabColor from matplotlib import cm def color_scale(n=256, theta=0, r=50, angle_offset=pi/2, dir='cw'): if dir == 'cw': angle_offset = -angle_offset else: angle_offset = angle_offset theta = pi * theta / 180 theta_vec = linspace(theta, theta + angle_offset, n) a = r * cos(theta_vec) b = r * sin(theta_vec) L = linspace(0, 100, n) rgbs = [] Lab = vstack([L, a, b]) for L, a, b in Lab.T: rgb = LabColor(L, a, b).convert_to('rgb') r = rgb.rgb_r/255.0 g = rgb.rgb_g/255.0 b = rgb.rgb_b/255.0 rgbs.append((r, g, b)) return cm.colors.LinearSegmentedColormap.from_list('color_scale', rgbs, n) if __name__ == "__main__": from pylab import * dx, dy = 0.01, 0.01 x = arange(-2.0, 2.0001, dx) y = arange(-2.0, 2.0001, dy) X,Y = meshgrid(x, y) Z = X * np.exp(-X**2 - Y**2) # Matplotlib's 2-bump example figure() imshow(Z, vmax=abs(Z).max(), vmin=-abs(Z).max(), cmap=color_scale(theta = 0, r = 50)) colorbar() show()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 # -*- coding: utf-8 -*- """ Created on Thu Feb 28 21:13:00 2013 """ import matplotlib as mpl from mpl_toolkits.mplot3d import Axes3D import numpy as np import matplotlib.pyplot as plt from color_scale import color_scale from bipolar import bipolar mpl.rcParams['legend.fontsize'] = 10 fig = plt.figure(1) ax = fig.gca(projection='3d') #colormap = color_scale(theta = 0, angle_offset=2*pi, r = 50) #colormap = bipolar(n=0) colormap = get_cmap('hsv') lutsize = 256 # Plain lines # colors = zeros((lutsize, 3)) # for i in xrange(0, lutsize): # colors[i] = colormap.__call__(i)[:3] # # r = colors[:,0] # g = colors[:,1] # b = colors[:,2] # # ax.plot(r, g, b, label=colormap.name) # Colored lines for i in xrange(0, lutsize-1): r1, g1, b1 = colormap.__call__(i )[:3] r2, g2, b2 = colormap.__call__(i+1)[:3] ax.plot([r1, r2], [g1, g2], [b1, b2], lw=3, color = (r1, g1, b1)) ax.legend() ax.set_xlim3d(0, 1) ax.set_ylim3d(0, 1) ax.set_zlim3d(0, 1) ax.set_xlabel("red") ax.set_ylabel("blue") ax.set_zlabel("green") plt.show()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 color_scale.m (Steve Eddins): Copyright (c) 2009, The MathWorks, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution * Neither the name of the The MathWorks, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. bipolar.m: Copyright (c) 2009, Ged Ridgway All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

endolith commented Jun 21, 2020

Why did I put the color_scale here though? That's a totally different thing...

endolith commented Jun 29, 2020

I cleaned up the git history and moved it here: https://github.com/endolith/bipolar-colormap

I'm planning to keep the "bipolar" map matching the existing ones, with the RGB cube angles and "halos", and rename the bezier curve version to "hotcold".