0

I have to make plots for several institutions to show their performance against 1 or more receivers. Subplots seemed the correct way to go but it seems each subplot required that I specify the axes parameters even though they are identical. So I created a little piece of code that creates subscripted axes objects and it works UNLESS there is only one receiver.

            num_plots = len(receivers)

            fig, axes = plt.subplots(num_plots, 1, figsize=(50, 150),    squeeze=False)

            minor_ticks = md.MinuteLocator(byminute=[0, 15, 30, 45], interval=1)
            hours = md.HourLocator(interval=1)

            for i,receiver in enumerate(receivers):
                axes[i].xaxis.set_minor_locator(minor_ticks)
                axes[i].xaxis.set_major_locator(hours)
                axes[i].xaxis.set_major_formatter(md.DateFormatter('%H:%M'))
                axes[i].xaxis.get_offset_text().set_fontsize(24)
                axes[i].yaxis.get_offset_text().set_fontsize(24)
                axes[i].grid(b=True, which='major', color='b',   linestyle='-', alpha=0.6)
                axes[i].grid(b=True, which='minor', color='r',   linestyle='--', alpha=0.3)
                axes[i].tick_params(axis="both", labelsize=30)
                axes[i].set_ylabel('Bilateral Risk/5 min', fontsize=40,   weight='bold')
                axes[i].set_xlabel('Time', fontsize=40, weight='bold')

If there is only one subplot (basically "fig, axes = plt.subplots(1, 1, fig size(50, 150), squeeze=False)" ) then I get the following error:


    Traceback (most recent call last):
          .
          .
          .

      File "/Users/xxx/risk_scoring.py", line 276, in plot_result
        axes[i].xaxis.set_minor_locator(minor_ticks)
     AttributeError: 'numpy.ndarray' object has no attribute 'xaxis'

That's unexpected because I thought from here and here that 'squeeze=' would allow a 1x1 subplot. What is making the error or is there a better way to do this?

FOLLOW UP and ANSWER:

Taking the preceding code and substituting receivers = ["a", "b", "c", "d"] and then same but just one receiver all with 'squeeze=True' (the default):

     0
     1
     2
     3
     [<matplotlib.axes._subplots.AxesSubplot object at 0x7f865c94b610>
      <matplotlib.axes._subplots.AxesSubplot object at 0x7f865b6f3750>
      <matplotlib.axes._subplots.AxesSubplot object at 0x7f865b727410>
      <matplotlib.axes._subplots.AxesSubplot object at 0x7f865bd67790>]

and

    Traceback (most recent call last):
      File "main.py", line 186, in <module>
        axes[i].xaxis.set_minor_locator(minor_ticks)
    TypeError: 'AxesSubplot' object is not subscriptable

And the reason is that 'axes' in the first case is an array but in the second case it is just an object 'AxesSubplot(0.125,0.11;0.775x0.77)'.

If you do the second case (1 receiver) but set 'squeeze=false' you get:

    [[<matplotlib.axes._subplots.AxesSubplot object at 0x7f2e447a7790>]]
    0
    Traceback (most recent call last):
       File "main.py", line 186, in <module>
       axes[i].xaxis.set_minor_locator(minor_ticks)
    AttributeError: 'numpy.ndarray' object has no attribute 'xaxis'

That's a 2-D array. So I changed all references to 'axes' with a 2-D index eg "axes[i][0].set..." and it all seems to work.

MikeB2019x
  • 823
  • 8
  • 23
  • I would think the code should also not work when `num_plots` is bigger then 1. – ImportanceOfBeingErnest Nov 07 '19 at 22:09
  • Works because 'subplots' is happy with more than 1 x 1 plot matrix eg. 2 x 1, etc. But squeeze= was supposed to help with that (see links I provided) – MikeB2019x Nov 07 '19 at 22:15
  • Did you try it with `num_plots=2`? Why would there be a difference between those cases when `squeeze=False`? Best also use a [mcve], so things are a bit more obvious. – ImportanceOfBeingErnest Nov 07 '19 at 22:17
  • I would not post a falsehood. As indicated, yes it works with 2 to (at least) 17 (the largest number of receivers I have). I can't post those results. The second link I posted in the last para of my question explains the difference that 'squeeze=' makes. The first link is the closest Stack post that is like my question. – MikeB2019x Nov 07 '19 at 22:34
  • If your code works with `num_plots > 1` that would be bug. Which version of matplotlib are you using? ([This answer](https://stackoverflow.com/a/44604834/4124317) should explain the theory best.) – ImportanceOfBeingErnest Nov 07 '19 at 22:42
  • My follow-up edit solves the problem. I just had to look closer at what 'subplots' was returning ie. 'squeeze=False' makes the returned 'axes' a 2-D array but you have to get the indexing right. When 'squeeze=True' subplots returns different values for 'axes' depending on whether 'numrows' is 1 or not. Hence the weird behaviour. Tnx for having a look. – MikeB2019x Nov 08 '19 at 02:09

0 Answers0