2

When running this program, I receive the error "TypeError: only length-1 arrays can be converted to Python scalars", specifically referring to line 9, where the x1-variable is assigned.

I'm kind of clueless here what it means in this context. I worked with a very similar piece of code for a previous assignment, where it all worked fine. I took in a vector as an argument to the function and computed all the values simultaneously.

Note: After I removed the floating it seems to work fine, but I have no clue why. Can anyone explain?

import matplotlib.pyplot as plt
import numpy as np
g = 9.78
p = 1000
h = 50
s = 7.9 * 10**-2

def water_wave_speed(l):
  x1 = float(g * l/(2 * np.pi))
  x2 = 1 + s * float((4 * np.pi**2)/(p * g * l**2))
  x3 = float((2 * np.pi * h)/l)
  c = np.sqrt(x1 * x2 * np.tanh(x3))
  return c

l_values = np.linspace(0.001, 0.1, 10)
c_values = water_wave_speed(l_values)
plt.plot(l_values, c_values)
plt.show()
SudokuNinja
  • 419
  • 1
  • 6
  • 16
  • 1
    Use `np.float` instead of `float`. Does that help? – Andras Deak -- Слава Україні Oct 07 '16 at 22:56
  • @AndrasDeak Unfortunately not.. getting the same error. – SudokuNinja Oct 07 '16 at 22:59
  • 2
    @AndrasDeak `np.float == float` – Moses Koledoye Oct 07 '16 at 23:01
  • 1
    What do you expect the `float` calls to do in this code? As far as I can see, the arguments it's being passed will always be a float or array of floats already (since you're multiplying by `np.pi`).. – Blckknght Oct 07 '16 at 23:01
  • 1
    @MosesKoledoye you're right, thanks. I didn't realize the weirdness of the approach until I read your answer, until then it seemed straightforward:) Obviously when you *would* need it, you'd need `.astype(float)`. – Andras Deak -- Слава Україні Oct 07 '16 at 23:02
  • @Blckknght Array of floats? Anyway, that makes sense, I was under the impression that it defaulted to whole number-division otherwise, but I haven't been paying attention enough it seems. – SudokuNinja Oct 07 '16 at 23:09
  • 1
    Integer division only happens in Python 2 when *both sides* of the `/` operator are integers. If either one is a float already, you get float division. Thus, since you're using `np.pi` in all of your calculations, you don't need to worry about it. In Python 3, dividing two integers with `/` does float division, you need to use `//` to specifically request integer division. – Blckknght Oct 07 '16 at 23:16
  • Moses has the right answer for OP. But for those with the same error message, and who actually need to work with one datatype (e.g int) and then convert to another one (e.g. float), this question has an answer for you: https://stackoverflow.com/q/10873824/1295595 – craq Aug 11 '19 at 22:34

1 Answers1

4

Drop all of those float calls and your code should work (as floats). You're trying to coerce numpy arrays into single float values which isn't going to work.

Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
  • Good point, but I pretty much think this should be a comment. – Andras Deak -- Слава Україні Oct 07 '16 at 23:01
  • I see. Can you explain the last part a bit more fully though? I don't understand how the arguments passed to float() would be arrays in this case. I thought when I made a function-call like this in Python, it'd go through the single values of the array and compute them one by one behind the scene. – SudokuNinja Oct 07 '16 at 23:14
  • 1
    As stated in the comments on your question, the computation involves `np.pi`, this keeps your results as floats, and the elements of the arrays are returned as floats. The function call is not performed on every item of the array as you expect. It simply tries to turn the array into a float – Moses Koledoye Oct 07 '16 at 23:20
  • 2
    @user4612744: Arrays don't have any magic than happens to them when they're passed as function arguments. As far as an ordinary function is concerned, an array is just another argument. You can turn a function that expects scalar arguments into one that works with arrays using `numpy.vectorize`, but it doesn't work like that in general. Some functions written for scalars still work because math operations like `*` and `/` will "broadcast" the operation over an array's values if either side is an array. – Blckknght Oct 07 '16 at 23:38
  • `float` takes a number or string and returns a single value. `float([1,2,3])` gives an error; so does `float('1.23 34.4')`. Functions that accept an iterable will treat an array like a flat list. Functions that delegate to an argument's method might also work (e.g. `str()`). Otherwise you need to use `numpy` aware functions. – hpaulj Oct 08 '16 at 17:04