cspecial
cspecial

Reputation: 89

How to create a new plot in a figure right below the first one after click event?

Given a matrix (list of lists)

A = [[1, 2, 3],
     [4, 6, 8],
     [9, 12, 15]]

and a list x = [1, 2, 3].

Each row j (0 <= j <= 2) of A consists of y-values so that 3 straight lines in total can be created in combination with x.

Now I want to plot these straight lines in the same plot with a special feature. If the user clicks on the graphic, an event handler should receive the x-position and create another plot right below the first one. This plot should be 1D and only visualise the data of the column in A whose index is given by the x-position.

Example: A click on x = 1 should plot [1 4 9], x = 2 should plot [2 6 12] and so on.

I have already tried to add a subplot using figure1.add_subplot(211) for the first plots and figure1.add_subplot(212) within the event handler and it also did not work.

A = [[1 2 3], [4 5 6], [7 8 9]]
x = [1 2 3]
figure1 = plt.figure()
plt.plot(x, A[0])
plt.plot(x, A[1])
plt.plot(x, A[2])

def onclick(event):
    Y = [A[i][int(event.xdata)] for i in range(0, 3)]
    plt.plot(Y)

figure1.canvas.mpl_connect('button_press_event', onclick)

Upvotes: 0

Views: 254

Answers (1)

gboffi
gboffi

Reputation: 25100

I have the following script that does what was asked for in the question:

  1. the callback function is heavily commented
  2. a key point is that the axis limits are not automatically updated, you can use ax.relim(); ax.autoscale_view() (aknowledgement, this comes from this answer from asmus) in the callback or fix suitable limits beforehand, as I have opted to do.

here it is the script:

import matplotlib.pyplot as plt
from matplotlib.lines import Line2D

def get_x(event):
    x = event.xdata
    # if you clic outside the graph, do nothing
    if x is None : return
    # from abscissa to column index
    i = int(round(x)-1)
    # update the line ordinates --- this is much faster than redrawing
    # the line, in this example it doesn't matter but possibly one
    # deals with larger data sets...
    line.set_ydata([row[i] for row in A])
    # we start with a clean subplot, if we haven't already placed a
    # line in it it's high time to do that
    if a2.lines == [] : a2.add_line(line)
    # eventually it's the moment of redrawing the whole figure
    fig.canvas.draw_idle()

# the data
A = [[1, 2, 3],
     [4, 5, 6],
     [7, 8, 9]]
x = [ 1, 2, 3]

# THE key issue is to set properly and in advance all the axes,
# hence the share{x,y}
f, (a1, a2) = plt.subplots(2, 1, sharex='col', sharey='col')
a1.grid(1), a2.grid(1)

# the first subplot, nitpick: adjust the y limits
a1.plot(x, list(zip(*A)))
a1.set_ylim(0, 10)

# prepare a line to be plotted in the second subplot
line = Line2D([1,2,3], [0,0,0], color='black')

# bind our callback and show the figure
f.canvas.mpl_connect('button_press_event', get_x)
plt.show()

the non-interactive figure

Upvotes: 1

Related Questions