0

I'm making an interface, where I have have some "clear this" and "clear that" buttons to remove various elements of a plot.

The problem with matplotlib is that I have to know the exact order the objects were plotted in to remove the correct one with ax.lines.pop(). For example, a plot could contain raw data, then a smoothed version, and then a fit on top, but depending on the order these were called, ax.lines.pop(2) would remove either the blue or the red line.

But how can I consistently remove e.g. the red line in a multi-layered scenario?

enter image description here

import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import medfilt

a = np.random.normal(0, 1, 100)
b = medfilt(a, 17)

fig1, axes = plt.subplots(ncols = 2)

ax1, ax2 = axes

ax1.set_title("Figure 1")
ax1.plot(a, color = "darkgrey")  # 0
ax1.plot(b, color = "firebrick") # 1
ax1.axhline(0.5, color = "blue") # 2

ax1.lines.pop(2)

ax2.set_title("Figure 2")
ax2.plot(a, color = "darkgrey")  # 0
ax2.axhline(0.5, color = "blue") # 2
ax2.plot(b, color = "firebrick") # 1

ax2.lines.pop(2)

plt.show()

1 Answer 1

1

For clarity and simplicity of exposition, the following example draws a single graph, and rather than delete the line, it toggles its visibility. Notice that two of the lines are labelled explicitly, the third has a label assigned to it by default. We use those labels to index our way to the line.

If you really want to delete the line, just replace the call to set_visible() with your call to pop(), c.f. ax.lines.pop(n).

import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons

import numpy as np
from scipy.signal import medfilt

a = np.random.normal(0, 1, 100)
b = medfilt(a, 17)

fig = plt.figure()
ax  = fig.add_subplot(1,1,1)

# Create a graph with two curves, and save the lines
ax.set_title("Figure 1")
ax.plot(a, label='a', color = "darkgrey")  # 0
ax.plot(b, label='b', color = "firebrick") # 1
ax.axhline(0.5, color = "blue") # 2

# Show the labels
plt.legend()

# Labels and initial states for buttons
labels = []
states = []
for l in ax.lines:
    labels.append( l.get_label() )
    states.append( l.get_visible() )

# Add a box with checkbuttons
plt.subplots_adjust(right=0.8)
bx = plt.axes( [0.85,0.4,0.1,0.15] )
cb = CheckButtons( bx, labels, states )

# Function to toggle visibility of each line
def toggle( label ):
    n = labels.index(label)
    ax.lines[ n ].set_visible( not ax.lines[ n ].get_visible() )
    plt.draw()

# Connect the function to the buttons
cb.on_clicked( toggle )

# And start the show
plt.show()
Sign up to request clarification or add additional context in comments.

2 Comments

That's great! All you really need then is to label lines accordingly and then toggle visibility with n = labels.index("a"); ax.lines[n].set_visible(not ax.lines[n].get_visible())
Happy that you like it. Thank you. I plotted the third line without specifying a label to show how to use its default label in case that might be useful also.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.