I wrote a code where I have an array called array2 with numbers between 0. and 1. in it. When I click on the array displayed by imshow the cells in the array take the value 2. and become red.
Then I added a colorbar but it kept shrinking once I clicked on it and the cells didn't become red.
What am I doing wrong ?
Code without colorbar (works fine)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib import cm
from mpl_toolkits.axes_grid1 import make_axes_locatable
from random import random
def test(n):
array1 = np.zeros((n,n))
for i in range(n):
for j in range(n):
array1[i,j] = random()
return array1
# Array
global array2
array2 = test(10)
# Colormap
greens = cm.Greens(np.linspace(0,1, num=50))
greensfill = cm.Greens(np.ones(25))
red = [(1,0,0,1)]*len(greens)
gray = [(.5,.5,.5,1)]*len(greens)
colors = np.vstack((greens, greensfill, red, gray))
mycmap = mcolors.LinearSegmentedColormap.from_list('my_colormap', colors)
# Matplotlib
fig, axes = plt.subplots(1)
fig.tight_layout()
plt.imshow(array2, animated=True, cmap = mycmap, interpolation="none", vmin=0, vmax=3.5, origin='lower')
def onclick(event):
global x, y
x, y = int(event.xdata), int(event.ydata)
array2[y,x] = 2.
plt.imshow(array2, animated=True, cmap = mycmap, interpolation="none", vmin=0, vmax=3.5, origin='lower')
fig.canvas.mpl_connect('button_press_event', onclick)
Code with colorbar (doesn't work)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib import cm
from mpl_toolkits.axes_grid1 import make_axes_locatable
from random import random
def test(n):
array1 = np.zeros((n,n))
for i in range(n):
for j in range(n):
array1[i,j] = random()
return array1
# Array
global array2
array2 = test(10)
# Colormap
greens = cm.Greens(np.linspace(0,1, num=50))
greensfill = cm.Greens(np.ones(25))
red = [(1,0,0,1)]*len(greens)
gray = [(.5,.5,.5,1)]*len(greens)
colors = np.vstack((greens, greensfill, red, gray))
mycmap = mcolors.LinearSegmentedColormap.from_list('my_colormap', colors)
# Matplotlib
fig, axes = plt.subplots(1)
fig.tight_layout()
im = plt.imshow(array2, animated=True, cmap = mycmap, interpolation="none", vmin=0, vmax=3.5, origin='lower')
divider = make_axes_locatable(axes)
cax = divider.append_axes("right", size="13%", pad=0.2)
cb = plt.colorbar(im, cax=cax, boundaries=np.linspace(0,1, num=100), ticks=[0,1])
cb.set_label("Title", fontsize=15, labelpad=-5, y=0.5)
def onclick(event):
global x, y
x, y = int(event.xdata), int(event.ydata)
array2[y,x] = 2.
im = plt.imshow(array2, animated=True, cmap = mycmap, interpolation="none", vmin=0, vmax=3.5, origin='lower')
divider = make_axes_locatable(axes)
cax = divider.append_axes("right", size="13%", pad=0.2)
cb = plt.colorbar(im, cax=cax, boundaries=np.linspace(0,1, num=100), ticks=[0,1])
cb.set_label("Title", fontsize=15, labelpad=-5, y=0.5)
fig.canvas.mpl_connect('button_press_event', onclick)
It would be better to just update the imshow, instead of drawing a new one every time a click is performed. This can be done using the .set_data() method. The advantage is that the colorbar can stay where it is and doesn't get touched.
In general it's best to work with the plotting objects directly instead of pyplot when doing interactive stuff. So using fig and ax instead of plt in most cases.
Note that to accurately catch the click on a pixel you need to round the coordinate first, int(np.round(event.xdata)).
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib import cm
from mpl_toolkits.axes_grid1 import make_axes_locatable
global array2
array2 = np.random.rand(10,10)
# Colormap
greens = cm.Greens(np.linspace(0,1, num=50))
greensfill = cm.Greens(np.ones(25))
red = [(1,0,0,1)]*len(greens)
gray = [(.5,.5,.5,1)]*len(greens)
colors = np.vstack((greens, greensfill, red, gray))
mycmap = mcolors.LinearSegmentedColormap.from_list('my_colormap', colors)
# Matplotlib
fig, ax = plt.subplots()
fig.tight_layout()
im = ax.imshow(array2, animated=True, cmap = mycmap, interpolation="none",
vmin=0, vmax=3.5, origin='lower')
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="13%", pad=0.2)
cb = fig.colorbar(im, ax =ax, cax=cax, boundaries=np.linspace(0,1, num=100),
ticks=[0,1])
cb.set_label("Title", fontsize=15, labelpad=-5, y=0.5)
def onclick(event):
x, y = int(np.round(event.xdata)), int(np.round(event.ydata))
array2[y,x] = 2.
im.set_data(array2)
fig.canvas.draw_idle()
fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
Related
I've made a colormap from a matrix (matrix300.txt). I would like to normalize my colormap, but I don't know how to do it. The axes should be from 0 to 3.
import numpy as np
import matplotlib.pyplot as plt
import math
from matplotlib import colors
import matplotlib.colors as colors
p = np.loadtxt('matrix300.txt')
cmap = colors.ListedColormap(['yellow', 'white'], name='Gamma=1')
bounds = [-1, 0, 1]
norm = colors.BoundaryNorm(bounds, cmap.N)
img = plt.imshow(p, interpolation='nearest', origin='lower', cmap=cmap, norm=norm)
plt.colorbar(img, cmap=cmap, norm=norm, boundaries=bounds)
plt.xlabel("h_0")
plt.ylabel("h")
plt.show()
Your usage of ListedColormap is not right here. It is for creating a user-defined colormap. So it may be a bit too much of elaborating if you need a colormap just for plotting. I post an example using ListedColormap anyway.
import numpy as np
import matplotlib.pyplot as plt
import math
from matplotlib import colors
import matplotlib.colors as colors
# dummy data
yy, xx = np.mgrid[0:1:10j, 0:1:10j]
p = np.exp(-10*(xx-0.5)**2-10*(yy-0.5)**2) # gaussian function
# create your own colormap
pmax, pmin = np.max(p), np.min(p) # get data range
bounds = np.linspace(pmin, pmax, 100) # set data range for colormap
num = 100 # how many colors do you need?
norm = colors.BoundaryNorm(bounds, ncolors=num) # an object for cmap normalization
carray = np.array([np.linspace(0,1,num), np.linspace(0.0,0.25,num), [0.5]*num, [1]*num]).T # list of RGBA values
cmap = colors.ListedColormap(carray, N=100, name='mycolormap') # create your own color map from carray
# plot data
img = plt.imshow(p, interpolation='nearest', origin='lower', cmap=cmap, norm=norm)
plt.colorbar(img, cmap=cmap, norm=norm, boundaries=bounds)
plt.show()
Mush easier way is to use pcolormesh.
fig, ax = plt.subplots(1,1)
ax.set_aspect("equal")
im = ax.pcolormesh(xx, yy, p, vmin=pmin, vmax=pmax)
cbar = fig.colorbar(mappable=im)
plt.show()
I would like to set a y-axis with pcolor, such as the y-axis would be depth. in this example, I would like to set the vector z as the y-axis, how can I do that?
this is my code:
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.colors import LogNorm
from matplotlib.ticker import LogLocator
z=np.arange(1,90,2)
mrectest = np.random.rand(45, 15)
fig, ax = plt.subplots(figsize=(20,20))
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.1)
im = ax.pcolor(mrectest,vmin = 0.1, vmax = 800, norm = LogNorm(),cmap= 'jet')
cbar = fig.colorbar(im,cax=cax, orientation='vertical')
cbar.ax.yaxis.set_major_locator(LogLocator()) # <- Why? See above.
#ax.invert_yaxis()
#cbar.set_ticks(cbar.ax.yaxis.get_major_locator().tick_values(0.01, 1000))
plt.savefig('mrec_exp_28_02'+'.png',bbox_inches = "tight", format='png', dpi=1000)
plt.show()
I would like to display a 2D np.array with imshow and the respective colorbar which should share its axis with a histogram of the np.array. Here is an attempt, however, without shared axes.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig, ax = plt.subplots(figsize=(7,10))
data = np.random.normal(0, 0.2, size=(100,100))
cax = ax.imshow(data, interpolation='nearest', cmap=cm.jet)
divider = make_axes_locatable(plt.gca())
axBar = divider.append_axes("bottom", '5%', pad='7%')
axHist = divider.append_axes("bottom", '30%', pad='7%')
cbar = plt.colorbar(cax, cax=axBar, orientation='horizontal')
axHist.hist(np.ndarray.flatten(data), bins=50)
plt.show()
I tried to use the sharex argument in axHist with axHist = divider.append_axes("bottom", '30%', pad='7%', sharex=axBar) but this somehow shifts the histogram data:
Besides the shared axis x, how could one modify the histogram to take the same colors as the colormap, similar to here?
You may color every patch of histogram by bin value without sharex:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.colors import Normalize
fig, ax = plt.subplots(figsize=(7,10))
data = np.random.normal(0, 0.2, size=(100,100))
cax = ax.imshow(data, interpolation='nearest', cmap=cm.jet)
divider = make_axes_locatable(plt.gca())
axBar = divider.append_axes("bottom", '5%', pad='7%')
axHist = divider.append_axes("bottom", '30%', pad='7%')
cbar = plt.colorbar(cax, cax=axBar, orientation='horizontal')
# get hist data
N, bins, patches = axHist.hist(np.ndarray.flatten(data), bins=50)
norm = Normalize(bins.min(), bins.max())
# set a color for every bar (patch) according
# to bin value from normalized min-max interval
for bin, patch in zip(bins, patches):
color = cm.jet(norm(bin))
patch.set_facecolor(color)
plt.show()
For more information look for manual page: https://matplotlib.org/xkcd/examples/pylab_examples/hist_colormapped.html
I use matplotlib.pyplot.pcolor() to plot a heatmap with matplotlib:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1)
data = np.sort(np.random.rand(8,12))
plt.figure()
c = plt.pcolor(data, edgecolors='k', linewidths=4, cmap='RdBu', vmin=0.0, vmax=1.0)
plt.colorbar(c)
plt.show()
How can I change the intensity of the 'RdBu' colormap? E.g., if the color is (0, 0, 1), it should be transformed into (0, 0, 0.8). More generally,
if the color is (x, y, z), it should be transformed into (ax, ay, az), where a is some scalar between zero and one.
This is quite similar to Stanley R's (edit: now Serenity) answer, without the (in my opinion) unnecessary complexity of loops, appending to lists, et cetera:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
a = 0.5
# Get the colormap colors, multiply them with the factor "a", and create new colormap
my_cmap = plt.cm.RdBu(np.arange(plt.cm.RdBu.N))
my_cmap[:,0:3] *= a
my_cmap = ListedColormap(my_cmap)
np.random.seed(1)
data = np.sort(np.random.rand(8,12))
plt.figure()
plt.subplot(121)
c = plt.pcolor(data, edgecolors='k', linewidths=4, cmap='RdBu', vmin=0.0, vmax=1.0)
plt.colorbar(c)
plt.subplot(122)
c = plt.pcolor(data, edgecolors='k', linewidths=4, cmap=my_cmap, vmin=0.0, vmax=1.0)
plt.colorbar(c)
plt.show()
You have to assembly new custom color map based on a standard.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
np.random.seed(1)
data = np.sort(np.random.rand(8,12))
plt.figure()
cmap = cm.get_cmap('RdBu', len(data)) # set how many colors you want in color map
# modify colormap
alpha = .5
colors = []
for ind in xrange(cmap.N):
c = []
for x in cmap(ind)[:3]: c.append(x*alpha)
colors.append(tuple(c))
my_cmap = matplotlib.colors.ListedColormap(colors, name = 'my_name')
# plot with my new cmap
cb = plt.pcolor(data, edgecolors='k', linewidths=4, cmap=my_cmap, vmin=0.0, vmax=1.0)
plt.colorbar(cb)
plt.show()
I would like to add a separate colorbar to each subplot in a 2x2 plot.
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
plt.colorbar(z1_plot,cax=ax1)
z2_plot = ax2.scatter(x,y,c = z2,vmin=0.0,vmax=40)
plt.colorbar(z1_plot,cax=ax2)
z3_plot = ax3.scatter(x,y,c = z3,vmin=0.0,vmax=894)
plt.colorbar(z1_plot,cax=ax3)
z4_plot = ax4.scatter(x,y,c = z4,vmin=0.0,vmax=234324)
plt.colorbar(z1_plot,cax=ax4)
plt.show()
I thought that this is how you do it, but the resulting plot is really messed up; it just has an all grey background and ignores the set_xlim , set_ylim commands I have (not shown here for simplicity). + it shows no color bars. Is this the right way to do it?
I also tried getting rid of the "cax = ...", but then the colorbar all goes on the bottom right plot and not to each separate plot!
This can be easily solved with the the utility make_axes_locatable. I provide a minimal example that shows how this works and should be readily adaptable:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
m1 = np.random.rand(3, 3)
m2 = np.arange(0, 3*3, 1).reshape((3, 3))
fig = plt.figure(figsize=(16, 12))
ax1 = fig.add_subplot(121)
im1 = ax1.imshow(m1, interpolation='None')
divider = make_axes_locatable(ax1)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im1, cax=cax, orientation='vertical')
ax2 = fig.add_subplot(122)
im2 = ax2.imshow(m2, interpolation='None')
divider = make_axes_locatable(ax2)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im2, cax=cax, orientation='vertical');
In plt.colorbar(z1_plot,cax=ax1), use ax= instead of cax=, i.e. plt.colorbar(z1_plot,ax=ax1)
Specify the ax argument to matplotlib.pyplot.colorbar(), e.g.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2)
for i in range(2):
for j in range(2):
data = np.array([[i, j], [i+0.5, j+0.5]])
im = ax[i, j].imshow(data)
plt.colorbar(im, ax=ax[i, j])
plt.show()
Please have a look at this matplotlib example page. There it is shown how to get the following plot with four individual colorbars for each subplot:
I hope this helps.
You can further have a look here, where you can find a lot of what you can do with matplotlib.
Try to use the func below to add colorbar:
def add_colorbar(mappable):
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.pyplot as plt
last_axes = plt.gca()
ax = mappable.axes
fig = ax.figure
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
cbar = fig.colorbar(mappable, cax=cax)
plt.sca(last_axes)
return cbar
Then you codes need to be modified as:
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
add_colorbar(z1_plot)