I want to have the shared legend of multiple subplots take the width of the plot areas of the subplots. Here is an illustration: Here's what I tried / a minimum reproducible example of what I expect should work based on the documentation: import matplotlib.pyplot as plt fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(7, 4), layout="constrained") # plot some dummy data x = [1, 2, 3, 4, 5] y1 = [1, 2, 3, 4, 5] y2 = [5, 4, 3, 2, 1] axes[0].plot(x, y1, label="Line 1") axes[1].plot(x, y1, label="Line 1") axes[1].plot(x, y2, label="Line 2") def find_ideal_bbox(axes): # Use the box that spans the combined plot width (excluding figure side margins) # Collect axes positions in figure coordinates positions = [ax.get_position() for ax in axes] if positions: x0 = min(p.xmin for p in positions) x1 = max(p.xmax for p in positions) # Full vertical extent (0->1) so outside locations can align horizontally; # width restricted to the subplot grid width. return (x0, 0.0, x1 - x0, 1.0) return None # Collect all handles and labels from all axes handles, labels = [], [] for ax in axes: h, label_list = ax.get_legend_handles_labels() for handle, label in zip(h, label_list): if label not in labels: # Avoid duplicates handles.append(handle) labels.append(label) # add one legend for both axes fig.legend( handles, labels, loc="outside upper center", ncol=2, bbox_to_anchor=find_ideal_bbox(axes), mode="expand", borderaxespad=-1, # move it outside the figure columnspacing=1.0, # Reduce space between columns (default is 2.0) handletextpad=0.4, # Reduce space between symbol and text (default is 0.8) ) # finally, save the figure in three different sizes widths = [None, 3.16, 4.21] # make sure they have the same aspect ratio original_size = fig.get_size_inches() aspect_ratio = original_size[1] / original_size[0] for w in widths: if w is not None: fig.set_size_inches(w, w * aspect_ratio) # re-set the legend size fig.legends[0].set_bbox_to_anchor(find_ideal_bbox(axes)) fig.savefig( f"mvr_figure_{w}.png" if w is not None else "mvr_figure.png", bbox_inches="tight", ) Here's what this results in: As can bee seen in these examples, the legend is too wide in all cases, and is always slightly too much to the left. Note the layout="constrained" – without this, the opposite can be observed, the legend is always a bit too long to the right. The strangest thing to me is that I can debug the find_ideal_bbox method by simply using fig.text() on the coordinates that are found, and the text is placed where I expect it to. What am I missing? Why are the legends not using the bbox I tell them to? Continue reading...