I started recently working with Pyton 3.10 and while I was creating a graph that works with random data I got a problem. I want the random module work between a minimum and a maximum value but the random value have to oscillate in a range between - 0 to 0.10 compared to the previous value and so I had a problem to convert the list from the random.choices (named value) in a float number, i got this error "Expected type 'SupportsFloat | SupportsIndex | str | bytes | bytearray', got 'list[float]' instead" I know I can't convert a list in a float because a list is a set of numbers but searching on internet I found nothing to solve in others ways this problem. Can you please help me?
import random
import matplotlib.pyplot as plt
from itertools import count
from matplotlib.animation import FuncAnimation
minimo = 90.00
massimo = 110.00
altissimo = 108
alto = 104
basso = 96
bassissimo = 92
x_vals = []
y_vals = []
pmin = ()
pmag = ()
valori = [minore, maggiore]
index = count()
plt.plot(x_vals, y_vals)
def animate(i):
global minore
global maggiore
global pmin
global pmag
value = random.choices(valori, weights=[pmin, pmag])
print(value)
value = float(value) #<-- here is the problem
value = round(value, 2)
if value > altissimo:
pmin = 80
pmag = 20
elif alto < value < altissimo:
pmin = 60
pmag = 40
elif basso < value < alto:
pmin = 40
pmag = 60
elif bassissimo < value < basso:
pmin = 20
pmag = 80
delta = random.uniform(0, 0.10)
delta = round(delta, 2)
minore = value - delta
maggiore = delta value
print(value)
x_vals.append(next(index))
y_vals.append(value)
plt.cla()
plt.plot(x_vals, y_vals)
plt.tight_layout()
ani = FuncAnimation(plt.gcf(), animate, interval=10)
plt.tight_layout()
plt.show()
CodePudding user response:
Your fundamental misunderstanding, I think, is in this line:
valori = [minore, maggiore]
You seem to be expecting that random.choices
will use that to choose between the current values of minore
and maggiore
. That's not how Python works. What that statement does is grab the current VALUE of those two variables. If you change minore
after that, the valori
list will not change.
I believe you are just using that array to choose whether to start with the minore
or maggiore
value, based on the percentages in pmin
and pmag
. There is an easier way to do that, just by checking whether random.random()
produces a number above or below that.
And please eliminate all the calls to "round". Rounding is only to be used when you are presenting numbers for human consumption. Let the computer work with all the significant digits it can. Remember that "0.20" is still an approximation; it cannot be represented exactly in binary.
This minor change does what I think you want:
import random
import matplotlib.pyplot as plt
from itertools import count
from matplotlib.animation import FuncAnimation
altissimo = 108
alto = 104
basso = 96
bassissimo = 92
x_vals = []
y_vals = []
pmin = 0.50
index = count()
plt.plot(x_vals, y_vals)
minore = 99.0
maggiore = 101.0
def animate(i):
global minore
global maggiore
global pmin
value = minore if random.random() < pmin else maggiore
print(value)
if value > altissimo:
pmin = .80
elif value > alto:
pmin = .60
elif value > basso:
pmin = .40
elif value > bassissimo:
pmin = .20
delta = random.uniform(0, 0.10)
minore = value - delta
maggiore = value delta
print(value)
x_vals.append(next(index))
y_vals.append(value)
plt.cla()
plt.plot(x_vals, y_vals)
plt.tight_layout()
ani = FuncAnimation(plt.gcf(), animate, interval=10)
plt.tight_layout()
plt.show()
CodePudding user response:
random.choices always returns a list. If you call it with the default k=1
, it returns a list of 1 value. You could fix this in a couple of ways.
On the line you marked as a problem, replace
value = float(value)
withvalue = float(value[0])
Change the line where you call random.choices to:
[value] = random.choices(valori, weights=[pmin, pmag])
. That means that you expect random.choices to return a list of 1 item, and that you want to put that item (not the list) into the variable 'value'.