Search code examples
pythonmatplotlibcheckboxtext

How to turn on/off all ax.text plotted through a checkbox?


it's my first question here!. I'm new at Python and I am focusing my learning programming simplest tasks I had already scripted in MatLab some time ago so I can compare and be sure my python scripting is working. I've not been able to do one simple thing: I can do that plotted points turn off/on in plot through a checkbox, but I've not been able to do the same thing with text plotted as labels related to those points. I can see the problem is that ax.text is called/assigned to line2 on a For loop, and then it's only taking the last assigned ax.text. This has an easy solution in Matlab that it should be to store every ax.text on a cell and then call it like a cell to turn it off/on. I've been searching the same thing on python and no luck till now. Any suggestions or readings will be much appreciated ... thanks !

x = np.random.randint(1,10,10)
y = np.random.randint(1,10,10)
z = np.random.randint(1,10,10)

tag = np.ones(len(x)).astype(str)

fig = plt.figure(figsize=(12,9))
ax = fig.add_subplot(1,1,1, projection='3d')

line1 = ax.scatter(x,y,z,'o',visible = True)

for sid, x, y, z in zip(tag, x, y, z):

    line2 = ax.text(x+0.01*x, y, z, sid, None, visible = True)

lines =  [line1, line2]
rax = plt.axes([0.8, 0.05, 0.1, 0.15])
labels = ['DOTS','TEXT']
visibility = [True,True]
check = CheckButtons(rax, labels, visibility)


def func(label):
    index = labels.index(label)
    lines[index].set_visible(not lines[index].get_visible())
    plt.draw()


check.on_clicked(func)

plt.show()

embed image


Solution

  • As you're mentioning, line2 has only the last text info. There seems no way annotate multiple texts in a time. So just use for loop to change with every button push. This code works. Note that I used dic to make unknown numbers of points, it might be tricky.

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.widgets import CheckButtons
    from mpl_toolkits.mplot3d import Axes3D
    
    
    def func(label):
        index = labels.index(label)
        if index == 0:
            lines[index].set_visible(not lines[index].get_visible())
        elif index == 1:
            for i in dic:  # change text one by one
                dic[i].set_visible(not dic[i].get_visible())
        plt.draw()
    
    
    x = np.random.randint(1, 10, 10)
    y = np.random.randint(1, 10, 10)
    z = np.random.randint(1, 10, 10)
    
    tag = np.ones(len(x)).astype(str)
    
    fig = plt.figure(figsize=(12, 9))
    ax = fig.add_subplot(1, 1, 1, projection="3d")
    
    line1 = ax.scatter(x, y, z, "o", visible=True)
    
    # make a variable with a name in every iteration
    # and plot text first time
    dic = {}
    for num, sid, x, y, z in zip(range(len(tag)), tag, x, y, z):
        dic["var{0}".format(num)] = ax.text(x + 0.01 * x, y, z, sid, None, visible=True)
    
    lines = [line1]  # dropped line2
    rax = plt.axes([0.8, 0.05, 0.1, 0.15])
    labels = ["DOTS", "TEXT"]
    visibility = [True, True]
    check = CheckButtons(rax, labels, visibility)
    
    check.on_clicked(func)
    
    plt.show()