0

I'm having trouble setting up subplots in matplotlib. Below is a screenshot of the layout I am trying to achieve. I've only gone up through ax4, as I have encountered two issues. Code is also below. (Note that on their own, the functions plot as expected.) I want to continue using "subplot2grid" instead of the other options, and I'm using Python 2.7

Expected behavior: Plots ax1, ax2, and ax3 should be a World Shade Relief Map, with position as shown in desired layout below. Plot ax4 should be a scatter plot, with position as shown in desired layout below.

Actual behavior: Plots ax1, ax2, and ax3 are all blank Plot ax4 is not a scatter, but it's actually the map; layout is also wrong.

I thought I was missing a "hold on" type feature, but it looks like that's not how matplotlib works. I also made sure I defined the plot limits in myplotA function.

import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter
from mpl_toolkits.basemap import Basemap
from random import randint

def myplotA(plotnum, title):
    south = 34.0129656032
    north = 34.721878622
    west = -116.7615176
    east = -116.336918412
    center = [(east + west) / 2, (north + south) / 2]
    m = Basemap(llcrnrlon=west, llcrnrlat=south, urcrnrlon=east, urcrnrlat=north, resolution='c', epsg=4326, lon_0=center[0], lat_0=center[1], suppress_ticks=False)
    img = m.arcgisimage(service="World_Shaded_Relief", xpixels=2000)
    img.set_alpha(0.5)
    plt.xticks(rotation='horizontal')
    plotnum.xaxis.set_major_formatter(ScalarFormatter(useOffset=False))
    plotnum.axis([west, east, south, north])
    for label in (plotnum.get_xticklabels() + plotnum.get_yticklabels()):label.set_fontsize(9)
    plt.gca().set_title(title, fontsize=12)

def myplotB(plotnum, title):
    x = [randint(0, 10) for i in range(0, 6)]
    y = [randint(0, 10) for i in range(0, 6)]
    plotnum.scatter(x, y, s=4)
    plotnum.xaxis.set_major_formatter(ScalarFormatter(useOffset=False))
    plt.xlabel('xlabel', fontsize=8)
    plt.ylabel('ylabel', fontsize=8)
    plt.gca().set_title(title, fontsize=12)



fig = plt.figure(figsize=(11, 17))
ax1 = plt.subplot2grid((8, 3), (0, 0), rowspan=4, colspan=1)
ax2 = plt.subplot2grid((8, 3), (0, 1), rowspan=4, colspan=1)
ax3 = plt.subplot2grid((8, 3), (0, 2), rowspan=4, colspan=1)
ax4 = plt.subplot2grid((8, 3), (5, 0), rowspan=1, colspan=2)
myplotA(ax1, 'ax1')
myplotA(ax2, 'ax2')
myplotA(ax3, 'ax3')
myplotB(ax4, 'ax4')
plt.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=.1, hspace=.1)
fig.savefig(outpath + '\\' + 'mytest.pdf')

Desired Layout Desired Layout Image

Actual Result Actual Result Image

username
  • 3
  • 1
  • 4

2 Answers2

0

You pass the axes to the plotting functions, but inside of those you need to actually use those passed axes. Else all the plt commands will apply to the currently active axes, which is the last one you create.

import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter
from mpl_toolkits.basemap import Basemap
from random import randint

def myplotA(ax, title):
    south = 34.0129656032
    north = 34.721878622
    west = -116.7615176
    east = -116.336918412
    center = [(east + west) / 2, (north + south) / 2]
    m = Basemap(llcrnrlon=west, llcrnrlat=south, urcrnrlon=east, urcrnrlat=north, 
                resolution='c', epsg=4326, lon_0=center[0], lat_0=center[1], 
                suppress_ticks=False, ax=ax)
    img = m.arcgisimage(service="World_Shaded_Relief", xpixels=2000)
    img.set_alpha(0.5)
    plt.setp(ax.get_xticklabels(), rotation='horizontal')
    plt.setp(ax.get_xticklabels() + ax.get_yticklabels(), fontsize=9)
    ax.xaxis.set_major_formatter(ScalarFormatter(useOffset=False))
    ax.axis([west, east, south, north])
    ax.set_title(title, fontsize=12)

def myplotB(ax, title):
    x = [randint(0, 10) for i in range(0, 6)]
    y = [randint(0, 10) for i in range(0, 6)]
    ax.scatter(x, y, s=4)
    ax.xaxis.set_major_formatter(ScalarFormatter(useOffset=False))
    ax.set_xlabel('xlabel', fontsize=8)
    ax.set_ylabel('ylabel', fontsize=8)
    ax.set_title(title, fontsize=12)



fig = plt.figure(figsize=(11, 8))
ax1 = plt.subplot2grid((8, 3), (0, 0), rowspan=4, colspan=1)
ax2 = plt.subplot2grid((8, 3), (0, 1), rowspan=4, colspan=1)
ax3 = plt.subplot2grid((8, 3), (0, 2), rowspan=4, colspan=1)
ax4 = plt.subplot2grid((8, 3), (5, 0), rowspan=1, colspan=2)
myplotA(ax1, 'ax1')
myplotA(ax2, 'ax2')
myplotA(ax3, 'ax3')
myplotB(ax4, 'ax4')
plt.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=.1, hspace=.1)
fig.savefig('mytest.pdf')
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • thanks @ImportanceOfBeingErnest -- I wasn't able to get it to work with your code, but your description of the problem led me to a solution (posted as answer) – username Jul 08 '19 at 13:28
  • You mean if you copy and paste the code from this answer you get a different result than shown in the image? – ImportanceOfBeingErnest Jul 08 '19 at 19:43
0

Thanks @ImportanceOfBeingErnest

I tried your code above, but still same plot as shown in the "actual results" part of the OP. However, your words describe the problem: I'm activating the axis, and then activating the next one before plotting. Below does the trick--perhaps this is what you had anyhow and just mistakenly copy/pasted the original code. Thanks for point me in the right direction.

fig = plt.figure(figsize=(11, 17))
ax1 = plt.subplot2grid((8, 3), (0, 0), rowspan=4, colspan=1)
myplotA(ax1, 'ax1')
ax2 = plt.subplot2grid((8, 3), (0, 1), rowspan=4, colspan=1)
myplotA(ax2, 'ax2')
ax3 = plt.subplot2grid((8, 3), (0, 2), rowspan=4, colspan=1)
myplotA(ax3, 'ax3')
ax4 = plt.subplot2grid((8, 3), (4, 0), rowspan=1, colspan=2)
myplotB(ax4, 'ax4')
plt.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=.1, hspace=.1)
fig.savefig(outpath + '\\' + 'mytest.pdf')

Link to image of output plot; looks as expected

username
  • 3
  • 1
  • 4