'How to transform data from one axis coordinates to another axis with matplotlib
I am trying to plot a line that overlays several axes using matplotlib and transforms, but I cannot seem to get the transforms right. Here is the code:
# Define figure
fig = plt.figure(figsize=(7,3))
# Define colors
Lcolor="grey"
Pcolor=[0.8, 0.47058823529411764, 0.7372549019607844, 1.0]
MAPcolor = [0.00784313725490196, 0.6196078431372549, 0.45098039215686275, 1.0]
# Add gridspec for legend
gs0 = fig.add_gridspec(nrows=1, ncols=1, left=0, right=0.15, bottom=0.01,top=.85)
ax0 = fig.add_subplot(gs0[0])
# Add grid spec for data
gs1 = fig.add_gridspec(nrows=1, ncols=1, left=0.25, right=.8,bottom=0.01,top=gs0.top)
ax1 = fig.add_subplot(gs1[0])
ax1.set_ylim(-.5,1.5)
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)
ax1.set_xlabel("Position",fontweight="bold")
ax1.set_ylabel("Position",fontweight="bold")
# Add gridspec for legend plot
gs2 = fig.add_gridspec(nrows=1, ncols=1, left=gs1.left, right=gs1.right, bottom=gs1.top+0.05,top=1)#,hspace=.25)
ax2 = fig.add_subplot(gs2[0])
# Define prior
xx = np.linspace(-.5, 1.5, 100)
prior = norm.pdf(xx, 0.5, .35)
ax0.plot(prior,xx,color="dodgerblue")
ax0.set_ylim(-.75,1.75)
ax0.xaxis.set_visible(False)
ax0.spines['bottom'].set_visible(False)
ax0.spines['top'].set_visible(False)
ax0.spines['right'].set_visible(False)
ax0.set_title("Prior belief",fontstyle="italic",color="dodgerblue",fontsize=10)
#### AXIS 2
plt.sca(ax1)
ax1.set_xlim(0,1.2)
nn=6
gs1_1 = fig.add_gridspec(nrows=1, ncols=nn, left=gs1.left, right=gs1.right, bottom=gs1.bottom,top=gs1.top)#,hspace=.25)
ax1_1 = []
xvals=np.linspace(0,1,nn)
for cnt,xval in enumerate(xvals):
# Store axis
ax1_1.append(fig.add_subplot(gs1_1[cnt],facecolor=None))
# Generate likelihood and posterior
_L = norm.pdf(xx, xval, 0.1)
_P = np.multiply(_L,prior)
# Plot distributions
ax1_1[cnt].plot(prior,xx,color="dodgerblue",zorder=3)
ax1_1[cnt].plot(_L,xx,color=Lcolor,zorder=3)
ax1_1[cnt].plot(_P,xx,color=Pcolor,zorder=4)
ax1_1[cnt].axvline(x=0,color="darkgrey",linestyle="--")
ax1_1[cnt].set_ylim(-.5,1.5)
ax1_1[cnt].set_axis_off()
# Plot MAP and adjust axis
ax1_1[cnt].scatter(_P.max(),xx[_P.argmax()],color=MAPcolor,s=30,clip_on=False)
xlims = ax1_1[cnt].get_xlim()
ax1_1[cnt].set_xlim(0,np.maximum(_P.max(),_L.max())+.25)
# Add axis on right side
ax1_r=ax1.twinx()
ax1_r.set_ylim(-.5,1.5)
ax1_r.set_ylabel("Error Predicted",color=MAPcolor,fontweight="bold",rotation=270)
ax1_r.tick_params(axis='y', colors=MAPcolor)
# Generate custom legend
colors=["dodgerblue",Lcolor,Pcolor,MAPcolor]
labels=["Prior","Likelihood","Posterior","Prediction (MAP)"]
for clr,lab in zip(colors,labels):
ax2.plot([], [], color=clr,alpha=1, label=lab)
leg = ax2.legend(loc="upper center",frameon=False,ncol=4,fontsize=10)
ax2.set_frame_on(False)
ax2.yaxis.set_visible(False)
ax2.xaxis.set_visible(False)
for (text,clr) in zip(leg.get_texts(),colors):
text.set_color(clr)
plt.show()
Here is the image: https://i.stack.imgur.com/dWGEP.png (I am unable to post inline)
Here is what I have tried so far:
- Get the coordinates of the peak of the distribution and convert to display coordinates.
- Define an inverse transform for the right axis
- Apply transform to data and plot
So in the for loop:
for cnt,xval in enumerate(xvals):
...
temp=ax1_1[cnt].transData.transform((_P.max(),xx[_P.argmax()]))
invax = ax1_r.transData.inverted()
out = invax.transform(temp)
ax1_r.scatter(out[0],out[1],s=100)
...
In theory, I can then append the values to a list and then just fit a line to the points. I can't quite figure out the proper order of transformations to get from the subplots in ax1_1 to the bigger axis ax1_r
Thanks for the help.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
