Search code examples
pythonmatplotlibfunction-fitting

Jupyter Lab Plotting Issues: plt.scatter() works just fine, but plt.plot() won't plot


Newcomer to Jupyter Lab, Conda, and Matplotlib here.

So I'm running into the weirdest problem.

Here's the background: my program uses polyfit() to find a line of best fit for 30 randomly generated points. The points were randomly generated using a target function. I first used a polyfit line of degree 1 (just a line), and then I used a polyfit line of degree 3 to better approximate the target function using the randomly generated points. I got the random points generated, the target function, and the two polyfit functions to work just fine, and it even plotted in Jupyter Lab.

Here's the problem: After closing the .ipynb file that I was working on. I opened it back up using Ubuntu's file explorer (while the Jupyter Lab instance was still running). I made some changes to my program, and now it won't plot anymore. plt.scatter() still scatterplots just fine, but plt.plot() doesn't display the functions on my graph. I don't get any warning messages of any sort or any interpreter errors. Right now, I can see two possible causes:

  1. I messed up something when I closed the .ipynb file and reopened it in file explorer while Jupyter Lab instance was still running. Some poking around on here revealed that other users had vaguely similar problems, and the issues were caused by the environment not being linked anymore? I checked and my (base) Conda environment has matplotlib installed. This may or may not be the cause, but I figured it was worth mentioning to assist with troubleshooting.

  2. The second, and more mundane, reason is that I simply messed something up in my program (I am a relative beginner to Python, so this is entirely possible). I've tried to debug the program myself, but with no warning or error messages, it is hard to know where to start. My print() statements are showing the variables to be in the correct type (either as arrays/lists or floats).

Here is my program (it's an .ipynb file). All helpful suggestions are much appreciated. Thank you!

import numpy as np
import matplotlib.pyplot as plt
import random
import warnings

# warnings.filterwarnings("ignore")

def func(x): 
    return x**3 + 2 * x**2 - 5 * x - 6

def line(x):
    return slope * x + y_int

def third_poly(x):
    return poly_trans[0] * x**3 + poly_trans[1] * x**2 + poly_trans[2] * x + poly_trans[3]

num_of_data_points = 30

x = np.linspace(-4.0, 4.0)
x_values = []
y_values = []

for i in range(num_of_data_points):
    x = np.random.uniform(-4.0, 4.0)
    y = np.random.uniform(-2.0, 2.0)
    fx = func(x) + y
    plt.scatter(x, fx)
    x_values.append(x)
    y_values.append(fx)

lin_reg = np.polyfit(x_values, y_values, 1)
# lin_reg is an array of size 1x2, first element is the coefficient, second element is the y-int

poly_trans = np.polyfit(x_values, y_values, 3)

print(lin_reg)
print(lin_reg.shape)

print(poly_trans)
print(poly_trans.shape)

y_int = lin_reg.flat[1]
slope = np.delete(lin_reg, 1)

print(y_int)
print(y_int.shape)
print(slope)
print(slope.shape)

plt.plot(x, func(x), label = "Target function (f(x))")
plt.plot(x, line(x), label = "Line of best fit (g)")
plt.plot(x, third_poly(x), label = "3rd-Order Polynomial transformation (g')")
plt.legend(loc = "upper left")
plt.ylim(-45, 50)
plt.xlim(-5, 5)
plt.grid()
plt.show()

Here is the output: Output


Solution

  • You have a small semantic error, where you are plotting the functions with respect to x which is a single datapoint. You should plot them with x_values. Additionally, the plotting within the for loop is counter-productive, since this will be treating every new scatter plot as a new group (hence the different colours).

    Here's a better version:

    # Define the target function
    def targetFunction(x):  # Define the target function f(x)
        return x**3 + 2 * x**2 - 5 * x - 6
    
    # Define the line function
    def lineFunction(x, slope, yIntercept):  # Define the line function g(x)
        return slope * x + yIntercept
    
    # Define the third degree polynomial function
    def thirdPolyFunction(x, polyTransform):  # Define the 3rd degree polynomial function g'(x)
        return polyTransform[0] * x**3 + polyTransform[1] * x**2 + polyTransform[2] * x + polyTransform[3]
    
    # Generating data points
    numOfDataPoints = 30
    xValues = []  # Initialize list to store x values
    yValues = []  # Initialize list to store y values
    for i in range(numOfDataPoints):  # Loop for generating random data points
        x = np.random.uniform(-4.0, 4.0)  # Generate random x value within range
        y = np.random.uniform(-2.0, 2.0)  # Generate random y value within range
        fx = targetFunction(x) + y  # Compute y value based on target function and random noise
        xValues.append(x)  # Append x value to the list
        yValues.append(fx)  # Append y value to the list
    
    # Regression and sorting
    linReg = np.polyfit(xValues, yValues, 1)  # Perform linear regression
    yIntercept = linReg[1]  # Extract y-intercept from linear regression
    slope = linReg[0]  # Extract slope from linear regression
    polyTransform = np.polyfit(xValues, yValues, 3)  # Perform polynomial transformation
    sortedIndices = np.argsort(xValues)  # Get indices that would sort the x values
    sortedX = np.array(xValues)[sortedIndices]  # Sort x values in ascending order
    sortedY = np.array(yValues)[sortedIndices]  # Sort y values corresponding to sorted x values
    
    # Plotting
    plt.figure()
    plt.scatter(sortedX, sortedY)  # Plot the sorted data points
    plt.plot(sortedX, targetFunction(sortedX), label="Target function f(x)")  # Plot the target function
    plt.plot(sortedX, lineFunction(sortedX, slope, yIntercept), label="Line of best fit (g)")  # Plot the line of best fit
    plt.plot(sortedX, thirdPolyFunction(sortedX, polyTransform), label="3rd-Order Polynomial transformation (g')")  # Plot the polynomial transformation
    plt.legend(loc="upper left")  # Add legend to the plot
    plt.ylim(-45, 50)  # Set y-axis limits
    plt.xlim(-5, 5)  # Set x-axis limits
    plt.grid()  # Add grid lines to the plot
    plt.title("Data Points, Target Function, and Fitted Models")  # Add title to the plot
    

    Also, I can recommend using the following imports:

    import numpy as np
    %matplotlib notebook
    import matplotlib.pyplot as plt
    

    %matplotlib notebook is very nice since it enables interactive plotting. Hope this helps!

    The results:

    plot