Search code examples
python-3.xnumpytkinterpiecewise

Piecewise functions


I'm fairly new to python and would like to know why I can't graph a piecewise function like below, and why the error message is popping up?

def get_data(self, frame):
    self.ydata =np.piecewise(self.xdata, [self.xdata<.2, self.xdata>=.2][ np.sin((self.frequency) * self.xdata +
                                                                frame), np.sin((5*self.frequency) * self.xdata + frame)])

It says my error is

  line 72, in get_data
    frame), np.sin((5*self.frequency) * self.xdata + frame)])
TypeError: list indices must be integers or slices, not tuple

I guess my question can also be what would I bind the piecewise function to? This is an animation and I'm doing this piecewise for a variable for my second go at it, but I don't know what i should put as 'x' if I'm wanting x<.2 because my x values are in an arange set-up.


Solution

  • I'm not sure what self is in the question. My code below works as a function but can be changed to a method if required.

    Your error message is caused by there not being a comma between the condition list and the function list.

    def get_data(self, frame):        
        self.ydata =np.piecewise(self.xdata, [self.xdata<.2, self.xdata>=.2]  # Must be a comma here
            [ np.sin((self.frequency) * self.xdata + frame), 
              np.sin((5*self.frequency) * self.xdata + frame) ] )
    

    Another problem is that the function lists must be functions, not the result of functions.

    import numpy as np    
    
    def get_data(xdata, frame):
        def f_lt(x):
            return np.sin( frequency * x + frame)
    
        def f_ge(x):                                                                                              
            return np.sin( 5*frequency * x + frame)  
    
        return np.piecewise(xdata, [xdata<.2, xdata>=.2], [ f_lt, f_ge ])
    
    frequency = 1.0
    
    xdata = np.arange(1,26)/25
    get_data(xdata, 0.1) 
    # array([ 0.13954311,  0.17902957,  0.21822962,  0.25708055,  0.89120736,
    #         0.96355819,  0.99749499,  0.99166481,  0.94630009,  0.86320937,
    #         0.74570521,  0.59847214,  0.42737988,  0.23924933,  0.04158066,
    #        -0.15774569, -0.35078323, -0.52983614, -0.68776616, -0.81827711,
    #        -0.91616594, -0.97753012, -0.99992326, -0.98245261, -0.92581468])
    

    I'm not sure what you're trying to do so I can't test the result but perhaps this helps.

    Edit: Response to a comment.

    get_data(x, frame) can be called as often as required.

    It may be better to expand the params list to make it more flexible. It really depends on what you're trying to do.

    def get_data(xdata, frame, frequency, step_point=0.2 ):
        def f_lt(x):
            return np.sin( frequency * x + frame)
    
        def f_ge(x):                                                                                              
            return np.sin( 5*frequency * x + frame)  
    
        return np.piecewise(xdata, 
                           [xdata<step_point, xdata>=step_point],
                           [ f_lt, f_ge ])
    

    None of the parameters in the function are now hardcoded. They can all be set each time the function is called.

    for frame in range(100):
        frame = frame / 100
        y = get_data(xdata, frame, frequency, 0.2)
        do_plot(xdata, y)
    

    Does this answer your comment?