Which library can I use to draw interactive "coupled" plots in Python?

60 Views Asked by At

I am trying to make an interactive plot of two variables 'x' and 'y1', and for each value of 'y1' there is a plot of a 'x' vs a third quantity 'y2'. (For anyone interested, I'm building a binary phase diagram. 'x' is composition, 'y1' is temperature, and 'y2' is the Gibbs free energy. I have equations for x vs y2, which is used to calculate y1)

y1 is on the bottom and y2 for several y1s is plotted on the top:

img1

In the attached image, y1 is plotted in the figure on the bottom, and for each y1 there is a x vs y2 curve. I want to recreate this such that the x vs y2 plot is updated based on the position of cursor on the x vs y1 plot. I would have all of these values calculated and stored in an array so I need to be able to select the right data points depending on the temperature.

Is this possible to implement in Python using any commonly available libraries? Can someone point me in the right direction? If this can't be done in Python I am open to trying other tools.

Thanks in advance.

1

There are 1 best solutions below

0
Olivier Samson On

First, let's create a figure with two subplots and plot our first plot:

fig, (ax1, ax2) = plt.subplots(2,1)
... # add title and labels for ax1 and ax2
line = ax1.plot(<plot as you would normally do>)

Then we need to subscribe to a mouse event (motion_notify_event in our case for mouse mouvement) on our figure and handle it once it is fired. Let's create the handler first:

def mouse_mov_handler(event):
    if event.inaxes != ax1:
        return # return if not in first plot
    contains, details = line.contains(event)
    if contains: # if event occured "on" our x vs y1 line created before 
         update_ax2(details) # This will update our second plot 

This handler needs to be called when we detect mouse mouvement (mouse_notify_event) so set it up before calling plt.show() as such:

fig.canvas.mpl_connect('motion_notify_event', mouse_mov_handler)
plt.show()

Now, here is the update_ax2 method:

def update_ax2(details):
    x,y = line.get_data() # get all points (can be from your own data points to be optimal)
    selected_y1 = y[details['ind'][0]] # get y value with first element of dictionary of indices returned
    # redraw ax2 plot
    ax2.clear()
    new_data = XvsY2(selected_y1) # calculate new x vs y2 curve from selected y1
    ax2.plot(new_data)
    fig.canvas.draw()

Here is an example pretty close to what you want to have a better idea of how to set things up: https://matplotlib.org/stable/gallery/event_handling/data_browser.html#sphx-glr-gallery-event-handling-data-browser-py