Matplotlib matrix/image explicitly state axis values - python

I would use imshow for this, so I will use it to describe my problem.
I have several matrices which I would like to plot on the same axis. Something like this:
import matplotlib.pyplot as plt
import numpy as np
a = np.array([[0,1,2],[0,1,2]])
x = np.array([0,1,2])
y = np.array([0,1])
a2 = np.array([[10,11,12],[10,11,12]])
x2 = np.array([10,11,12])
y2 = np.array([0,1])
plt.imshow(a,extent=[x.min(),x.max(),y.min(),y.max()])
plt.imshow(a2,extent=[x2.min(),x2.max(),y2.min(),y2.max()])
plt.show()
(With this code the first imshow is overwritten by the second)
The reason why I can't combine them into a single matrix with one set of x and y axes (by filling the gaps with zeros) is that the combined matrix would be huge and there are large spaces in between the strips.

It's not overwritten, the axes limits are just reset to the extents of the last image each time.
Just call plt.autoscale().
As a quick example of what you're seeing:
import numpy as np
import matplotlib.pyplot as plt
data1, data2 = np.random.random((2,10,10))
fig, ax = plt.subplots()
ax.imshow(data1, extent=[-10, 0, -10, 0])
ax.imshow(data2, extent=[10, 20, 10, 20])
plt.show()
Now, if we just call autoscale:
import numpy as np
import matplotlib.pyplot as plt
data1, data2 = np.random.random((2,10,10))
fig, ax = plt.subplots()
ax.imshow(data1, extent=[-10, 0, -10, 0])
ax.imshow(data2, extent=[10, 20, 10, 20])
ax.autoscale()
plt.show()

Related

Create a heat map out of three 1D arrays

I want to create a heatmap out of 3 1dimensional arrays. Something that looks like this:
Up to this point, I was only able to create a scatter plot where the markers have a different color and marker size depending on the third value:
My code:
xf = np.random.rand(1000)
yf = np.random.rand(1000)
zf = 1e5*np.random.rand(1000)
ms1 = (zf).astype('int')
from matplotlib.colors import LinearSegmentedColormap
# Remove the middle 40% of the RdBu_r colormap
interval = np.hstack([np.linspace(0, 0.4), np.linspace(0.6, 1)])
colors = plt.cm.RdBu_r(interval)
cmap = LinearSegmentedColormap.from_list('name', colors)
col = cmap(np.linspace(0,1,len(ms1)))
#for i in range(len(ms1)):
plt.scatter(xf, yf, c=zf, s=5*ms1/1e4, cmap=cmap,alpha=0.8)#, norm =matplotlib.colors.LogNorm())
ax1 =plt.colorbar(pad=0.01)
is giving me this result:
Any idea how I could make it look like the first figure?
Essentially what I want to do is find the average of the z value for groups of the x and y arrays
I think the functionality you are looking for is provided by scipy.stats.binned_statistic_2d. You can use it to organize values of xf and yf arrays into 2-dimensional bins, and compute the mean of zf values in each bin:
import numpy as np
from scipy import stats
np.random.seed(0)
xf = np.random.rand(1000)
yf = np.random.rand(1000)
zf = 1e5 * np.random.rand(1000)
means = stats.binned_statistic_2d(xf,
yf,
values=zf,
statistic='mean',
bins=(5, 5))[0]
Then you can use e.g. seaborn to plot a heatmap of the array of mean values:
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(10, 8))
sns.heatmap(means,
cmap="Reds_r",
annot=True,
annot_kws={"fontsize": 16},
cbar=True,
linewidth=2,
square=True)
plt.show()
This gives:

Problems with unpacking Matplotlib hist2d outputs

I'm using Matplotlib's function hist2d() and I want to unpack the output in order to further use it. Here's what I do: I simply load with numpy a 2-column file containing my data and use the following code
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np
traj = np.loadtxt('trajectory.txt')
x = traj[:,0]
y = traj[:,1]
M, xe, ye, img = plt.hist2d(x, y, bins = 80, norm = LogNorm())
plt.imshow(M)
plt.show()
The result I get is the following:
Instead, if I try to directly plot the hist2d results without unpacking them:
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np
traj = np.loadtxt('trajectory.txt')
x = traj[:,0]
y = traj[:,1]
plt.hist2d(x, y, bins = 80, norm = LogNorm())
plt.show()
I get the whole plot without the strange blue box. What am I doing wrong?
You can create a histogram plot directly with plt.hist2d. This calculates the histogram and plots it to the current axes. There is no need to show it yet another time using imshow.
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np; np.random.seed(9)
x = np.random.rayleigh(size=9900)
y = np.random.rayleigh(size=9900)
M, xe, ye, img = plt.hist2d(x, y, bins = 80, norm = LogNorm())
plt.show()
Or, you may first calculate the histogram and afterwards plot the result as an image to the current axes. Note that the histogram produced by numpy is transposed, see Matplotlib 2D histogram seems transposed, making it necessary to call imshow(M.T). Also note that in order to obtain the correct axes labeling, you need to set the imshow's extent to the extremal values of the xe and ye edge arrays.
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np; np.random.seed(9)
x = np.random.rayleigh(size=9900)
y = np.random.rayleigh(size=9900)
M, xe, ye = np.histogram2d(x, y, bins = 80)
extent = [xe[0], xe[-1], ye[0], ye[-1]]
plt.imshow(M.T, extent=extent, norm = LogNorm(), origin="lower")
plt.show()

heatmap with variable datapoint width

I want to plot the coefficients of a linear model over time.
On the y-axis you have the i-th feature of my model, on the x-axis is time and the value of the i-th coefficient is color coded.
In my example, the coefficients are constant from 0 to t1, t1 to t2 and so on. The intervals are not equally sized. Currently I circumvent this by creating many points spaced by delta t:
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
xi1 = [0, 1, 2]
t1 = range(4)
xi2 = [1, 1, 2]
t2 = range(5, 8)
data= np.vstack([xi1]*len(t1) + [xi2]*len(t2)).T
sns.heatmap(data)
Is there a way to do this more efficiently (without creating the redundant information)? I am also looking to have the right x-axis labels according to my t values.
You can use a matplotlib pcolormesh.
import matplotlib.pyplot as plt
import numpy as np
a = [[0,1],[1,1],[2,2]]
y = [0,1,2,3]
x = [0,5,8]
X,Y = np.meshgrid(x,y)
Z = np.array(a)
cmap = plt.get_cmap("RdPu", 3)
plt.pcolormesh(X,Y,Z, cmap=cmap)
plt.gca().invert_yaxis()
plt.colorbar(boundaries=np.arange(-0.5,3), ticks=np.unique(Z))
plt.show()

Different y axis in one array subplot

I don't know how to tell matplotlib to use different axis in one peculiar subplot of an array subplot:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
def plotter():
y=np.random.rand(10)
y1 = np.random.rand(10)*100
x = np.arange(len(y))
f, axarr = plt.subplots(2,2,sharex=True)
axarr[0][0].errorbar(x,y,)
axarr[0][0].errorbar(x,y1)
axarr[1][1].twinx()
axarr[1][1].errorbar(x,y)
axarr[1][1].errorbar(x,y1)
plt.show()
plotter()
This gives:
The issue is that my one data set is greater by a factor of hundred, so plotting them on the same y axis is useless. What I want to have for the lower right panel (and only for this panel) is one y axis that ranges from (0,10) on the right side of the plot and one that ranges from (0,100) on the other side. The blue line should be represented by the right (0,10) y axis, while the blue line should be represented by the left (0,100) y axis
One way of doing this is:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
def plotter():
y=np.random.rand(10)
y1 = np.random.rand(10)*100
x = np.arange(len(y))
f, axarr = plt.subplots(2,2,sharex=True)
axarr[0][0].errorbar(x,y,)
axarr[0][0].errorbar(x,y1)
axarr[1][1].errorbar(x,y)
ax2 = axarr[1][1].twinx()
ax2.plot(x,y1, 'r')
#ax2.tick_params('y', colors='r')
plt.show()
plotter()
Which gives this:

display matrix values and colormap

I need to display values of my matrix using matshow.
However, with the code I have now I just get two matrices - one with values and other colored.
How do I impose them? Thanks :)
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
min_val, max_val = 0, 15
for i in xrange(15):
for j in xrange(15):
c = intersection_matrix[i][j]
ax.text(i+0.5, j+0.5, str(c), va='center', ha='center')
plt.matshow(intersection_matrix, cmap=plt.cm.Blues)
ax.set_xlim(min_val, max_val)
ax.set_ylim(min_val, max_val)
ax.set_xticks(np.arange(max_val))
ax.set_yticks(np.arange(max_val))
ax.grid()
Output:
You need to use ax.matshow not plt.matshow to make sure they both appear on the same axes.
If you do that, you also don't need to set the axes limits or ticks.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
min_val, max_val = 0, 15
intersection_matrix = np.random.randint(0, 10, size=(max_val, max_val))
ax.matshow(intersection_matrix, cmap=plt.cm.Blues)
for i in xrange(15):
for j in xrange(15):
c = intersection_matrix[j,i]
ax.text(i, j, str(c), va='center', ha='center')
Here I have created some random data as I don't have your matrix. Note that I had to change the ordering of the index for the text label to [j,i] rather than [i][j] to align the labels correctly.
In Jupyter notebooks this is also possible with DataFrames and Seaborn:
import numpy as np
import seaborn as sns
import pandas as pd
min_val, max_val = 0, 15
intersection_matrix = np.random.randint(0, 10, size=(max_val, max_val))
cm = sns.light_palette("blue", as_cmap=True)
x=pd.DataFrame(intersection_matrix)
x=x.style.background_gradient(cmap=cm)
display(x)

Categories

Resources