0

I am running a script to plot a set of up to 6 curves sharing a common timeline. I am using twinx() up to 5 times and getting up to 4 detached axes on the right side of the plot. The script (shown below) is derived from this example. However, the recipe for drawing the extra axes shown in that example does not work if I have more than one extra axis. In order to draw the extra axes, I have to use plt.tight_layout(). But when I do that, I am getting excessive padding, mostly on the right side of the plot, which greatly reduces the ability to show nicely laid out curves, even when expanding the display window, as shown in this snapshot: result of script I am not getting the extra padding when not using tight_layout, but then I am not seeing the extra axes. I have tried several recipes of repairing the display of the extra axes based on the code in the referenced example, as evidenced by bits of commented out code in my script, to no avail.

How do I get rid of this extra padding and get to see my extra axes at the same time?

Script:

#!/usr/bin/env python3
import matplotlib.pyplot as plt
import matplotlib as mpl
x_data1=[234.5, 242.9, 251.4, 259.8, 268.2, 276.7, 285.1, 293.5, 339.7, 341.5, 343.4, 345.3, 347.2, 349.1, 351.0, 352.9, 354.8, 356.7, 358.6, 360.5, 362.4, 364.2, 366.1, 368.0, 370.0, 372.2, 374.5, 377.3, 381.7, 386.1, 390.6, 396.0, 401.4, 406.8, 409.8, 412.0, 414.3, 416.5, 437.6, 441.8, 446.0, 450.2, 454.4, 458.5, 462.7, 466.9, 471.1, 475.3, 479.5, 483.7, 487.9, 492.0, 496.2, 500.4, 504.6, 508.8, 513.0, 517.2, 521.3, 525.5, 529.7, 533.9, 538.1, 542.3, 607.5, 612.5, 617.5, 622.5, 627.6, 632.6, 637.6, 642.2, 646.6, 651.0, 655.5, 659.9, 664.4, 668.8, 673.2, 677.7, 682.1, 686.5, 691.0, 695.4, 699.9, 704.3, 708.7, 712.4, 715.9, 719.3, 722.8, 726.9]
y_data1=[229.0, 415.0, 399.0, 399.0, 399.0, 280.0, 257.0, 256.0, 172.0, 82.0, 61.0, 61.0, 61.0, 61.0, 61.0, 61.0, 61.0, 61.0, 61.0, 61.0, 61.0, 61.0, 61.0, 61.0, 58.0, 21.0, 16.0, 16.0, 16.0, 16.0, 17.0, 17.0, 17.0, 17.0, 19.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 17.0, 153.0, 151.0, 150.0, 150.0, 154.0, 154.0, 154.0, 154.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 83.0, 86.0, 94.0, 91.0, 96.0, 95.0]
x_data2=[234.5, 242.9, 251.4, 259.8, 268.2, 276.7, 285.1, 293.5, 339.7, 341.5, 343.4, 345.3, 347.2, 349.1, 351.0, 352.9, 354.8, 356.7, 358.6, 360.5, 362.4, 364.2, 366.1, 368.0, 370.0, 372.2, 374.5, 377.3, 381.7, 386.1, 390.6, 396.0, 401.4, 406.8, 409.8, 412.0, 414.3, 416.5, 437.6, 441.8, 446.0, 450.2, 454.4, 458.5, 462.7, 466.9, 471.1, 475.3, 479.5, 483.7, 487.9, 492.0, 496.2, 500.4, 504.6, 508.8, 513.0, 517.2, 521.3, 525.5, 529.7, 533.9, 538.1, 542.3, 607.5, 612.5, 617.5, 622.5, 627.6, 632.6, 637.6, 642.2, 646.6, 651.0, 655.5, 659.9, 664.4, 668.8, 673.2, 677.7, 682.1, 686.5, 691.0, 695.4, 699.9, 704.3, 708.7, 712.4, 715.9, 719.3, 722.8, 726.9]
y_data2=[180857.0, 363307.0, 329311.0, 326878.0, 335580.0, 317721.0, 310990.0, 320455.0, 63791.0, 28188.0, 2225.0, 1185.0, 1169.0, 1119.0, 1107.0, 1102.0, 1060.0, 1064.0, 964.0, 935.0, 876.0, 844.0, 785.0, 786.0, 790.0, 112.0, 28.0, 16.0, 16.0, 16.0, 50.0, 50.0, 50.0, 50.0, 22.0, 18.0, 18.0, 17.0, 264.0, 264.0, 251.0, 245.0, 244.0, 244.0, 247.0, 241.0, 264.0, 250.0, 239.0, 243.0, 244.0, 244.0, 269.0, 273.0, 266.0, 266.0, 266.0, 266.0, 266.0, 266.0, 266.0, 267.0, 267.0, 267.0, 9176.0, 67583.0, 49187.0, 48926.0, 59661.0, 54753.0, 59591.0, 58931.0, 35613.0, 32199.0, 30769.0, 30220.0, 28164.0, 24589.0, 23711.0, 23711.0, 19949.0, 20236.0, 20238.0, 21827.0, 22666.0, 22666.0, 22666.0, 23609.0, 28585.0, 33004.0, 33649.0, 32913.0]
x_data3=[339.7, 341.5, 343.4, 345.3, 347.2, 349.1, 351.0, 352.9, 354.8, 356.7, 358.6, 360.5, 362.4, 364.2, 366.1, 368.0, 370.0, 372.2, 374.5, 377.3, 381.7, 386.1, 390.6, 396.0, 401.4, 406.8, 409.8, 412.0, 414.3, 416.5, 437.6, 441.8, 446.0, 450.2, 454.4, 458.5, 462.7, 466.9, 471.1, 475.3, 479.5, 483.7, 487.9, 492.0, 496.2, 500.4, 504.6, 508.8, 513.0, 517.2, 521.3, 525.5, 529.7, 533.9, 538.1, 542.3, 607.5, 612.5, 617.5, 622.5, 627.6, 632.6, 637.6, 642.2, 646.6, 651.0, 655.5, 659.9, 664.4, 668.8, 673.2, 677.7, 682.1, 686.5, 691.0, 695.4, 699.9, 704.3, 708.7, 712.4, 715.9, 719.3, 722.8, 726.9]
y_data3=[1661870.0, 1662180.0, 1662330.0, 1662390.0, 1667640.0, 1672780.0, 1677880.0, 1682720.0, 1687830.0, 1692960.0, 1697780.0, 1702610.0, 1707020.0, 1711770.0, 1715340.0, 1715620.0, 1715620.0, 1715670.0, 1715700.0, 1715700.0, 1714460.0, 1706260.0, 1697080.0, 1696900.0, 1694770.0, 1689730.0, 1690880.0, 1691670.0, 1692840.0, 1692860.0, 1692860.0, 1691270.0, 1692140.0, 1693570.0, 1694640.0, 1695590.0, 1696470.0, 1697190.0, 1697790.0, 1698290.0, 1698730.0, 1699100.0, 1699380.0, 1699660.0, 1700020.0, 1700210.0, 1700560.0, 1700580.0, 1700580.0, 1700590.0, 1700590.0, 1700600.0, 1700600.0, 1700610.0, 1700610.0, 1700610.0, 1700610.0, 1700610.0, 1700610.0, 1700610.0, 1700610.0, 1700610.0, 1700610.0, 1700610.0, 1700560.0, 1700570.0, 1700920.0, 1701290.0, 1701890.0, 1702220.0, 1702250.0, 1702250.0, 1702250.0, 1702250.0, 1702190.0, 1702470.0, 1702650.0, 1702700.0, 1702700.0, 1702700.0, 1702700.0, 1702700.0, 1702700.0, 1702700.0]
x_data4=[18.4, 236.6, 245.0, 253.5, 261.9, 270.4, 278.8, 287.2, 295.6, 340.1, 342.0, 343.9, 345.8, 347.7, 349.6, 351.5, 353.4, 355.3, 357.2, 359.0, 360.9, 362.8, 364.7, 366.6, 368.5, 370.6, 372.8, 375.0, 378.4, 382.8, 387.2, 391.9, 397.3, 402.7, 408.1, 410.4, 412.6, 414.8, 417.1, 438.7, 442.8, 447.0, 451.2, 455.4, 459.6, 463.8, 468.0, 472.2, 476.3, 480.5, 484.7, 488.9, 493.1, 497.3, 501.5, 505.6, 509.8, 514.0, 518.2, 522.4, 526.6, 530.8, 534.9, 539.1, 543.3, 608.7, 613.8, 618.8, 623.8, 628.8, 633.8, 638.8, 643.3, 647.7, 652.1, 656.6, 661.0, 665.5, 669.9, 674.3, 678.8, 683.2, 687.7, 692.1, 696.5, 701.0, 705.4, 709.8, 713.3, 716.8, 720.2, 723.7, 840.1]
y_data4=[0.0124657, 0.012522, 0.0882, 0.1029, 0.1029, 0.0737, 0.0809, 0.0813, 0.0649, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.019607, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.149659, 0.158997, 0.1891, 0.1968, 0.1968, 0.1219, 0.1223, 0.0879, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.0193957, 0.1515, 0.1045, 0.0861, 0.0755, 0.0169167]
x_data5=[437.6, 441.8, 446.0, 450.2, 454.4, 458.5, 462.7, 466.9, 471.1, 475.3, 479.5, 483.7, 487.9, 492.0, 496.2, 500.4, 504.6, 508.8, 513.0, 517.2, 521.3, 525.5, 529.7, 533.9, 538.1, 542.3, 607.5, 612.5, 617.5, 622.5, 627.6, 632.6, 637.6, 642.2, 646.6, 651.0, 655.5, 659.9, 664.4, 668.8, 673.2, 677.7, 682.1, 686.5, 691.0, 695.4, 699.9, 704.3, 708.7, 712.4, 715.9, 719.3, 722.8, 726.9]
y_data5=[244.0, 244.0, 191.0, 191.0, 191.0, 191.0, 191.0, 191.0, 191.0, 191.0, 191.0, 191.0, 191.0, 191.0, 191.0, 191.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 160.0, 164.0, 164.0, 164.0, 164.0, 164.0, 164.0, 164.0, 164.0, 164.0, 164.0, 164.0, 164.0, 22.0, 22.0, 22.0, 22.0, 22.0, 22.0, 22.0, 22.0, 22.0]
x_data6=[437.6, 441.8, 446.0, 450.2, 454.4, 458.5, 462.7, 466.9, 471.1, 475.3, 479.5, 483.7, 487.9, 492.0, 496.2, 500.4, 504.6, 508.8, 513.0, 517.2, 521.3, 525.5, 529.7, 533.9, 538.1, 542.3, 607.5, 612.5, 617.5, 622.5, 627.6, 632.6, 637.6, 642.2, 646.6, 651.0, 655.5, 659.9, 664.4, 668.8, 673.2, 677.7, 682.1, 686.5, 691.0, 695.4, 699.9, 704.3, 708.7, 712.4, 715.9, 719.3, 722.8, 726.9]
y_data6=[949459.0, 949459.0, 804920.0, 607955.0, 465419.0, 357145.0, 273773.0, 201022.0, 147651.0, 108046.0, 77119.0, 53458.0, 36383.0, 25208.0, 17901.0, 16613.0, 893.0, 865.0, 853.0, 840.0, 829.0, 824.0, 819.0, 401.0, 398.0, 398.0, 398.0, 398.0, 398.0, 398.0, 398.0, 398.0, 398.0, 21560.0, 21762.0, 21762.0, 21741.0, 21740.0, 21738.0, 21662.0, 21654.0, 21695.0, 21736.0, 21739.0, 21739.0, 4865.0, 847.0, 204.0, 198.0, 198.0, 198.0, 198.0, 198.0, 198.0]
def make_patch_spines_invisible(ax):
    ax.set_frame_on(True)
    ax.patch.set_visible(False)
    for sp in ax.spines.values():
        sp.set_visible(False)

def patch_detached_spines(ax_list):
    for ax in ax_list:
        ax.set_frame_on(True)
    for ax in ax_list:
        ax.patch.set_visible(False)
    for ax in ax_list:
        for sp in ax.spines.values():
            sp.set_visible(False)
    for ax in ax_list:
        ax.spines['right'].set_visible(True)

def run_one_plot(x_data, y_data, fig, host, key, label, color_and_style, axis_offset, lines, detached_spine_plots):
    tkw = dict(size=4,width=1.5)
    if axis_offset > 0.8:
        plot = host.twinx()
    else:
        plot = host
    if axis_offset > 1.0:
        detached_spine_plots.append(plot)
    if key == 'TTT' or key == 'HHH':
        plot.set_yscale('log')
    if axis_offset > 1.0:
        plot.spines['right'].set_position(('axes', axis_offset))
        #make_patch_spines_invisible(plot)
        #plot.spines['right'].set_visible(True)
    p, = plot.plot(x_data, y_data, color_and_style, label=label)
    if axis_offset == 0.8:
        plot.set_ylabel(label)
    else:
        plot.text(axis_offset, 0, label, ha="left", va="top", rotation=90, transform=host.transAxes)
    lines.append(p)
    plot.yaxis.label.set_color(p.get_color())
    plot.tick_params(axis='y', colors=p.get_color(),**tkw)


fig, host = plt.subplots()
host.set_xlabel('Time (minutes)')
x_ticks = [18.366666666666667, 232.4, 295.8, 339.18333333333334, 376.1666666666667, 408.1166666666667, 417.65, 436.56666666666666, 544.3666666666667, 606.2333333333333, 641.05, 724.6666666666666]
x_labels = ['xxx_init@18.4', 'xx_yy@232.4', 'xxx_yyyyyy@295.8', 'setup_wwwwww@339.2', 'setup_rrrrr@376.2', 'setup_uuuuu@408.1', 'setup_oooo@417.6', 'mmmm_lllll@436.6', 'mmmm_kkkkkkk_jjjjj@544.4', 'ffffffff_dddddddd_sssss@606.2', 'ffffffff_sss_aaa@641.0', 'ffffffff_xxx_bbbbb@724.7']
plt.xticks(x_ticks,x_labels,rotation='vertical')
plt.tick_params(axis='x', which='both', labelsize = 6)
lines = []
detached_spine_plots = []
extra_axis_offset = 0.8

run_one_plot(x_data1, y_data1, fig, host, 'AAA', 'AAA', "b+", extra_axis_offset, lines, detached_spine_plots)
extra_axis_offset = 1.0

run_one_plot(x_data2, y_data2, fig, host, 'TTT', 'TTT', "rs", extra_axis_offset, lines, detached_spine_plots)
extra_axis_offset+=0.2

run_one_plot(x_data3, y_data3, fig, host, 'AAAA', 'AAAA', "g^", extra_axis_offset, lines, detached_spine_plots)
extra_axis_offset+=0.2

run_one_plot(x_data4, y_data4, fig, host, 'OOOOOOOOOOO', 'GGGGGGGGGG', "ko", extra_axis_offset, lines, detached_spine_plots)
extra_axis_offset+=0.2

run_one_plot(x_data5, y_data5, fig, host, 'WWW', 'WWW', "c.", extra_axis_offset, lines, detached_spine_plots)
extra_axis_offset+=0.2

run_one_plot(x_data6, y_data6, fig, host, 'HHH', 'HHH', "mx", extra_axis_offset, lines, detached_spine_plots)
extra_axis_offset+=0.2

host.legend(lines, [l.get_label() for l in lines])
#patch_detached_spines(detached_spine_plots)
fig.tight_layout(pad=0)
plt.show()
LMNCA
  • 21
  • 6
  • what happens if you remove tight_layout but instead save the figure using bbox_inches='tight'? also, please also post your code as a gist 'cause it's really hard to copy and paste accurately. – story645 Feb 18 '19 at 20:59
  • The only chance you currently have currently is to determine the spacing manually. In the easiest case, just add `fig.subplots_adjust(right=0.6)` between tight_layout and show and play with the number `0.6` until you're satisfied. – ImportanceOfBeingErnest Feb 18 '19 at 21:48
  • If I remove tight_layout and use bbox_inches='tight' (did it by adding fig.savefig('xx',bbox_inches='tight')) I still get only one axis drawn on the right. The 'subplot_adjust' scheme seems to work, and I can get rid of both bbox_inches='tight' and tight_layout workarounds in order to see the extra axes, so I will go with that, I think. – LMNCA Feb 19 '19 at 14:17
  • However, not wanting to be mean, but I am just applying the recipes you give me without any understanding of why and how it all works. Barring reading the implementation code, where can I find a good resource on how to control the relative layout of figure, axes and associated annotations, as well as any added padding ? – LMNCA Feb 19 '19 at 14:27
  • A lot of that sort of stuff is covered in https://matplotlib.org/tutorials/intermediate/tight_layout_guide.html#sphx-glr-tutorials-intermediate-tight-layout-guide-py – story645 Feb 19 '19 at 21:24

2 Answers2

0

Using anything that sets bbox_inches='tight', (including as an argument ot fig.savefig) generates the following figure: add

story645
  • 566
  • 3
  • 13
  • just updated with the image I got trying that. Like the image is still too cluttered, but like that's cause it needs a bigger figsize & custom/manual ticks. – story645 Feb 18 '19 at 23:49
  • 1
    You likely produced this image in jupyter and hence with the `bbox_inches="tight"` option activated, which means you should get the same image with `constrained_layout=False`, right? – ImportanceOfBeingErnest Feb 18 '19 at 23:51
  • I think there is even a very fundamental problem with constrained_layout in such a case where something is positionned in axes coordinates, because the axes size depends on the auxillary artist, which is positionned in axes coordinates and hence depends on the axes size. I imagine that resolving such circular restriction is close to impossible. – ImportanceOfBeingErnest Feb 18 '19 at 23:59
  • is there an open issue about that? – story645 Feb 19 '19 at 00:04
  • 1
    I don't think so, but [this comment](https://github.com/matplotlib/matplotlib/pull/13457#issuecomment-464771556) may be close to it. – ImportanceOfBeingErnest Feb 19 '19 at 00:08
  • My installed version of matplotlib does not have 'constrained_layout'. Unfortunately, I cannot change that easily because it's a corporate install, and upgrading it will require long weeks and a lot of paperwork. I tried with bbox_inches="tight" as suggested, but without constrained_layout, of course, and I am not seeing any padding of the left side anymore, but padding on the right-hand side is even bigger (more than 1/3 of the width). – LMNCA Feb 19 '19 at 14:04
0

What worked for me was to apply @ImportanceOfBeingErnest's suggestion of using fig.subplots_adjust(right=). My version of matplotlib does not seem to know anything about constrained_layout, so for me @story645's suggestion of combining that option with bbox_inches="tight" did not work.

LMNCA
  • 21
  • 6