Inconsistent results using matplotlib - python

What I would like to achieve is having a plot like
So, if the green line should have the line color of value 19, it should be the same color as between 19 and 20 on the right hand side. I also know exactly the range where I will have values (here from 17 to 25).
The approach below sometimes work, but strangely it does only work about each second time. When I execute it again, suddenly I get a completely blue line (rgb 0 0 255). Is there something wrong with my approach?
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
cmap = plt.get_cmap('cubehelix')
minval = 17
maxval = 25
bounds = np.arange(minval, maxval+1)
mynorm = matplotlib.colors.Normalize(vmin = minval, vmax = maxval)
sm = matplotlib.cm.ScalarMappable(norm=mynorm, cmap=cmap)
color = sm.to_rgba(20)
ax.plot([0, 100], [0, 100], c=color, lw=2)
ax2 = fig.add_axes([0.90, 0.1, 0.03, 0.8])
cb = matplotlib.colorbar.ColorbarBase(ax2, cmap=cmap, norm=mynorm, spacing='proportional', ticks=bounds, boundaries=bounds, format='%1i')
plt.show()
I'm using Python 3.5.0 with matplotlib 1.4.3.

I have found that the c parameter can sometimes produce non-intuitive results. However, simply using the color parameter tends to be much more consistent.
Does this code fix your issue?
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
cmap = plt.get_cmap('cubehelix')
minval = 17
maxval = 25
bounds = np.arange(minval, maxval+1)
mynorm = matplotlib.colors.Normalize(vmin = minval, vmax = maxval)
sm = matplotlib.cm.ScalarMappable(norm=mynorm, cmap=cmap)
color = sm.to_rgba(20)
ax.plot([0, 100], [0, 100], color=color, lw=2) # Using 'color' instead of 'c'
ax2 = fig.add_axes([0.90, 0.1, 0.03, 0.8])
cb = matplotlib.colorbar.ColorbarBase(
ax2, cmap=cmap, norm=mynorm, spacing='proportional',
ticks=bounds, boundaries=bounds, format='%1i')
plt.show()
This issue is referenced here, https://github.com/matplotlib/matplotlib/issues/5197 it will be fixed in 1.5.0

Your code looks fine. I ran it on Python 2.7.10 |Anaconda 2.3.0 (x86_64)|OS X 10.10.5 without getting your reported error.

Related

Python matplotlib logarithmic colorbar in tricontourf

I am currently trying to visualize some data.
I have a set of X,Y and coresponding data values.
Due to some singularities, I am hoping to use some logarithmic plotting of my data.
def plot_field(idx, data):
# make sure there are no 0 values or negative values inside my data
data = np.clip(data, np.max(data) / 1000000, np.max(data))
plot = ax[idx].tricontourf(x_coords,y_coords,data, 10, locator=matplotlib.ticker.LogLocator(), cmap='plasma')
ax[idx].set_aspect(1)
divider = make_axes_locatable(ax[idx])
cax = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(plot,cax=cax)
For some reason, this leads to the same color for all values between 1-10, 10-100, 100-1000.
I wish to have more steps.
Does somebody here know, what a solution could be?
I also tried using the norm argument, which does not work either:
plot = ax[idx].tricontourf(x_coords,y_coords,data, 10, norm=matplotlib.colors.LogNorm(), cmap='plasma')
Entire code to reproduce
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from mpl_toolkits.axes_grid1 import make_axes_locatable
import math
x_coords = np.random.rand((1000))
y_coords = np.random.rand((1000))
values = np.random.rand((1000))*1000
aspect_ratio = (max(x_coords) - min(x_coords)) / (max(y_coords) - min(y_coords))
plots_x = 1 if aspect_ratio > 1.5 else 2
plots_y = 2 if aspect_ratio > 1.5 else 1
fig, ax = plt.subplots(plots_y, plots_x)
def plot_field(idx, data, min=1, max=1, log_norm=False):
# make sure there are no 0 values or negative values inside my data
if log_norm:
data = np.clip(data, np.max(data) / 1000000, np.max(data))
if not log_norm:
plot = ax[idx].tricontourf(x_coords,y_coords,data, 10, cmap='plasma')
else:
plot = ax[idx].tricontourf(x_coords,y_coords,data, 10, norm=matplotlib.colors.LogNorm(), cmap='plasma')
# ax[idx].scatter(x_coords,y_coords, c='red', s=1)
ax[idx].set_aspect(1)
divider = make_axes_locatable(ax[idx])
cax = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(plot,cax=cax)
plot_field(0,values, log_norm=True)
plt.tight_layout()
plt.show()

Define aspect ratio when using twinx in new version of matplotlib

Current version of matplotlib do not allow box-forced anymore, how should I do the same thing as the answer?
I am using matplotlib 3.1.0. After I ploted another set of data on the same plot with twinx() function, I want to change the aspect ratio of the actual plot area to 1.
Normally I do this and it works for non-twinx axis
ratio = 1
xleft, xright = ax.get_xlim()
ybottom, ytop = ax.get_ylim()
ax.set_aspect(abs((xright - xleft) / (ybottom - ytop)) * ratio)
For twinx axis, the above code do not work, but will not raise any error either.
Then I found an answer here
The code basically used the same method to set aspect ratio to 1, only with box-forced option.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 1.6, 50) + 50.0
fig, ax = plt.subplots()
ax2 = ax.twinx()
XLIM = [50.0, 51.6]
YLIM = [0.0, 1.1, 0.0, 11.0]
ax.plot(x, np.sin(x - 50.0), 'b')
ax2.plot(x, np.cos(x - 50.0) * 10., 'r')
# set aspect to 1
ax.set(adjustable='box-forced',
xlim=XLIM, ylim=YLIM[:2],
xticks=np.arange(XLIM[0], XLIM[1], 0.2),
yticks=np.arange(YLIM[0], YLIM[1] + 0.1, 0.1)[:-1],
aspect=(XLIM[1] - XLIM[0]) / (YLIM[1] - YLIM[0]))
ax2.set(adjustable='box-forced',
ylim=YLIM[2:],
yticks=np.arange(YLIM[2], YLIM[3] + 1.0, 1.0),
aspect=(XLIM[1] - XLIM[0]) / (YLIM[3] - YLIM[2]))
ax.grid(True, which='major', linestyle='solid')
plt.show()
This code in my python don't work, raises
ValueError: 'box-forced' is not a valid value for adjustable; supported values are 'box', 'datalim'
And if I change that to 'box', it gives
RuntimeError: Adjustable 'box' is not allowed in a twinned Axes. Use 'datalim' instead.
I am not sure from when the box-forced was removed.
Now how should we set the aspect ratio in a 'box' manner?
Thanks!
For reference: matplotlib.axes.Axes.set_adjustable
As I just commented on a respective matplotlib issue,
"aspect" in matplotlib always refers to the data, not the axes box. Therefore setting the aspect for twinned or shared axes and letting the box be adjustable actually only makes sense when the scales are the same - or differ by an offset (as opposed to any other linear or nonlinear function). Matplotlib does not perform any check on this, so it disallows for adjustable='box' in such case.
It seems to me that using aspect here is merely a workaround for getting a fixed ratio for the axes box. Matplotlib does not provide any clear codepath for that as of now, but one could e.g. force the axes box into a square space by adjusting the subplot parameters
import numpy as np
import matplotlib.pyplot as plt
def squarify(fig):
w, h = fig.get_size_inches()
if w > h:
t = fig.subplotpars.top
b = fig.subplotpars.bottom
axs = h*(t-b)
l = (1.-axs/w)/2
fig.subplots_adjust(left=l, right=1-l)
else:
t = fig.subplotpars.right
b = fig.subplotpars.left
axs = w*(t-b)
l = (1.-axs/h)/2
fig.subplots_adjust(bottom=l, top=1-l)
x = np.linspace(0,1.6,50) + 50.0
fig, ax = plt.subplots()
ax2 = ax.twinx()
ax.set(xlim = [50.0, 51.6], ylim = [0.0, 1.1])
ax2.set(ylim = [0.0, 11.0])
ax.plot(x,np.sin(x-50.0),'b')
ax2.plot(x,np.cos(x-50.0)*10.,'r')
ax.grid(True, which='major',linestyle='solid')
squarify(fig)
fig.canvas.mpl_connect("resize_event", lambda evt: squarify(fig))
plt.show()
Also see this answer for more than one subplot.
If you want to use mpl_toolkits and make your hands dirty, this answer would be a good read.
Thanks to #ImportanceOfBeingErnest, but to make this work in several subplots, I found another way inspired by your answer:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import Divider, Size
from mpl_toolkits.axes_grid1.axes_divider import AxesDivider
def make_patch_spines_invisible(ax):
ax.set_frame_on(True)
ax.patch.set_visible(False)
for sp in ax.spines.values():
sp.set_visible(False)
def demo_fixed_size_axes():
fig, axs = plt.subplots(1, 2, figsize=(12, 9))
axs[0].plot([1, 2, 3])
axs[1].plot([1, 2, 3.5])
ax3 = axs[1].twinx()
ax3.plot([1, 2, 3], [1, 25, 30])
axs[1].spines['right'].set_visible(False)
make_patch_spines_invisible(ax4Alt)
ax4Alt.spines['right'].set_visible(True)
for ax in fig.get_axes():
figPos = AxesDivider(ax).get_position()
h = [Size.Fixed(4)] # has to be fixed
v = h
divider = Divider(fig, figPos, h, v, aspect=False)
ax.set_axes_locator(divider.new_locator(nx=0, ny=0))
if __name__ == "__main__":
demo_fixed_size_axes()
plt.show()
The disadvantage is that one has to decide which size to use in inches.
I do not fully understand my code though...

Matplotlib colormap, scatter plot passing a third variable for color: invalid RGBA argument

we are building our reports on matplotlib. Each page has multiple charts and some text.
In the report data there is over 100 locations, each location has a density. The idea is to plot the points on a map where the color (shade of red) represents the density of the location.
However, I do not understand the connection between the kwargs : c and cmap in the ax.scatter call, nor do I understand the role of color.Normalize in this application.
import pandas as pd
import matplotlib
import numpy as np
from pandas import Series, DataFrame
import csv
from scipy import stats
import matplotlib.pyplot as plt
import random
import matplotlib.colors as colors
# Get the data and transform
data = pd.read_csv('logHistThis.csv')
data.drop('Unnamed: 0', axis=1, inplace=True)
dataMean = data['Density'].mean()
data = list(data['Density'])
# I was under the impresion that the data for the colormap
# had to be between 1 and 0 so did this:
aColorScale = []
def myColorScale(theData):
aColorScale = []
for x in theData:
this = x/100
aColorScale.append(this)
return aColorScale
aColorScale = myColorScale(data)
estimated_mu, estimated_sigma = stats.norm.fit(data)
xmin = min(data)
xmax = max(data)
x = np.linspace(xmin, xmax, 100)
pdf = stats.norm.pdf(x, loc=estimated_mu, scale=estimated_sigma)
thisRangeMin = np.log(27)
thisRangeMax = np.log(35)
q = [np.random.choice(data, 40)]
z = [ np.random.randint(1, 50, size=40)]
s = 100 *q
colormap = 'Reds'
normalize =matplotlib.colors.Normalize(vmin=xmin, vmax=xmax)
#plt.scatter(x,y,z,s=5, cmap=colormap, norm=normalize, marker='*')
fig = plt.figure(figsize=(10, 5), frameon=False, edgecolor='000000', linewidth = 1)
rect0 = .05, .05, .4, .9
rect1 = .5, .05, .4, .9
# This works great
ax1 = fig.add_axes(rect0)#<-----------x2TopTenSummary
ax1.hist(data, bins=13, normed=True, color='c', alpha=0.05)
#ax1.fill_between(x, pdf, where=(), alpha=.2)
ax1.fill_between(x, pdf, where=((x < thisRangeMax) & ( x > thisRangeMin)), alpha=.2, label='City Range')
ax1.vlines(dataMean, 0, stats.norm.pdf(dataMean, loc=estimated_mu, scale=estimated_sigma), color='r')
ax1.plot(x, pdf, 'k')
# This does not work :
# It just gives blue dots
ax2= fig.add_axes(rect1)
ax2= fig.add_axes(rect1)
ax2.scatter(q,z, s=200, cmap= 'Reds',norm=matplotlib.colors.Normalize(vmin=min(aColorScale) , vmax=max(aColorScale)))
# Tried to set the color map in a variety of ways:
# When kwarg 'c' is set to the variable 'aColorScale' i get the error
plt.show()
plt.close()
So my question is how do we incorporate the colormap in an application of this sort?
Multiple axes on a figure with a predetermined size (A4 or letter).
The color determination is a third variable z, (not x or y)
The color determinant is a float where 0 < z < 8
the call is ax not plt
The description of the application in the docs is unclear to me:
the doc for axes.scatter
the doc for color.normalize
I have seen plenty of examples where there is only one ax in the figure and the call is to plt.scatter... for example here
In our case x, y will be longitude, lattitude and the variable is 'data' a list or array of floats between 0 and 8.
Thanks
Okay the answer came from the PyCon Israel 2017 in this document by Tamir Lousky.
The normalization of the data and the correlation with color map happens with this block of code right here:
aColorScale = data
aColorScale = np.array(aColorScale)
norm = (aColorScale - aColorScale.min())/(aColorScale.max() - aColorScale.min())
cmap= plt.get_cmap('Reds')
colors = [cmap(tl) for tl in norm]#<---- thisRightHere
Then colors gets fed into ax2:
ax2= fig.add_axes(rect1)
ax2.scatter(q,z, s=200, color = colors)
I wish those who downvoted my question would say why, there was hours of searching and trying to find this.
Anyway here is the final image:
While I do have problems understanding the issue itself, I can tell you that the solution you have in your answer can be simplified to the usual way to plot scatters:
ax2= fig.add_axes(rect1)
ax2.scatter(q,z, c=aColorScale, s=200, cmap='Reds')

Changing point color on matplolib and basemap not working

I am having some issue with getting my data onto a map with Basemap and having those points change in color. I have read many different things online about how to do this, but I still get a map with no points. Here is my code:
import pandas as pd
import numpy as np
import pickle
from IPython.display import SVG, display_svg
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.colors as co
d3data = pickle.load( open( "9_28_2015to10_04_2015.pickle", "rb" ) )
lons = d3data['longitude'].tolist()
lats = d3data['latitude'].tolist()
normcts = co.Normalize(d3data['GrossCounts'])
plt.figure(figsize=(20,10))
m = Basemap(projection='cass', lat_0 = 40.108004, lon_0 = -88.228878,
resolution = 'h', area_thresh = 0.1,
llcrnrlon=-88.238399, llcrnrlat=40.097942,
urcrnrlon=-88.219345, urcrnrlat=40.116158)
m.drawcountries()
m.fillcontinents(color='white')
m.drawmapboundary()
m.readshapefile('mhj_shapes/lines', 'lines')
cmap = plt.cm.RdYlBu_r
norm = co.Normalize(vmin=d3data['GrossCounts'].min(),
vmax=d3data['GrossCounts'].max())
pointcolors = plt.cm.ScalarMappable(norm, cmap)
for i in range(0, len(d3data)):
col = pointcolors.to_rgba(d3data['GrossCounts'][i])
x,y = m(d3data['longitude'][i],d3data['latitude'][i])
m.scatter(x, y, marker = 'o', s=10, color=col, cmap=cmap)
plt.show()
My problem is that my shape file generates a map just fine, but I don't get any points on top of it. I want to plot the dataframe columns d3data['GrossCounts'] on top of the map and have the color scale with the (integer) value of d3data['GrossCounts'].
Any suggestions would be greatly appreciated!
It is hard to test without your data/shape file etc, but the problem could be your for loop. Maybe try without the loop:
col = pointcolors.to_rgba(d3data['GrossCounts'])
x, y = m(d3data['longitude'], d3data['latitude'])
m.scatter(x, y, marker='o', s=10, color=col, cmap=cmap)
i.e. if I do:
plt.figure(figsize=(8,5))
m = Basemap(projection='cass', lat_0 = 0, lon_0 = 0,
resolution = 'l', area_thresh = 0.1,
llcrnrlon=-10, llcrnrlat=-10,
urcrnrlon=10, urcrnrlat=10)
m.drawcountries()
m.fillcontinents(color='white')
m.drawmapboundary()
#m.readshapefile('mhj_shapes/lines', 'lines')
cmap = plt.cm.RdYlBu_r
x, y = m([0, 5], [0, 5])
df = pd.DataFrame({'a': [1,2]})
norm = co.Normalize(vmin=df.a.min(), vmax=df.a.max())
pointcolors = plt.cm.ScalarMappable(norm, cmap)
col = pointcolors.to_rgba(df.a)
m.scatter(x, y, s=10, color=col)
plt.show()
I get:
Is that what you're after?
Problem solved!
It turns out that this is described in `map.scatter` on basemap not displaying markers (although I was not searching for the right terms when I googled in here). Here is the change that finally worked:
m.drawcountries()
m.fillcontinents(color='white', zorder=0) # <--zorder!!!
m.drawmapboundary()
m.readshapefile('mhj_shapes/lines', 'lines')
cmap = plt.cm.jet
x, y = m(lons, lats)
norm = co.Normalize(vmin=d3data.GrossCounts.min(), vmax=250)
pointcolors = plt.cm.ScalarMappable(norm, cmap)
col = pointcolors.to_rgba(d3data.GrossCounts)
m.scatter(x, y, s=10, c=col, cmap=plt.cm.jet)
I don't know why I never saw zorder in any of the online examples that I had found, but adding this makes sure that the map itself is sent to the back so the points are brought to the front. Thank you, all for your help!

Scatter plot on top of white background, change colorbar range [duplicate]

I would like to use a colormap from matplotlib e.g. CMRmap. But I don't want to use the "black" color at the beginning and the "white" color at the end. I'm interested to plot my data using the in-between colors. I think ppl use it quite often but I was searching over internet and could not manage to find any simple solution. I'll appreciate if someone suggest any solution.
The staticmethod colors.LinearSegmentedColormap.from_list can be used to create new LinearSegmentedColormaps. Below, I sample the original colormap at 100 points between 0.2 and 0.8:
cmap(np.linspace(0.2, 0.8, 100))
and use these colors to generate a new colormap:
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100):
new_cmap = colors.LinearSegmentedColormap.from_list(
'trunc({n},{a:.2f},{b:.2f})'.format(n=cmap.name, a=minval, b=maxval),
cmap(np.linspace(minval, maxval, n)))
return new_cmap
arr = np.linspace(0, 50, 100).reshape((10, 10))
fig, ax = plt.subplots(ncols=2)
cmap = plt.get_cmap('jet')
new_cmap = truncate_colormap(cmap, 0.2, 0.8)
ax[0].imshow(arr, interpolation='nearest', cmap=cmap)
ax[1].imshow(arr, interpolation='nearest', cmap=new_cmap)
plt.show()
The plot on the left shows the image using the original colormap (in this example, jet). The plot on the right shows the same image using new_cmap.
In my CMasher package, I provide the get_sub_cmap()-function (https://cmasher.readthedocs.io/user/usage.html#sub-colormaps), which takes a colormap and a range, and returns a new colormap containing the requested range.
So, for example, if you want to take the colors between 20% and 80% of the viridis colormap, you can do that with:
import cmasher as cmr
cmap = cmr.get_sub_cmap('viridis', 0.2, 0.8)
PS: Do not use jet (or CMRmap), as they are not perceptually uniform sequential.
Instead, use the 5 proper colormaps in matplotlib or the colormaps provided by cmocean or my CMasher.
EDIT: In the latest version of CMasher, one can also use this same function to create a discrete/qualitative colormap out of any colormap by supplying the function with the number of segments to take.
For example, if you want to create a qualitative colormap of viridis in the 20% to 80% range, you can do this with:
cmap = cmr.get_sub_map('viridis', 0.2, 0.8, N=5)
I was just recently struggling with this on my own. Here are some possible solutions:
Try using vmin, vmax keyword arguments in your plotting function. For example, say you had data between 0 and 1 but didn't like the colors used at the extremes of the colormap for 0 and 1.
import matplotlib.pyplot as plt
import matplotlib.cm as cm
my_cmap = cm.spectral_r
my_cmap.set_over('c')
my_cmap.set_under('m')
plt.pcolor(data, vmin=0.01, vmax=0.99, cmap=my_cmap)
This will force the entire colormap to be used for values between 0.01 and 0.99 and values above and below will be cyan and magenta respectively. This may not solve your problem exactly, but it could be useful if you like a particular colormap and wish it had additional colors at both ends.
If you really want to change the colormap, look at the documentation here and for LinearSegmentedColormap here.
First,
import matplotlib.cm as cm
cdict = cm.get_cmap('spectral_r')._segmentdata
This returns a dictionary of all the colors that make up the colormap. However, it's pretty tricky figuring out exactly how to alter this dictionary. This dict has three keys, red, green, blue. cdict[key] returns a list of values of the form (x, y0, y1). Let's take a look at two consecutive elements of cdict['red']:
((0.0, 0.0, 0.0)
(0.5, 1.0, 1.0),...
What this means is that data with z (assuming we're doing a pcolor or imshow) between 0.0 and 0.5 will have the red component of the rgb color associated with that data will increase from 0.0 (no red) to 1.0 (maximum red). This means that to change the color of the colormap, you have to examine how each of the three components of rgb are interpolated in the region of the colormap that you are interested in. Just make sure that for each color, the first and the last entry start with x=0 and x=1 respectively; you must cover the whole spectrum of [0, 1].
If you want to change the beginning and end colors, try
import matplotlib.cm as cm
from matplotlib.colors import LinearSegmentedColormap
cdict = cm.get_cmap('spectral_r')._segmentdata
cdict['red'][0] = (0, 0.5, 0.5) # x=0 for bottom color in colormap
cdict['blue'][0] = (0, 0.5, 0.5) # y=0.5 gray
cdict['green'][0] = (0, 0.5, 0.5) # y1=y for simple interpolation
cdict['red'][-1] = (1, 0.5, 0.5) # x=1 for top color in colormap
cdict['blue'][-1] = (1, 0.5, 0.5)
cdict['green'][-1] = (1, 0.5, 0.5)
my_cmap = LinearSegmentedColormap('name', cdict)
Then use this cmap in your plotting function.
What I wanted to do was change the gray at the end of the spectral_r colormap to pure white. This was achieved using
# Using imports from above
cdict = matplotlib.cm.get_cmap('spectral_r')._segmentdata
cdict['red'][0] = (0, 1, 1)
cdict['green'][0] = (0, 1, 1)
cdict['blue'][0] = (0, 1, 1)
my_cmap = LinearSegmentedColormap('my_cmap', cdict)
Here is an adaptation of a previous answer which embeds the plotting function:
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
################### Function to truncate color map ###################
def truncate_colormap(cmapIn='jet', minval=0.0, maxval=1.0, n=100):
'''truncate_colormap(cmapIn='jet', minval=0.0, maxval=1.0, n=100)'''
cmapIn = plt.get_cmap(cmapIn)
new_cmap = colors.LinearSegmentedColormap.from_list(
'trunc({n},{a:.2f},{b:.2f})'.format(n=cmapIn.name, a=minval, b=maxval),
cmapIn(np.linspace(minval, maxval, n)))
arr = np.linspace(0, 50, 100).reshape((10, 10))
fig, ax = plt.subplots(ncols=2)
ax[0].imshow(arr, interpolation='nearest', cmap=cmapIn)
ax[1].imshow(arr, interpolation='nearest', cmap=new_cmap)
plt.show()
return new_cmap
cmap_mod = truncate_colormap(minval=.2, maxval=.8) # calls function to truncate colormap
Having a compact function with the plotting embedded is helpful if you need to call the function more than once.
Slight improvement of visualization from a previous answer, (inspired by that answer)
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100):
'''
https://stackoverflow.com/a/18926541
'''
if isinstance(cmap, str):
cmap = plt.get_cmap(cmap)
new_cmap = mpl.colors.LinearSegmentedColormap.from_list(
'trunc({n},{a:.2f},{b:.2f})'.format(n=cmap.name, a=minval, b=maxval),
cmap(np.linspace(minval, maxval, n)))
return new_cmap
cmap_base = 'jet'
vmin, vmax = 0.2, 0.8
cmap = truncate_colormap(cmap_base, vmin, vmax)
fig, ax = plt.subplots(nrows=2)
sm = mpl.cm.ScalarMappable(cmap=cmap_base)
cbar = plt.colorbar(sm, cax=ax[0], orientation='horizontal')
sm = mpl.cm.ScalarMappable(cmap=cmap)
cbar = plt.colorbar(sm, cax=ax[1], orientation='horizontal')
plt.show()
Quick Wrapper Function:
def sub_cmap(cmap, vmin, vmax):
return lambda v: cmap(vmin + (vmax - vmin) * v)
Usage:
cmap = matplotlib.cm.get_cmap('viridis') # Get your favorite cmap
new_cmap = sub_cmap(cmap, 0.2, 0.9)
# Do plot or something
# ...
cmap = cmr.get_sub_map('viridis', 0.2, 0.8, N=5)
proposed by #1313e must be the most elegant solution. But the new function is cmr.get_sub_cmap(), just replace it.

Categories

Resources