Search code examples
pythonmatplotlibglobalnameerror

Why do I get NameError: global name 'phase' is not defined


I'm trying to add some interactivity to the plots, that is, a left-click should delete a data point in the plot and a right-lick should restore the deleted data points in reverse order. Here's the relevant excerpt from my Python script:

def plot_folded_light_curve(best_frequency, method):
    x_time = np.asarray(x_period)
    phase = (x_time * best_frequency) % 1

    fig, ax = plt.subplots(figsize=(8, 6))
    plt.subplots_adjust(left=0.25, bottom=0.25)

    blue_scatter = plt.scatter(phase, y_m0, color="blue", picker=10)

    # delete data points in the raw light curve plot by left-clicks
    def pick_handler(event):
        global phase
        if event.mouseevent.button==1:
            ind = event.ind
            print "Deleting data point:", ind[0], np.take(phase, ind[0]), np.take(y_m0, ind[0])
            deleted_phase.append(phase[ind[0]])
            phase_index.append(ind[0])
            phase = np.delete(phase, [ind[0]])
            deleted_y_m0.append(y_brightness[ind[0]])
            y_m0_index.append(ind[0])
            del y_m0[ind[0]]
            deleted_blocks_items.append(sorted(blocks[blocks.keys()[0]].items())[ind[0]])
            del blocks[blocks.keys()[0]][sorted(block)[ind[0]]]
            blue_scatter.set_offsets(phase,y_m0)
            fig.canvas.draw()

    # restore data points in the raw light curve plot by right-clicks
    def click_handler(event):
        global phase
        if event.button == 3:
            if len(deleted_phase) > 0:
                print "Restoring data point:", phase_index[-1], deleted_phase[-1], deleted_y_m0[-1]
                phase = np.insert(phase, phase_index.pop(), deleted_phase.pop())
                y_m0.insert(y_m0_index.pop(), deleted_y_m0.pop())
                blocks[blocks.keys()[0]].update([deleted_blocks_items[-1]])
                deleted_blocks_items.pop()
                blue_scatter.set_offsets(np.c_[phase,y_m0])
                fig.canvas.draw()
            else:
                print "No deleted data points left!"

    fig.canvas.mpl_connect('pick_event', pick_handler)
    fig.canvas.mpl_connect('button_press_event', click_handler)

When I run the script and when it comes to the call of function pick_handler() I get an error message:

  File "/usr/local/bin/apex_geo_lightcurve.py", line 624, in pick_handler
    print "Deleting data point:", ind[0], np.take(phase, ind[0]), np.take(y_m0, ind[0])
NameError: global name 'phase' is not defined

I don't understand why is it not defined? What am I doing wrong? Could someone help me there?

This runnable test script worked fine, though:

import numpy as np
import matplotlib.pyplot as plt

x = np.asarray([1, 3, 5])
y = [2, 4, 6]

deleted_x = []
deleted_y = []
x_index= []
y_index= []

# delete data points in the raw light curve plot by left-clicks
def pick_handler(event):
    global x
    if event.mouseevent.button==1:
        ind = event.ind
        print ind
        print "Deleting data point:", ind[0], np.take(x, ind[0]), np.take(y, ind[0])
        deleted_x.append(x[ind[0]])
        x_index.append(ind[0])
        x = np.delete(x, [ind[0]])
        deleted_y.append(y[ind[0]])
        y_index.append(ind[0])
        del y[ind[0]]
        blue_scatter.set_offsets(np.c_[x, y])
        fig.canvas.draw()

# restore data points in the raw light curve plot by right-clicks
def click_handler(event):
    global x
    if event.button == 3:
        if len(deleted_x) > 0:
            print "Restoring data point:", x_index[-1], deleted_x[-1], deleted_y[-1]
            x = np.insert(x, x_index.pop(), deleted_x.pop())
            y.insert(y_index.pop(), deleted_y.pop())
            blue_scatter.set_offsets(np.c_[x, y])
            fig.canvas.draw()
        else:
            print "No deleted data points left!"

fig, ax = plt.subplots()
blue_scatter = plt.scatter(x, y, color="blue", picker=10)
fig.canvas.mpl_connect('pick_event', pick_handler)
fig.canvas.mpl_connect('button_press_event', click_handler)
plt.show()

By the way, if I understand it right, I should be able to use the whole thing without globals, if I simply pass phase during the function call, but I dont know how to do that correctly in this case.


Solution

  • Are you running Python 3? Try using nonlocal phase instead of global phase.

    The problem is that your definition of phase isn't "global", it's defined inside a function definition that happens to surrounds me. global doesn't mean "defined somewhere outside of me". It really means "defined in the global scope".

    Alternatively, you could add global phase to plot_folded_light_curve. This works in both Python2 and Python3. It forces all the occurrences of phase to be global.