Question

I have some graphs created with NetworkX and show them on screen using Matplotlib. Specifically, since I don't know in advance how many graphs I need to show, I create a subplot on the figure on fly. That works fine. However, at some point in the script, some subplots are removed from the figure and the figure is shown with some empty subplots. I would like to avoid it, but I was not able to retrieve the subplots that are empty in the figure. Here is my code:

#instantiate a figure with size 12x12
fig = plt.figure(figsize=(12,12))

#when a graph is created, also a subplot is created:
ax = plt.subplot(3,4,count+1)

#and the graph is drawn inside it: N.B.: pe is the graph to be shown
nx.draw(pe, positions, labels=positions, font_size=8, font_weight='bold', node_color='yellow', alpha=0.5)

#many of them are created..

#under some conditions a subplot needs to be deleted, and so..
#condition here....and then retrieve the subplot to deleted. The graph contains the id of the ax in which it is shown.
for ax in fig.axes:
    if id(ax) == G.node[shape]['idax']:
         fig.delaxes(ax)

until here works fine, but when I show the figure, the result looks like this:

enter image description here

you can notice that there are two empty subplots there.. at the second position and at the fifth. How can I avoid it? Or.. how can I re-organize the subplots in such a way that there are no more blanks in the figure?

Any help is apreciated! Thanks in advance.

Was it helpful?

Solution

So to do this I would keep a list of axes and when I delete the contents of one I would swap it out with a full one. I think the example below solved the problem (or at least gives an idea of how to solve it):

import matplotlib.pyplot as plt

# this is just a helper class to keep things clean
class MyAxis(object):
    def __init__(self,ax,fig):
        # this flag tells me if there is a plot in these axes
        self.empty = False
        self.ax = ax
        self.fig = fig
        self.pos = self.ax.get_position()

    def del_ax(self):
        # delete the axes
        self.empty = True
        self.fig.delaxes(self.ax)

    def swap(self,other):
        # swap the positions of two axes
        #
        # THIS IS THE IMPORTANT BIT!
        #
        new_pos = other.ax.get_position()
        self.ax.set_position(new_pos)
        other.ax.set_position(self.pos)
        self.pos = new_pos

def main():
    # generate a figure and 10 subplots in a grid
    fig, axes = plt.subplots(ncols=5,nrows=2)

    # get these as a list of MyAxis objects
    my_axes = [MyAxis(ax,fig) for ax in axes.ravel()]

    for ax in my_axes:
        # plot some random stuff
        ax.ax.plot(range(10))

    # delete a couple of axes
    my_axes[0].del_ax()
    my_axes[6].del_ax()

    # count how many axes are dead
    dead = sum([ax.empty for ax in my_axes])

    # swap the dead plots for full plots in a row wise fashion
    for kk in range(dead):
        for ii,ax1 in enumerate(my_axes[kk:]):
            if ax1.empty:
                print ii,"dead"
                for jj,ax2 in enumerate(my_axes[::-1][kk:]):
                    if not ax2.empty:
                        print "replace with",jj
                        ax1.swap(ax2)
                        break
                break



    plt.draw()
    plt.show()

if __name__ == "__main__":
    main()

The extremely ugly for loop construct is really just a placeholder to give an example of how the axes can be swapped.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top