'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:

  1. Get the coordinates of the peak of the distribution and convert to display coordinates.
  2. Define an inverse transform for the right axis
  3. 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