How to pad adjacency matrix cells in D3.js style? - python

I'm trying to replicate the matrix adjacency visualization as demonstrated in this D3.js example. Note that each cell is padded, resulting in a white border around each cell.
This is what I've got so far:
img = matplotlib.pyplot.imshow(m, interpolation='none')
img.axes.xaxis.tick_top()
img.axes.xaxis.set_ticks_position('none')
img.axes.yaxis.set_ticks_position('none')
img.axes.spines['top'].set_color('none')
img.axes.spines['bottom'].set_color('none')
img.axes.spines['left'].set_color('none')
img.axes.spines['right'].set_color('none')
matplotlib.pyplot.set_cmap('gray_r')
matplotlib.pyplot.xticks(range(len(m)), G.nodes(), rotation='vertical')
matplotlib.pyplot.yticks(range(len(m)), G.nodes(), rotation='horizontal')
I've looked into ways of iterating through each cell, and into other interpolation techniques, but I'd really like to keep no interpolation at all, as I'd like to keep the cells square. Has anyone tried to do this before?

One possible solution is to use the pcolor method of pyplot, as it accepts a kwarg edgecolor.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(6)
y = np.arange(6)
X, Y = np.meshgrid(x, y)
Z = np.random.rand(5, 5)
ax = plt.subplot(111, aspect='equal') # To make the cells square
ax.pcolor(X, Y, Z,
edgecolor='white', # Color of "padding" between cells
linewidth=2) # Width of "padding" between cells
plt.show()

Related

3d contour with 3 variables and 1 variable as colour

I have three variables for my plot and I colour by the fourth variable. I have made a scatter plot via the following code, but I want a contour plot. My code:
import numpy as np
import matplotlib.pyplot as plt
a=np.linspace(4.0,14.0,3)
b=np.linspace(0.5,2.5,3)
c=np.linspace(0.0,1.0,3)
d=np.random.rand(len(a),len(b),len(c)) #colour by this variable
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
z,y,x=np.meshgrid(c,a,b)
img = ax.scatter(x, y, z, c=d, cmap='RdGy')
fig.colorbar(img, pad=0.2).set_label('colour')
ax.set_xlabel('c')
ax.set_ylabel('a')
ax.set_zlabel('b')
I want a filled contour instead of scatter plot. I know mayavi.mlab has this feature, but I cannot import mlab for some reason. Is there an alternative, or is there a better way of presenting this data?
Here is how I would present this 3-dimensional data. Each plot is a cross-section through the cube. This makes sense intuitively.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(4.0, 14.0, 3)
y = np.linspace(0.5, 2.5, 3)
z = np.linspace(0.0, 1.0, 3)
data = np.random.rand(len(x), len(y), len(z))
fig, axes = plt.subplots(len(z), 1, figsize=(3.5, 9),
sharex=True,sharey=True)
for i, (ax, d) in enumerate(zip(axes, data.swapaxes(0, 2))):
ax.contour(x, y, d)
ax.set_ylabel('y')
ax.grid()
ax.set_title(f"z = {z[i]}")
axes[-1].set_xlabel('x')
plt.tight_layout()
plt.show()
My advice: 3D plots are rarely used for serious data visualization. While they look cool, it is virtually impossible to read any data points with any accuracy.
Same thing goes for colours. I recommend labelling the contours rather than using a colour map.
You can always use a filled contour plot to add colours as well.

Set size of subplot to other sublot with equal aspect ratio

I would like a representation consisting of a scatter plot and 2 histograms on the right and below the scatter plot
create. I have the following requirements:
1.) In the scatter plot, the apect ratio is equal so that the circle does not look like an ellipse.
2.) In the graphic, the subplots should be exactly as wide or high as the axes of the scatter plot.
This also works to a limited extent. However, I can't make the lower histogram as wide as the x axis of the scatter plot. How do I do that?
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import random
#create some demo data
x = [random.uniform(-2.0, 2.0) for i in range(100)]
y = [random.uniform(-2.0, 2.0) for i in range(100)]
#create figure
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, width_ratios = [3, 1], height_ratios = [3, 1])
ax = plt.subplot(gs[0])
# Axis labels
plt.xlabel('pos error X [mm]')
plt.ylabel('pos error Y [mm]')
ax.grid(True)
ax.axhline(color="#000000")
ax.axvline(color="#000000")
ax.set_aspect('equal')
radius = 1.0
xc = radius*np.cos(np.linspace(0,np.pi*2))
yc = radius*np.sin(np.linspace(0,np.pi*2))
plt.plot(xc, yc, "k")
ax.scatter(x,y)
hist_x = plt.subplot(gs[1],sharey=ax)
hist_y = plt.subplot(gs[2],sharex=ax)
plt.tight_layout() #needed. without no xlabel visible
plt.show()
what i want is:
Many thanks for your help!
The easiest (but not necessarily most elegant) solution is to manually position the lower histogram after applying the tight layout:
ax_pos = ax.get_position()
hist_y_pos = hist_y.get_position()
hist_y.set_position((ax_pos.x0, hist_y_pos.y0, ax_pos.width, hist_y_pos.height))
This output was produced by matplotlib version 3.4.3. For your example output, you're obviously using a different version, as I get a much wider lower histogram than you.
(I retained the histogram names as in your example although I guess the lower one should be hist_x instead of hist_y).

Projecting contour lines from one graph to another

I want to project the contour lines from one figure to another figure (with the same x,y reference system). Instead of onto a fixed plane I want it to be projected onto a surface plot in the second figure.
UPDATE: There is a workaround; by using the contour.allsegs command you can get a list of arrays containing x,y coordinates of the contour lines, which you can then use to preprocess data for the second figure.
BUT: This only works, because I know the mathematical respresentation of the second surface. Meaning I can simply calculate the z-values using the x,y-values of the first-figure contour lines according to the formula.
import numpy as np
import matplotlib.pyplot as plt
X,Y = np.meshgrid(np.arange(0,5,1/5), np.arange(0,5,1/5))
Z1 = np.sin(X)+np.cos(Y)
Z2 = X+Y
fig = plt.figure(figsize=plt.figaspect(0.5))
ax1 = fig.add_subplot(1, 2, 1, projection='3d',title='fig1')
surf1 = ax1.plot_surface(X, Y, Z1, alpha=0.2)
contour1 = ax1.contour(X, Y, Z1)
segs=contour1.allsegs
ax2 = fig.add_subplot(1, 2, 2, projection='3d',title='fig2')
surf2 = ax2.plot_surface(X, Y, Z2, alpha=0.2)
for i in range(len(segs)):
if segs[i]:
plt.plot(segs[i][0][:,0],segs[i][0][:,1],[x+y for x,y in zip(segs[i][0][:,0],segs[i][0][:,1])])
if len(segs[i]) >= 2:
plt.plot(segs[i][1][:,0],segs[i][1][:,1],[x+y for x,y in zip(segs[i][1][:,0],segs[i][1][:,1])])
plt.show()
Resulting in:
Is there another (easy) way to get contour lines from fig1 projected onto the surface of fig2 (maybe a mpl built-in function I am missing)?
How can I further develop the approach above to also be able to use it with surfaces I do not know the mathematical representation of, but rather have a XYZ data set from a file?
Any hints or alternative approaches for a solution are very welcome!

How to set markersize in plt.imshow()

I have the following problem:
I want to plot an adjacency matrix using a colormap. Now I want do adjust the markersize, because you cannot really
see the dots in the picture since the matrix is really big . How can I do this? Using spy(), this works like this.
plt.spy(adj, markersize = 1)
I want to have something like this:
plt.imshow(adj, cmap = colormap, markersize= 1)
This however, doesnt work.
Thanks
You may use a scatter plot, which allows to set the markersize using the s argument.
ax.scatter(X,Y,c=z, s=36, marker="s")
An example comparing a spy, imshow and scatter plot.
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1,ax2,ax3) = plt.subplots(ncols=3, figsize=(8,4))
z = np.random.rand(20, 20)
X,Y = np.meshgrid(np.arange(z.shape[1]),np.arange(z.shape[0]))
z[5] = 0.
z[:, 12] = 0.
ax1.spy(z, markersize=5, precision=0.1, origin="lower")
ax2.imshow(z, origin="lower")
ax3.scatter(X,Y,c=z, s=36, marker="s")
ax3.set_aspect("equal")
ax3.margins(0)
ax1.set_title("spy")
ax2.set_title("imshow")
ax3.set_title("scatter")
plt.show()

plot many circles based on x,y,r being vectors in python

x,y are positions of the circles and r is the radius - all vectors.I want to plot them all at once. Something like:
import matplotlib.pyplot as plt
from matplotlib.patches Circle
#define x,y,r vectors
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
plt.Circle((x,y),r,color='r')
plt.show()
Thanks.
plt.scatter allows you to define a radius of the points plotted.
From the doc
matplotlib.pyplot.scatter(x, y, s=20, c='b', marker='o')
[...]
s:
size in points^2. It is a scalar or an array of the same length as x and y.
Playing with facecolor and edgecolor you should be able to get what you want
You can find an example in How to set_gid() for each bubble in matplot scatter chart?
I am not informed about the Circles patch, but here is how you can do it with the standard plot command:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([0.2,0.4])
y = np.array([0.2,1.2])
r = np.array([0.5,0.3])
phi = np.linspace(0.0,2*np.pi,100)
na=np.newaxis
# the first axis of these arrays varies the angle,
# the second varies the circles
x_line = x[na,:]+r[na,:]*np.sin(phi[:,na])
y_line = y[na,:]+r[na,:]*np.cos(phi[:,na])
plt.plot(x_line,y_line,'-')
plt.show()
The basic idea is to give the plt.plot(...) command two 2D arrays. In that case they are interpreted as a list of plots. Espacially for many plots (=many circles) this is much faster, than plotting circle by circle.

Categories

Resources