L. Winchler
L. Winchler

Reputation: 101

Matplotlib and checkbuttons customization

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

Upvotes: 2

Views: 2039

Answers (2)

L. Winchler
L. Winchler

Reputation: 101

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()

Upvotes: 2

Venkatachalam
Venkatachalam

Reputation: 16966

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

Upvotes: 1

Related Questions