Displaying multiple graphs from networkx in a table - python

I've been playing around with the random graph feature of networkx as seen here with the Erdos-Renyi graph:
G = nx.gnp_random_graph(n, p, seed=None, directed=False)
I can then draw the graph with
nx.draw
Is there a way, I can make a table of random graph images using nx.draw? I want to make a table of some sampled graphs with some labels. Is there a way to do this using Matlab plot?

If I understand correclty, you can use subplots to achieve what you want:
fig, axes = plt.subplots(nrows=3, ncols=3)
for ax in axes.ravel():
G = nx.gnp_random_graph(10,10, seed=None, directed=False)
nx.draw_networkx(G, ax=ax)
Edit:
You can change the size of the figure at instantiation, by using:
fig, axes = plt.subplots(nrows=rows, ncols=cols, figsize=(10,10)) # default unit is inches.
You can change the size after the fact by doing:
fig.set_figwidth(10)
and
fig.set_figheight(10)
you can access individual subplots if you have more than 1 row and more than 1 column, like so:
axes[row,column] # zero-indexed.
to add labels or other stuff, you can do:
axes[row,column].set_ylabel('blah')
axes[row,column].set_title('blubb')
to change the figure title you can do:
fig.suptitle('my fancy title')
If at the end your labels intersect or your figure looks otherwise messy, you can enforce tight layout:
plt.tight_layout()

Related

Matplotlib: How to extract vlines and fill_between data from ax objects?

I have a figure comprised of two x/y curves, a vline and a fill_between in Matplotlib.
My ultimate aim is displaying this figure along with 2 other figures as subplots in a 4th new figure. And I really want to avoid creating all three figures from scratch again just for this new figure with subplots.
So, I'm looking to create a 1x3 figure (subplots, 1 row, 3 columns) like this:
[fig1, fig2, fig3]
I'm almost there. I've so far been able to extract the two x/y curves from the original figure's ax object. Moving through a for loop, I've been able to rebuild most of the three figures as subplots in my new figure:
(ax_a, ax_b, ax_c are ax objects belonging to the three original figures I want to add as subplots to my new figure)
fig = plt.figure(figsize = (16,4))
ax1 = fig.add_subplot(1,3,1)
ax2 = fig.add_subplot(1,3,2)
ax3 = fig.add_subplot(1,3,3)
for ax, ref in zip(fig.axes, [ax_a, ax_b, ax_c]):
for line in ref.lines:
x = line.get_xdata()
y = line.get_ydata()
ax.plot(x,y)
ax.set_xlabel(ref.get_xlabel())
ax.set_ylabel(ref.get_ylabel())
This actually creates a 1x3 grid of my original 3 plots. It's almost perfect.
What's missing are the fill_between component and the vlines component. If I could extract those objects from ax_a, ax_b and ax_c, I'd be done. But I can't find a way to do that.
Is there a way? If not, how would you solve a problem like this?
Thanks so much in advance for any advice offered.

Is there a way in python using matplotlib to create a figure with subplots of subplots?

I'm trying to display a figure that contains 3 plots, and each of the plots is a plot of (8,1)-shaped subplots.
Essentially, I want one big figure with three sections each containing (8,1)-shaped subplots.
I'm looking for a way to do this without having to manually set all the proportions and spacings. The reason I'm doing this is to visualize an 8-channel neural signal compared to three other pre-defined signals, each signal being 8 channels.
If it makes any sense this way, I'm trying for something like this (ficticious code):
fig, ax = plt.subplots(n_figures = 3, n_rows = 8, n_cols = 1)
ax[figure_i, row_j, col_k].imshow(image)
Is there a way to do this?
Here is an example of what I am talking about. Ideally it would three subplots, and in each of the subplots there is a set of subplots of shape 8x1. I understand how to plot this all out by going through all the margins and setting the proportions, but I'm wondering if there's a simpler way to do this without having to go through all the additional code and settings as described in the above example code I've written.
You can create this kind of figure by first creating a subplot grid with the appropriate layout using the plt.subplots() function and then looping through the array of axes to plot the data, like in this example:
import numpy as np # v 1.19.2
import matplotlib.pyplot as plt # v 3.3.2
# Create sample signal data as a 1-D list of arrays representing 3x8 channels
signal_names = ['X1', 'X2', 'X3']
nsignals = len(signal_names) # ncols of the subplot grid
nchannels = 8 # nrows of the subplot grid
nsubplots = nsignals*nchannels
x = np.linspace(0, 14*np.pi, 100)
y_signals = nsubplots*[np.cos(x)]
# Set subplots width and height
subp_w = 10/nsignals # 10 corresponds the figure width in inches
subp_h = 0.25*subp_w
# Create figure and subplot grid with the appropriate layout and dimensions
fig, axs = plt.subplots(nchannels, nsignals, sharex=True, sharey=True,
figsize=(nsignals*subp_w, nchannels*subp_h))
# Optionally adjust the space between the subplots: this can also be done by
# adding 'gridspec_kw=dict(wspace=0.1, hspace=0.3)' to the above function
# fig.subplots_adjust(wspace=0.1, hspace=0.3)
# Loop through axes to create plots: note that the list of axes is transposed
# in this example to plot the signals one after the other column-wise, as
# indicated by the colors representing the channels
colors = nsignals*plt.get_cmap('tab10').colors[:nchannels]
for idx, ax in enumerate(axs.T.flat):
ax.plot(x, y_signals[idx], c=colors[idx])
if ax.is_first_row():
ax.set_title(signal_names[idx//nchannels], pad=15, fontsize=14)
plt.show()

Making an odd number of subplots in Python

I'm very new to Python, and I want to plot 13 different figures all in one plot. To do this nicely, I would like to plot the first 12 figures in a 6x2 grid (this works just fine), and then plot the 13th figure below it; either the same size as the other figures and centered, or larger than the rest so that its width is equal to twice the width of the other figures and all the edges are aligned. What would be the best way to specify axes of this kind using subplots? (So far, I've just used nrows=6, ncols=2, but I think something like that won't work with an odd number of figures to plot.) The code I have so far for plotting the first 12 plots looks like this (with simple test data):
fig, axes = plt.subplots(nrows=6, ncols=2, figsize=(45,10))
for ax in axes.flat:
ax.plot([1,2,3,4])
fig.subplots_adjust(right=0.5)
How can I add a 13th figure below the others?
You can use GridSpec (link to documentation) to generate flexible axes layout.
The following code creates the desired layout and puts all Axes objects in a list for easy access.
gs00 = matplotlib.gridspec.GridSpec(7, 2)
fig = plt.figure()
axs = []
for i in range(6):
for j in range(2):
ax = fig.add_subplot(gs00[i,j])
axs.append(ax)
ax = fig.add_subplot(gs00[6,:])
axs.append(ax)

plot graph in a specific figure in python

Actually, I am not clear that
fig_1 = plt.figure()
plt.subplot(2,2,1)
...
Is the ploting like plt.subplot(2,2,1) and other plt. plot on the fig_1 or system will automatically create a new empty figure?
Then how to plot something in a specific figure, for example:
fig_1 = plt.figure()
fig_2 = plt.figure()
plt.subplot(2,2,1)
I want to subplot on fig_2.
You can access a certain figure by e.g.
ax_1_1 = fig_1.add_subplot(2,2,1)
but this has a slightly different syntax (compare plt.subplot() against fig.add_subplot())
So I would recommend to create figures with subplots already prepared vis plt.subplots which returns handles for figure and axes on the fly:
fig_1, axs_1 = plt.subplots(2, 2)
fig_2, axs_2 = plt.subplots(3, 4)
axs_1[0, 0].plot(range(10))
axs_2[2, 3].plot(range(100))
fig_1.suptitle('Figure 1')
fig_2.suptitle('Figure 2')
etc. ...
You can use figure.add_subplot which will return an ax linked to your figure on which you can plot your data. Look at this page to get a global view of the different objects used by matplotlib.

Eliminate white space between subplots in a matplotlib figure

I am trying to create a nice plot which joins a 4x4 grid of subplots (placed with gridspec, each subplot is 8x8 pixels ). I constantly struggle getting the spacing between the plots to match what I am trying to tell it to do. I imagine the problem is arising from plotting a color bar on the right side of the figure, and adjusting the location of the plots in the figure to accommodate. However, it appears that this issue crops up even without the color bar included, which has further confused me. It may also have to do with the margin spacing. The images shown below are produced by the associated code. As you can see, I am trying to get the space between the plots to go to zero, but it doesn't seem to be working. Can anyone advise?
fig = plt.figure('W Heat Map', (18., 15.))
gs = gridspec.GridSpec(4,4)
gs.update(wspace=0., hspace=0.)
for index in indices:
loc = (i,j) #determined by the code
ax = plt.subplot(gs[loc])
c = ax.pcolor(physHeatArr[index,:,:], vmin=0, vmax=1500)
# take off axes
ax.axis('off')
ax.set_aspect('equal')
fig.subplots_adjust(right=0.8,top=0.9,bottom=0.1)
cbar_ax = heatFig.add_axes([0.85, 0.15, 0.05, 0.7])
cbar = heatFig.colorbar(c, cax=cbar_ax)
cbar_ax.tick_params(labelsize=16)
fig.savefig("heatMap.jpg")
Similarly, in making a square figure without the color bar:
fig = plt.figure('W Heat Map', (15., 15.))
gs = gridspec.GridSpec(4,4)
gs.update(wspace=0., hspace=0.)
for index in indices:
loc = (i,j) #determined by the code
ax = plt.subplot(gs[loc])
c = ax.pcolor(physHeatArr[index,:,:], vmin=0, vmax=400, cmap=plt.get_cmap("Reds_r"))
# take off axes
ax.axis('off')
ax.set_aspect('equal')
fig.savefig("heatMap.jpg")
When the axes aspect ratio is set to not automatically adjust (e.g. using set_aspect("equal") or a numeric aspect, or in general using imshow), there might be some white space between the subplots, even if wspace and hspaceare set to 0. In order to eliminate white space between figures, you may have a look at the following questions
How to remove gaps between *images* in matplotlib?
How to combine gridspec with plt.subplots() to eliminate space between rows of subplots
How to remove the space between subplots in matplotlib.pyplot?
You may first consider this answer to the first question, where the solution is to build a single array out of the individual arrays and then plot this single array using pcolor, pcolormesh or imshow. This makes it especially comfortable to add a colorbar later on.
Otherwise consider setting the figuresize and subplot parameters such that no whitespae will remain. Formulas for that calculation are found in this answer to the second question.
An adapted version with colorbar would look like this:
import matplotlib.pyplot as plt
import matplotlib.colors
import matplotlib.cm
import numpy as np
image = np.random.rand(16,8,8)
aspect = 1.
n = 4 # number of rows
m = 4 # numberof columns
bottom = 0.1; left=0.05
top=1.-bottom; right = 1.-0.18
fisasp = (1-bottom-(1-top))/float( 1-left-(1-right) )
#widthspace, relative to subplot size
wspace=0 # set to zero for no spacing
hspace=wspace/float(aspect)
#fix the figure height
figheight= 4 # inch
figwidth = (m + (m-1)*wspace)/float((n+(n-1)*hspace)*aspect)*figheight*fisasp
fig, axes = plt.subplots(nrows=n, ncols=m, figsize=(figwidth, figheight))
plt.subplots_adjust(top=top, bottom=bottom, left=left, right=right,
wspace=wspace, hspace=hspace)
#use a normalization to make sure the colormapping is the same for all subplots
norm=matplotlib.colors.Normalize(vmin=0, vmax=1 )
for i, ax in enumerate(axes.flatten()):
ax.imshow(image[i, :,:], cmap = "RdBu", norm=norm)
ax.axis('off')
# use a scalarmappable derived from the norm instance to create colorbar
sm = matplotlib.cm.ScalarMappable(cmap="RdBu", norm=norm)
sm.set_array([])
cax = fig.add_axes([right+0.035, bottom, 0.035, top-bottom])
fig.colorbar(sm, cax=cax)
plt.show()

Categories