colorbar does not apply vmin and vmax - python

I have the following strange behavior: When I limit the range of the figure, the colorplot shows it nevertheless:
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.linspace(0,1,100)
X,Y = np.meshgrid(x,x,indexing="ij")
im = ax.contourf(X,Y,X**2-Y**2, 100, vmin = 0, vmax = 0.5)
plt.colorbar(im, ax=ax)
plt.show()
how can I configure the limits of the colorbar correctly?

The 100 within the ax.contourf() means that you want 100 levels within the contour. You do have values that go over 0.5 within the plot itself.
You can customize the range of the color bar ticks as such.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
cbarticks = np.arange(0.0,0.55,0.05)
x = np.linspace(0,1,100)
X,Y = np.meshgrid(x,x,indexing="ij")
im = ax.contourf(X,Y,X**2-Y**2, cbarticks, vmin = 0, vmax = 0.5)
plt.colorbar(im, ax=ax,ticks=cbarticks)
plt.show()
which will give you
Unsure if this is exactly what you want but I had a similar question and answered it myself here: Colorbar Question

Related

Colorbar and its range shared between two plots

I adapted this code (https://stackoverflow.com/a/73099652/2369957) that demonstrates how to share a colorbar and its range for two plots, but it doesn't seem to work when the range of the two plots are different - in the case of the posted code, the plots have the same range (half-open interval [0.0, 1.0)). I generated two plots with different ranges and the colorbar only follows the last plot. Is the code posted wrong for a general case? How do I make the colorbar have the range of the two plots?
Adapted code:
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
fig, ax = plt.subplots(figsize=(12,9))
ax1 = plt.subplot(211)
im = ax1.imshow(np.random.uniform(low=0.00001, high=5, size=(100,100)))
ax2 = plt.subplot(212)
im = ax2.imshow(np.random.uniform(low=0.3, high=0.6, size=(100,100)))
plt.colorbar(im, ax=[ax1, ax2], aspect = 40)
plt.show()
Thank you very much in advance.
I generated two plots with different ranges and the colorbar only
follows the last plot.
This is because im is overwritten when running im = ax2.imshow(np.random.uniform(low=0.3, high=0.6, size=(100,100))).
To have both images share the same colorbar, you need to combine both arrays and use the min and max values of the combined array in imshow as detailed in this SO answer:
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
array_1 = np.random.uniform(low=0.00001, high=5, size=(100,100))
array_2 = np.random.uniform(low=0.3, high=0.6, size=(100,100))
combined_array = np.array([array_1,array_2])
_min, _max = np.amin(combined_array), np.amax(combined_array)
fig, ax = plt.subplots(figsize=(12,9))
ax1 = plt.subplot(211)
im = ax1.imshow(array_1, vmin = _min, vmax = _max)
ax2 = plt.subplot(212)
im = ax2.imshow(array_2, vmin = _min, vmax = _max)
norm = mpl.colors.Normalize(vmin=0.00001, vmax=5)
fig.colorbar(mpl.cm.ScalarMappable(norm=norm, ),
ax=[ax1, ax2], aspect = 40)
plt.show()
This returns the following image:

Centering Custom y-ticks Imshow

I'm trying to center yaxis tick marks on an imshow image similar to the one here. In the image, each row is a separate "profile" that I've stacked together. I want the tick location to be at the center of each horizontal section, like this (made in Powerpoint).
Here's some working code to make the images above:
import numpy as np
import matplotlib.pyplot as plt
td = [0,1,2,5,10,15,25,66]
N = len(td)
profiles = np.random.randn(N, 501).cumsum(axis=1)
fig, ax = plt.subplots(1,1)
ax.imshow(profiles, interpolation='none', aspect='auto', extent=[0, 500, N-1, 0])
ax.set_yticks(range(N))
plt.show()
Is there an easy way to do this? Let me know how I can clarify my question. If possible, I'd like to learn how to do this with matplotlib.axes (i.e., fig, ax = plt.subplots(1,1)...). Thanks!
You can manually set y ticks and tick labels at 0.5, 1.5 etc. (matplotlib 3.5.0 or above to do this in one call to set_ylabel):
import numpy as np
import matplotlib.pyplot as plt
td = [0,1,2,5,10,15,25,66]
N = len(td)
profiles = np.random.randn(N, 501).cumsum(axis=1)
fig, ax = plt.subplots()
ax.imshow(profiles, interpolation='none', aspect='auto', extent=[0, 500, N, 0])
ax.set_yticks(np.arange(N) + 0.5, [f'{y}' for y in td])

Matplotlib: Add colorbar to non-mappable object

I have a series of lines representing the change of a variable; each with a unique color. For that reason I want to add a colorbar next to the plot. The desired output is shown below.
The problem is that plot is a non-mappable object, i.e. the colorbar has to be added manually. I consider my current solution (below) sub-optimal as it involves size parameters of which I have no interest in controlling. I'd prefer a similar solution as for a mappable object (example below current solution).
Desired output
Current solution
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
x = np.linspace(0, 5, 100)
N = 20
cmap = plt.get_cmap('jet',N)
fig = plt.figure(figsize=(8,6))
ax1 = fig.add_axes([0.10,0.10,0.70,0.85])
for i,n in enumerate(np.linspace(0,2,N)):
y = np.sin(x)*x**n
ax1.plot(x,y,c=cmap(i))
plt.xlabel('x')
plt.ylabel('y')
ax2 = fig.add_axes([0.85,0.10,0.05,0.85])
norm = mpl.colors.Normalize(vmin=0,vmax=2)
cb1 = mpl.colorbar.ColorbarBase(ax2,cmap=cmap,norm=norm,orientation='vertical')
plt.show()
Desired solution
(obviously replacing imshow)
fig,ax = plt.subplots()
cax = ax.imshow(..)
cbar = fig.colorbar(cax,aspect=10)
plt.show()
You may define your own ScalarMappable and use it just as if it was present in the plot.
(Note that I changed the numbero f colors to 21 to have nice spacings of 0.1)
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
x = np.linspace(0, 5, 100)
N = 21
cmap = plt.get_cmap('jet',N)
fig = plt.figure(figsize=(8,6))
ax1 = fig.add_axes([0.10,0.10,0.70,0.85])
for i,n in enumerate(np.linspace(0,2,N)):
y = np.sin(x)*x**n
ax1.plot(x,y,c=cmap(i))
plt.xlabel('x')
plt.ylabel('y')
norm = mpl.colors.Normalize(vmin=0,vmax=2)
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
plt.colorbar(sm, ticks=np.linspace(0,2,N),
boundaries=np.arange(-0.05,2.1,.1))
plt.show()

matshow in python with extents that make ticks in the middle of squares

The following code generates a matrix plot that every square of it indexed in the middle with a number from 1 to 39:
import numpy as np
from matplotlib import pyplot as plt
a=np.random.uniform(0,1,1600).reshape((40,40))
fig, ax = plt.subplots(1,1)
ax.matshow(a, vmin = 0, vmax = 1, interpolation = 'none')
label_list=np.arange(0,40,5)
label_list=np.append(label_list,39)
ax.set_xticks(label_list)
ax.set_yticks(label_list)
plt.show()
When I want to change the numbers to be between 0 and 1.95 or basically [0,39]*0.05 the labels shrink to the beginning of axes. If I try to use extent in matshow then the labels don't point to the middle of squares! How can I make this float indices to point to the middle of squares?
import numpy as np
from matplotlib import pyplot as plt
a=np.random.uniform(0,1,1600).reshape((40,40))
fig, ax = plt.subplots(1,1)
ax.matshow(a, vmin = 0, vmax = 1, interpolation = 'none')
tick_list = np.append(np.arange(0,40,5), 39)
label_list=map(lambda x: str(0.05*x), tick_list)
ax.set_xticks(tick_list)
ax.set_xticklabels(label_list)
ax.set_yticks(tick_list)
ax.set_yticklabels(label_list)
plt.show()

How to create matplotlib colormap that treats one value specially? [duplicate]

This question already has an answer here:
How to redefine a color for a specific value in a matplotlib colormap
(1 answer)
Closed 8 years ago.
How can I create a matplotlib colormap that maps 0 (and only 0) to white, and any other value 0 < v <= 1 to a smooth gradient such as rainbow?
It seems neither LinearSegmentedColormap nor ListedColormap can do this.
There are a few ways of doing it. From your description of your values range, you just want to use cmap.set_under('white') and then set the vmin to 0 + eps.
For example:
import matplotlib.pyplot as plt
import numpy as np
cmap = plt.get_cmap('rainbow')
cmap.set_under('white') # Color for values less than vmin
data = np.random.random((10, 10))
data[3:5, 7:] = 0
# Very small float such that 0.0 != 0 + eps
eps = np.spacing(0.0)
fig, ax = plt.subplots()
im = ax.imshow(data, interpolation='nearest', vmin=eps, cmap=cmap)
fig.colorbar(im, extend='min')
plt.show()
However, if 0 was in the middle of your data range, you could mask the values and set the color with cmap.set_bad (I'll use black as the color to distinguish from the default for masked portions.):
import matplotlib.pyplot as plt
import numpy as np
cmap = plt.get_cmap('rainbow')
cmap.set_bad('black')
data = np.random.normal(0, 1, (10, 10))
data[3:5, 7:] = 0
data = np.ma.masked_equal(data, 0)
fig, ax = plt.subplots()
im = ax.imshow(data, interpolation='nearest', cmap=cmap)
fig.colorbar(im)
plt.show()

Categories

Resources