"ValueError: x and y must be the same size" when plotting
Question:
I’m writing a python code that implements euler’s method to solve a 1st order ODE for an arbitrary range of values of time-step h
.
The simplest solution I’ve come up with is to declare a Python list to store the results at the end of the ‘outer for’ loop:
y = []
for h in (0.05, 0.1, 0.2):
t = np.arange(0, 5 + h, h) ## Time-steps as np array
N = np.zeros(len(t)) ## Initialize number of U^{235} nuclei array.
N[0] = N_0
## Implementation of Euler's method, first-order case. One 'for' loop suffices.
for i in range(0, len(t) - 1):
N[i+1] = N[i] * (1.0 - h/tau)
y.append(t) ## Store results in python list. Each element is an array
## with the corresponding value of h
Then I tried to plot the results for h = 0.05
, that are stored in y[0]
, as x-axis:
plt.scatter(y[0], N, marker='o', facecolors='none', s=60, lw=2)
But this returns the error "ValueError: x and y must be the same size"
I don’t understand why I’m getting size error. Isn’t y[0]
an one-dimensional list? So i can’t use a list as an axis for a plot?
I’m confused because it WORKS with the variable t as it is a np.array:
t = np.arange(0, 5 + h, h) ## Time-steps as np array
N = np.zeros(len(t)) ## Initialize number of U^{235} nuclei array.
N[0] = N_0
## Implementation of Euler's method, first-order case. One 'for' loop suffices.
for i in range(0, len(t) - 1):
N[i+1] = N[i] * (1.0 - h/tau)
plt.scatter(t, N, marker='o', facecolors='none', s=60, lw=2)
Answers:
You are not storing the various N
arrays in a list, so you are trying to plot t
from the first iteration (i.e. y[0]
) and N
from the last iteration.
If you store everything in a dictionary, you can store the time and the number of nuclei as a value and the time increment h
as a key:
# Imports.
import matplotlib.pyplot as plt
import numpy as np
# Constants.
N_0 = 1000
TAU = 5
TIME_INCREMENTS = (0.05, 0.1, 0.2)
data = {}
for h in TIME_INCREMENTS :
t = np.arange(0, 5 + h, h) # Time-steps as np array.
N = np.zeros(len(t)) # Initialize number of U^{235} nuclei array.
N[0] = N_0
# Implementation of Euler's method, first-order case. One 'for' loop suffices.
for i in range(0, len(t) - 1):
N[i+1] = N[i] * (1.0 - h/TAU)
data[h] = (t, N)
fig, ax = plt.subplots()
for key, values in data.items():
ax.scatter(*values, marker='o', s=60, lw=2, label=f"h = {key:.2f}")
ax.legend()
When you use numpy, you want to avoid loop for performance reasons (say if you have 1M of time increments). We could turn this:
N = np.zeros(len(t))
N[0] = N_0
for i in range(0, len(t) - 1):
N[i+1] = N[i] * (1.0 - h/TAU)
Into this:
N = N_0 * (1.0 - h/TAU)**np.arange(len(t))
I’m writing a python code that implements euler’s method to solve a 1st order ODE for an arbitrary range of values of time-step h
.
The simplest solution I’ve come up with is to declare a Python list to store the results at the end of the ‘outer for’ loop:
y = []
for h in (0.05, 0.1, 0.2):
t = np.arange(0, 5 + h, h) ## Time-steps as np array
N = np.zeros(len(t)) ## Initialize number of U^{235} nuclei array.
N[0] = N_0
## Implementation of Euler's method, first-order case. One 'for' loop suffices.
for i in range(0, len(t) - 1):
N[i+1] = N[i] * (1.0 - h/tau)
y.append(t) ## Store results in python list. Each element is an array
## with the corresponding value of h
Then I tried to plot the results for h = 0.05
, that are stored in y[0]
, as x-axis:
plt.scatter(y[0], N, marker='o', facecolors='none', s=60, lw=2)
But this returns the error "ValueError: x and y must be the same size"
I don’t understand why I’m getting size error. Isn’t y[0]
an one-dimensional list? So i can’t use a list as an axis for a plot?
I’m confused because it WORKS with the variable t as it is a np.array:
t = np.arange(0, 5 + h, h) ## Time-steps as np array
N = np.zeros(len(t)) ## Initialize number of U^{235} nuclei array.
N[0] = N_0
## Implementation of Euler's method, first-order case. One 'for' loop suffices.
for i in range(0, len(t) - 1):
N[i+1] = N[i] * (1.0 - h/tau)
plt.scatter(t, N, marker='o', facecolors='none', s=60, lw=2)
You are not storing the various N
arrays in a list, so you are trying to plot t
from the first iteration (i.e. y[0]
) and N
from the last iteration.
If you store everything in a dictionary, you can store the time and the number of nuclei as a value and the time increment h
as a key:
# Imports.
import matplotlib.pyplot as plt
import numpy as np
# Constants.
N_0 = 1000
TAU = 5
TIME_INCREMENTS = (0.05, 0.1, 0.2)
data = {}
for h in TIME_INCREMENTS :
t = np.arange(0, 5 + h, h) # Time-steps as np array.
N = np.zeros(len(t)) # Initialize number of U^{235} nuclei array.
N[0] = N_0
# Implementation of Euler's method, first-order case. One 'for' loop suffices.
for i in range(0, len(t) - 1):
N[i+1] = N[i] * (1.0 - h/TAU)
data[h] = (t, N)
fig, ax = plt.subplots()
for key, values in data.items():
ax.scatter(*values, marker='o', s=60, lw=2, label=f"h = {key:.2f}")
ax.legend()
When you use numpy, you want to avoid loop for performance reasons (say if you have 1M of time increments). We could turn this:
N = np.zeros(len(t))
N[0] = N_0
for i in range(0, len(t) - 1):
N[i+1] = N[i] * (1.0 - h/TAU)
Into this:
N = N_0 * (1.0 - h/TAU)**np.arange(len(t))