2

I am working to a plot in matplotlib where multiple lines are represented by a single entry. In particular deselect or select multiple lines when picking a single legend entry; for clarity I started from the demo in matplotlib documentation (https://matplotlib.org/gallery/widgets/check_buttons.html and https://matplotlib.org/api/widgets_api.html#matplotlib.widgets.CheckButtons) and I just modified it a little:

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons

t = np.arange(0.0, 2.0, 0.01)
s0 = np.sin(2*np.pi*t)
s1 = np.sin(4*np.pi*t)
s2 = np.sin(6*np.pi*t)
s3 = 2*np.sin(4*np.pi*t)

fig, ax = plt.subplots()
l0, = ax.plot(t, s0, lw=2,c='r')
l1, = ax.plot(t, s1, lw=2,c='b')
l2, = ax.plot(t, s2, lw=2,c='g')
l3, = ax.plot(t, s3, lw=2,c='b')
plt.subplots_adjust(left=0.2)

rax = plt.axes([0.05, 0.4, 0.1, 0.15])
check = CheckButtons(rax, ('2 Hz', '4 Hz', '6 Hz'), (True, True, True))

#Define colours for rectangles and set them
c = ['r', 'b', 'g']    
[rec.set_facecolor(c[i]) for i, rec in enumerate(check.rectangles)]


def func(label):
    if label == '2 Hz':
        l0.set_visible(not l0.get_visible())
    elif label == '4 Hz':
        l1.set_visible(not l1.get_visible())
        l3.set_visible(not l3.get_visible())
    elif label == '6 Hz':
        l2.set_visible(not l2.get_visible())
    plt.draw()
check.on_clicked(func)

plt.show()

The output is this:

matplotlib_checkbuttons_example

I would like to solve two kind of problems:

  1. I don't know how to loop for creating the "lx," values (I have many lines to create and I don't want to write "l0," "l1," "l2," ... etc)
  2. I would like to having different appearence on checkbutton. In particular I would love to have a rectangle filled with line color when selected, and an empty rectangle (white background) when de-selected.

I tried finding for help in the documentation, but I'm a newbie and I am stuck at the moment. Could someone please help me?

Thank you

2 Answers 2

2

Thanks to the contribute of AILearning and ImportanceOfBeingErnest I solved the first question. For the second question I find a way to solve it by putting 0 line width at the check boxes and by activating or deactivating background colour only when the line is visible or not. The final answer is:

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

t = np.arange(0.0, 2.0, 0.01)
s0 = np.sin(2*np.pi*t)
s1 = np.sin(4*np.pi*t)
s2 = np.sin(6*np.pi*t)
s3 = 2*np.sin(4*np.pi*t)

fig, ax = plt.subplots()

l=[]
for si,c,label in zip([s0,s1,s2,s3],['r','b','g','b'],('2 Hz', '4 Hz', '6 Hz','4 Hz')):
    l.append(ax.plot(t, si, lw=2,c=c,label=label)[0])


plt.subplots_adjust(left=0.2)
labels = [str(line.get_label()) for line in l]



rax = plt.axes([0.05, 0.4, 0.1, 0.15])
check = CheckButtons(rax, ('2 Hz', '4 Hz', '6 Hz'), (True,True,True))

#Define colours for rectangles and set them
c = ['r', 'b', 'g']    
[rec.set_facecolor(c[i]) for i, rec in enumerate(check.rectangles)]
[ll.set_linewidth(0) for l in check.lines for ll in l]

def func(label):
    id_lab = [i for i, s in enumerate(check.labels) if label in s._text]
    for index,lab in enumerate(labels):
        if lab==label:
            l[index].set_visible(not l[index].get_visible())
            if (l[index].get_visible()):
                check.rectangles[id_lab[0]].set_fill(True)
            else:
                check.rectangles[id_lab[0]].set_fill(False)
    plt.draw()

check.on_clicked(func)

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

Comments

1

Try this!

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons[![enter image description here][1]][1]
from matplotlib.patches import Rectangle

t = np.arange(0.0, 2.0, 0.01)
s0 = np.sin(2*np.pi*t)
s1 = np.sin(4*np.pi*t)
s2 = np.sin(6*np.pi*t)
s3 = 2*np.sin(4*np.pi*t)

fig, ax = plt.subplots()

l=[]
for si,c,label in zip([s0,s1,s2,s3],['r','b','g','b'],('2 Hz', '4 Hz', '6 Hz','4 Hz')):
    l.append(ax.plot(t, si, lw=2,c=c,label=label)[0])


plt.subplots_adjust(left=0.2)
labels = [str(line.get_label()) for line in l]



rax = plt.axes([0.05, 0.4, 0.1, 0.15])
check = CheckButtons(rax, ('2 Hz', '4 Hz', '6 Hz'), (True,True,True))

#Define colours for rectangles and set them
c = ['r', 'b', 'g']    
[rec.set_facecolor(c[i]) for i, rec in enumerate(check.rectangles)]
[rec.set_fill(False) for i, rec in enumerate(check.rectangles)]



def func(label):
    for index,lab in enumerate(labels):
        if lab==label:
            l[index].set_visible(not l[index].get_visible())
            check.rectangles[index].set_fill(True)
        else:
            check.rectangles[index].set_fill(False)
    plt.draw()

check.on_clicked(func)

plt.show()

enter image description here

2 Comments

I think the problem is that there are two lines for 4Hz, but only one for 2Hz in the question.
The first question is now answered, thank you! For the second I think that there is something wrong, since trying toggling on/off the differente plots will result in a "funny" behaviour.

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.