This is my code, and I get the following error:
ValueError: NumPy boolean array indexing assignment cannot assign 100 input values to the 90 output values where the mask is true. The error is on the line assigning a value for V.
What am I doing wrong?
from pylab import *
import numpy as np
from math import *
r = np.linspace(0, 10, 100)
V = np.piecewise(r, [r < 1, r > 1 ], [1, (r/2)*(3 - (r**2))])
#Graph of V r / k q vs. r/R for unitless quantities
figure()
plot(r, V)
xlabel('r / R')
ylabel('V r / k q')
title('Behavior of V(r) vs r')
ax = plt.gca()
ax.set_xticks([1])
ax.set_xticklabels(['R'])
plt.tick_params(left = False, right = False , labelleft = False)
grid()
show()
CodePudding user response:
Did you wanted something like this?
r = np.linspace(1, 10, 100)
V = np.piecewise(r, [r < 1, r > 0 ], [1, (r/2)*(3 - (r**2))])
#Graph of V r / k q vs. r/R for unitless quantities
figure()
plt.plot(r, V)
plt.xlabel('r / R')
plt.ylabel('V r / k q')
plt.title('Behavior of V(r) vs r')
ax = plt.gca()
ax.set_xticks([1])
ax.set_xticklabels(['R'])
plt.tick_params(left = False, right = False , labelleft = False)
plt.grid()
plt.show()
CodePudding user response:
First your error with full traceback:
In [1]: r = np.linspace(0, 3, 20)
In [2]: V = np.piecewise(r, [r < 1, r > 1 ], [1, (r/2)*(3 - (r**2))])
Traceback (most recent call last):
File "<ipython-input-2-0bb13126761c>", line 1, in <module>
V = np.piecewise(r, [r < 1, r > 1 ], [1, (r/2)*(3 - (r**2))])
File "<__array_function__ internals>", line 5, in piecewise
File "/usr/local/lib/python3.8/dist-packages/numpy/lib/function_base.py", line 612, in piecewise
y[cond] = func
ValueError: NumPy boolean array indexing assignment cannot assign 20 input values to the 13 output values where the mask is true
The problem is in piecewise
. If you (re)read its docs, you'll see that the elements of the 3rd argument list are supposed to scalars or functions. You provided an array as the 2nd.
In [4]: np.size((r/2)*(3 - (r**2)))
Out[4]: 20
In [5]: np.sum(r<1), np.sum(r>1)
Out[5]: (7, 13)
piecewise
is trying to assign 7 values from one condition to the array, and 13 for the other. That's why its complaining when you provide all 20 for the 2nd. 20 does not match 13!
If both values are scalar:
In [6]: V = np.piecewise(r, [r < 1, r > 1 ], [1, 2])
In [7]: V
Out[7]:
array([1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2.,
2., 2., 2.])
We could use a lambda function that will evaluate just the 13 values we want:
In [8]: V = np.piecewise(r, [r < 1, r > 1 ], [1, lambda i: (i/2)*(3-(i**2))])
In [9]: V
Out[9]:
array([ 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 0.98279633, 0.88700977, 0.6967488 ,
0.40020411, -0.01443359, -0.55897361, -1.24522525, -2.08499781,
-3.0901006 , -4.27234291, -5.64353404, -7.21548331, -9. ])
But we don't need to use piecewise
. Instead evaluate all values of r
, and replace selected ones:
In [10]: V = (r/2)*(3 - (r**2))
In [12]: V[r<1] = 1
In [13]: V
Out[13]:
array([ 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 0.98279633, 0.88700977, 0.6967488 ,
0.40020411, -0.01443359, -0.55897361, -1.24522525, -2.08499781,
-3.0901006 , -4.27234291, -5.64353404, -7.21548331, -9. ])
From the docs:
funclist : list of callables, f(x,*args,**kw), or scalars
Each function is evaluated over `x` wherever its corresponding
condition is True. It should take a 1d array as input and give an 1d
array or a scalar value as output. If, instead of a callable,
a scalar is provided then a constant function (``lambda x: scalar``) is
assumed.
So the working piecewise
is doing:
In [17]: fun = lambda i: (i/2)*(3-(i**2))
In [18]: fun(r[r>1])
Out[18]:
array([ 0.98279633, 0.88700977, 0.6967488 , 0.40020411, -0.01443359,
-0.55897361, -1.24522525, -2.08499781, -3.0901006 , -4.27234291,
-5.64353404, -7.21548331, -9. ])
to create 13 values to put in V
.