Finally figured this one out. The jumping around behavior and inconsistent pixel sizes both seem to come from a bug in how the automargins are calculated. These are set to True by default, so we need to explicitly set automargin=False for both axes. Then we need to manually specify how much space is needed for the labels in the margin dictionary, e.g. margin=dict(t=100, b=0, l=80, r=0). We also need to pad with these numbers when calculating the overall figure size, e.g. height = 100 + cut * 30.