Isometric orientation for heatmap with matplotlib - python

Assume we have a heat-map as below
construct using the code
import string
import numpy as np
from matplotlib import pyplot as plt
label=list(string.ascii_uppercase)
mdata = np.random.randn(3, len(label), len(label))
data = mdata[0, :, :]
data=np.tril(data,-1)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)
plt.show()
Is possible whether using Matplotlib, Seaborn or any other package to render into isometric
alignment as below.

With matplotlib's 3D toolkit, and using numpy's triu_indices, you could create a bar plot from the triangular matrix:
import numpy as np
import matplotlib.pyplot as plt
ax = plt.figure().add_subplot(projection='3d')
N = 26
data = np.random.randn(3, N, N)
for i, (plane, cmap) in enumerate(zip(data, ['Reds', 'Greens', 'Blues'])):
indices = np.triu_indices(N, 1)
norm = plt.Normalize(plane.min(), plane.max())
ax.bar(left=indices[0], bottom=indices[1], height=0.9,
zs=i, zdir='y',
color=plt.get_cmap(cmap)(norm(plane[indices])))
plt.show()
PS: To have full rectangles, the sub-arrays from np.indices need to be made 1D:
import numpy as np
import matplotlib.pyplot as plt
ax = plt.figure().add_subplot(projection='3d')
N = 26
data = np.random.randn(3, N, N)
for i, (plane, cmap) in enumerate(zip(data, ['Reds', 'Greens', 'Blues'])):
indices = np.indices((N,N))
norm = plt.Normalize(plane.min(), plane.max())
ax.bar(left=indices[0].ravel(), bottom=indices[1].ravel(), height=0.9,
zs=i, zdir='y',
color=plt.get_cmap(cmap)(norm(plane).ravel()))
plt.show()

Related

python multicolored background

How do I use matplotlib.pyplot to colour the background of my plot based on an array (of True/False's)?
So for example, if my array was (T,F,F,F,T,T) and I choose the colours 'red' and 'blue', I need the background to be a red column, 3 blue colomns, followed by 2 more reds.
N = 2000
tf = np.random.normal(size = N)
ctf = np.array([np.sum(tf[:1+i]) for i in range(N)])
fig, ax = plt.subplots()
tf2 = tf[None,:]
ax.imshow(tf2, cmap='RdYlGn', aspect = 'auto')
ax.plot(ctf,'k')
You can use imshow:
import numpy as np
from matplotlib import pyplot as plt
fig, ax = plt.subplots()
data = np.array([True, False, True])[ None, :]
ax.imshow(data, cmap = 'RdBu', aspect="auto")
ax.axis('off')
fig.show()
edit: swapped axis to produce columns
edit2: add larger imshow
import numpy as np
from matplotlib import pyplot as plt
N = 2000
tf = np.random.normal(size = N)
ctf = np.array([np.sum(tf[:1+i]) for i in range(N)])
fig, ax = plt.subplots(2, sharex = 'all', \
gridspec_kw = dict(\
height_ratios = [5, 1]))
tf2 = tf[None,:]
ax[0].plot(ctf,'k')
ax[1].imshow(tf2, cmap='RdYlGn', aspect = 'auto')
plt.subplots_adjust(hspace = 0)
edit 3:
import numpy as np
from matplotlib import pyplot as plt
N = 2000
tf = np.random.normal(size = N)
ctf = np.array([np.sum(tf[:1+i]) for i in range(N)])
fig, ax = plt.subplots()
tf2 = tf[None,:]
ax.plot(ctf,'k')
ax.imshow(tf2, cmap='RdYlGn', aspect = 'auto', extent =[0, ctf.shape[0], ctf.min(), ctf.max()])
Sounds like you want to draw rectangles on your plot. (See matplotlib: how to draw a rectangle on image) If you want to have the Rectangles behind some other data, set their zorder to a negative number when you create them.

matplotlib plot_surface 3D plot with non-linear color map

I have this following python code, which displays the following 3D plot.
My code is:
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
# Generate data example
X,Y = np.meshgrid(np.arange(-99,-90), np.arange(-200,250,50))
Z = np.zeros_like(X)
Z[:,0] = 100.
Z[4][7] = 10
# Normalize to [0,1]
Z = (Z-Z.min())/(Z.max()-Z.min())
colors = cm.viridis(Z)
rcount, ccount, _ = colors.shape
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rcount=rcount, ccount=ccount,
facecolors=colors, shade=False)
surf.set_facecolor((0,0,0,0))
plt.show()
I want to color the irregularities on the XY plane in a different color. I want to be able to highlight the bumps on the XY plane.
How do I do that?
The problem is that the grid is not very dense. The bump consist of a single pixel. So there are 4 cells in the grid, 3 of which have their lower left corner at 0, and would hence not receive a different color according to their value. Only the one pixel which actually is the bump gets colorized.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
X,Y = np.meshgrid(np.arange(-99,-90), np.arange(-200,250,50))
Z = np.zeros_like(X)
Z[:,0] = 100.
Z[4][7] = 10
norm = plt.Normalize(Z.min(),Z.min()+10 )
colors = cm.viridis(norm(Z))
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, facecolors=colors, shade=False)
surf.set_facecolor((0,0,0,0))
plt.show()
Now you may expand the colorized part of the plot, e.g. using scipy.ndimage.grey_dilation, such that all pixels that are adjacent also become yellow.
from scipy import ndimage
C = ndimage.grey_dilation(Z, size=(2,2), structure=np.ones((2, 2)))
norm = plt.Normalize(Z.min(),Z.min()+10 )
colors = cm.viridis(norm(C))

How to increase the size of a single subfigure with pyplot/gridspec?

I'm trying to plot 23 graphs in a 6x4 grid, with one figure taking up twice the width of the other figures. I'm using gridspec and my current code is:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
x = np.arange(0, 7, 0.01)
fig = plt.figure(figsize=(6, 4))
gs = gridspec.GridSpec(nrows=6, ncols=4)
for n in range(22):
ax = fig.add_subplot(gs[n])
ax.plot(x, np.sin(0.2*n*x))
corrax = fig.add_subplot(gs[22])
fig.tight_layout()
plt.show()
This produces the following:
I want to increase the width of the rightmost plot in the bottom row so it takes up the remaining space in that row. Is there a way to accomplish this?
You can use slices to select several positions from the gridspec, e.g. gs[22:24].
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
x = np.arange(0, 7, 0.01)
fig = plt.figure(figsize=(6, 4))
gs = gridspec.GridSpec(nrows=6, ncols=4)
for n in range(22):
ax = fig.add_subplot(gs[n])
ax.plot(x, np.sin(0.2*n*x))
corrax = fig.add_subplot(gs[22:24])
corrax.plot(x,np.sin(0.2*22*x), color="crimson", lw=3)
fig.tight_layout()
plt.show()
You can also slice the gridspec two-dimensionally. E.g. to create a 3x3 grid and make the plot in the lower right corner span two columns and two rows, you could slice like gs[1:,1:].
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
x = np.arange(0, 7, 0.01)
fig = plt.figure(figsize=(6, 4))
gs = gridspec.GridSpec(nrows=3, ncols=3)
for n in range(3):
ax = fig.add_subplot(gs[0,n])
ax.plot(x, np.sin(0.2*n*x))
if n !=0:
ax = fig.add_subplot(gs[n,0])
ax.plot(x, np.sin(0.2*n*x))
corrax = fig.add_subplot(gs[1:,1:])
corrax.plot(x,np.sin(0.2*22*x), color="crimson", lw=3)
fig.tight_layout()
plt.show()
#corrax = fig.add_subplot(gs[5,2:])
corrax = fig.add_subplot(6,4,(23,24))
both shold work.
see examples

How do you scale a polygon patch in matplotlib?

In the example below, I create a rectangular patch using matplotlib.patches.Polygon. Is there a way to scale the patch before adding it to the plot?
I've tried using matplotlib.transforms.Affine2D in a variety of ways with no success. As usual, the matplotlib documentation on transformations is woefully insufficient.
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot([-3,3],[-3,3])
x = [-1,0,1,1,0,-1]
y = [1,1,1,-1,-1,-1]
poly = Polygon( zip(x,y), facecolor='red', edgecolor='red', alpha=0.5)
ax.add_patch(poly)
plt.show()
If by scale you mean multiplication by a factor, you can easily do this via numpy.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot([-3,3],[-3,3])
x = [-1,0,1,1,0,-1]
y = [1,1,1,-1,-1,-1]
scale = 2
poly = Polygon( np.c_[x,y]*scale, facecolor='red', edgecolor='red', alpha=0.5)
ax.add_patch(poly)
plt.show()
The same can be achieved with a matplotlib.transforms.Affine2D() transform.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
import matplotlib.transforms as transforms
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot([-3,3],[-3,3])
x = [-1,0,1,1,0,-1]
y = [1,1,1,-1,-1,-1]
trans = transforms.Affine2D().scale(2) + ax.transData
poly = Polygon( np.c_[x,y], facecolor='red', edgecolor='red', alpha=0.5,
transform=trans)
ax.add_patch(poly)
plt.show()
Although it seems a bit overkill for a simple scaling like this.

Colorbar for errorbar on matplotlib

I have a 1D array for some quantity, say T. I have data points (X, Y) to be plotted with errorbars and colorcoded with T.
I am plotting errorbars as:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.pylab as pylab
import matplotlib
X = np.linspace(0, 10, 50)
Y = np.random.normal(0, 1, 50)
E = np.random.normal(0, 0.1, 50)
norm = matplotlib.colors.Normalize(vmin=0, vmax=0.5)
c_m = matplotlib.cm.jet
s_m = matplotlib.cm.ScalarMappable(cmap=c_m, norm=norm)
s_m.set_array([])
plt.figure()
for i in range(0, len(Y)):
plt.errorbar(X[i], Y[i], color=s_m.to_rgba(E[i]), yerr=[E[i], E[i]], capsize=3, ls='none')
plt.grid()
plt.show()
This doesn't seem to work. Says :
err must be [ scalar | N, Nx1 or 2xN array-like ]
For plt.plot, if I have say N curves, each with M points, and I have to colorcode each curve by T, (dimensions: X[M], Y[N][M], T[N])
I do the following:
norm = matplotlib.colors.Normalize(
vmin=0,
vmax=32)
# choose a colormap
c_m = matplotlib.cm.jet
# create a ScalarMappable and initialize a data structure
s_m = matplotlib.cm.ScalarMappable(cmap=c_m, norm=norm)
s_m.set_array([])
plt.figure()
for i in range(0, N):
plt.plot(X, Y[i], color=s_m.to_rgba(T[i]))
plt.grid()
plt.show()
This scheme works for plot! But does not seem to work with errorbar and 1D arrays.
However, I am not really sure how far the comparison is good since array dimensions are different in plot (2D) and errorbar (1D) case.
EDIT:
Got the solution. It does not relate to colorbar at all. Just that yerr array needs 2XN array.
Hence yerr=[[E[i]], [E[i]]] fixes it.
I still don't see the problem. Replacing plt.plot with plt.errorbar is working just fine:
import matplotlib.pyplot as plt
import matplotlib.colors
import matplotlib.cm
import numpy as np
N=3
x=np.arange(10)
Y = np.random.rand(len(x),N)
a = np.ones_like(x)*0.1
T = np.array([5,12,27])
plt.figure()
norm = matplotlib.colors.Normalize(vmin=0,vmax=32)
# choose a colormap
c_m = matplotlib.cm.jet
# create a ScalarMappable and initialize a data structure
s_m = matplotlib.cm.ScalarMappable(cmap=c_m, norm=norm)
s_m.set_array([])
for i in range(0, N):
plt.errorbar(x, Y[:,i], yerr=[a,a], color=s_m.to_rgba(T[i]), capsize=3, ls='none')
plt.grid()
plt.grid()
plt.show()

Categories

Resources