Issue
We have a code that creates figures from input.txt files. We need to combine 2 of these figures in a single subplot. The data from figure1 will be plotted in the left subplot and from figure2 in the right subplot, sharing the same legend and witht he same scale in axes x and y:
Here there is some example data:
x = [ 1, 2, 3, 5, 10, 100, 1000 ]
y1 = [ 1, 0.822, 0.763, 0.715, 0.680, 0.648, 0.645 ]
y2 = [ 1, 0.859, 0.812, 0.774, 0.746, 0.721, 0.718 ]
import matplotlib.pyplot as plt
# mode 01 from one case
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.plot( x, y1, label='mode 01' )
# mode 01 from other case
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.plot( x, y2, label='mode 01' )
EDIT: the method suggested by @nordev works. Now it would be really convenient to pass the ax1 and ax2 objects to the new figure, since they have much more information. It seems that there is no straightforward way to achieve that.
The real case has been made available here. To make it work, please run plot_both.py
.
EDIT2: it was easier to change the routine that reads the input.txt files. Now it supports multiple plots. But the question is still valid because it would be great to treat the AxesSubplot
as an easily interchangeable object among different figures, subplots and so forth...
Solution
Does this solve your problem?
x = [ 1, 2, 3, 5, 10, 100, 1000 ]
y1 = [ 1, 0.822, 0.763, 0.715, 0.680, 0.648, 0.645 ]
y2 = [ 1, 0.859, 0.812, 0.774, 0.746, 0.721, 0.718 ]
import matplotlib.pyplot as plt
from matplotlib.transforms import BlendedGenericTransform
# mode 01 from one case
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
line1, = ax1.plot( x, y1, label='mode 01' )
# mode 01 from other case
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
line2, = ax2.plot( x, y2, label='mode 01' )
# Create new figure and two subplots, sharing both axes
fig3, (ax3, ax4) = plt.subplots(1,2,sharey=True, sharex=True,figsize=(10,5))
# Plot data from fig1 and fig2
line3, = ax3.plot(line1.get_data()[0], line1.get_data()[1])
line4, = ax4.plot(line2.get_data()[0], line2.get_data()[1])
# If possible (easy access to plotting data) use
# ax3.plot(x, y1)
# ax4.lpot(x, y2)
ax3.set_ylabel('y-axis')
ax3.grid(True)
ax4.grid(True)
# Add legend
fig3.legend((line3, line4),
('label 3', 'label 4'),
loc = 'upper center',
bbox_to_anchor = [0.5, -0.05],
bbox_transform = BlendedGenericTransform(fig3.transFigure, ax3.transAxes))
# Make space for the legend beneath the subplots
plt.subplots_adjust(bottom = 0.2)
# Show only fig3
fig3.show()
This gives output as seen below
Edit
Looking at the code in your uploaded zip-file, I'd say most of the requested functionality is achieved?
I see you have changed the function creating the plots, making the solution to your problem radically different, as you are no longer trying to "merge" two subplots from different figures. Your solution is basically the same as the one I presented above, in the sense that both are creating both Axes
instances as subplots on the same figure (giving the desired layout), and then plotting, rather than plotting, then extract/move the axes, as your question was concerning originally.
As I suspected, the easiest and most trivial solution is to make the individual Axes
subplots of the same figure instead of having them tied to separate figures, as moving one Axes
instance from one Figure
to another is not easily accomplished (if at all possible), as specified in a comment. The "original" problem still seems to be very hard to accomplish, as simply adding an Axes
instance to the Figure
's _axstack
makes it hard to customize to the desired layout.
One modification to the ax.legend(...
of your current code, to make the legend centered horizontally, with the top just below the axes:
# Add this line
from matplotlib.transforms import BlendedGenericTransform
# Edit the function call to use the BlendedGenericTransform
ax.legend(loc='upper center',
ncol=7,
labelspacing=-0.7,
columnspacing=0.75,
fontsize=8,
handlelength=2.6,
markerscale=0.75,
bbox_to_anchor=(0.5, -0.05),
bbox_transform=BlendedGenericTransform(fig.transFigure, ax.transAxes))
Here, the bbox_to_anchor
argument should be customized to fit within the boundaries of our figure.
The BlendedGenericTransform
allows the transforms of the x-axis and y-axis to be different, which can be very useful in many situations.
Answered By - sodd
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.