Bokeh Histogram of Roulette Game not showing up, am I missing something? - python

So I'm making a roulette game, here are the guidelines:
Roulette is a casino game that involves a steel ball spinner around a wheel. There are 38 slots where the ball might drop. 18 of those slots are colored red, another 18 are colored black and 2 are colored green. When you bet on either red or black and win, you get back twice the amount of your original bet. For example, if you bet $1, you would get an extra $1 for winning, but you would lose that original $1 if you lost.
Simulate 200 people playing roulette, each betting $1 on red 100 times.
Create a line chart and an appropriate histogram that describes these results.
Make sure to label your line chart and histogram.
So I believe my code for the game is right, but the histogram is showing up as a blank graph without anything on it.
Am I missing something? Is there something else I need to add or incorporate?
Here's what I have written for this.
import math
import random
import numpy as np
from bokeh.plotting import figure, show
def roulette(x):
results = []
count = 0
for i in range(1, x):
roll = random.randint(1, 38)
if roll <= 18:
count += 1
results.append(count/i)
else:
count -= 1
results.append(count/i)
return results
def listf(x):
for i in range(x):
return(roulette(100)[-1])
roulette_list = listf(200)
hist = np.histogram(roulette_list, bins = 10, range = (0, 200))
yval = hist[0]
xval = hist[1]
xbarwidth = xval[1] - xval[0]
xval = xval + xbarwidth/2
xval = xval[0:-1]
print(xval)
f = figure()
for x, y in zip(xval, yval):
f.vbar(x, xbarwidth, y, line_color = "white")
show(f)

Your bokeh code works perfectly, here you can see a minimal example with self defined xval and yval.
xval = [1,2,3,4]
yval = [1,2,3,4]
xbarwidth = 1
f = figure()
for x, y in zip(xval, yval):
f.vbar(x, xbarwidth, y, line_color = "white")
show(f)
You have to ckeck your implementation for the roulette() and listf. If you call
roulette_list = listf(200)
this returns only one value right now and than np.histogram doesn't work as intended.
Edit
My you can substitute your call roulette_list = listf(200) function with roulette_list =np.random.randint(0, 38, size=200, dtype=int). If you do so for a test, you will see some output in your figure.

Related

Is it possible to set the gradient colour for a line plot based on the minimum and maximum of Y-values? [duplicate]

This question already has an answer here:
How to create a step-plot with a gradient based on y-value?
(1 answer)
Closed last month.
I am working on a task where I need to generate a line plot with maximum values assigned to one color and minimum values assigned to another. There should be gradient colors between the maximum and minimum values.
To generate a line plot with gradient colour, I use the code previously provided. As you can see, the output looks like this.
I saw the answer provided in enter link description here, but it is for step plot. I want to implement this using matplotlib line plot.
I would like the gradient colour to follow the y-values (i.e., from maximum to minimum) not the x-values (i.e., from left to right). I hope my question is clear. To generate the current output, I used the code below as a reference.
x = np.linspace(0, 4.*np.pi, 1000)
y = np.sin(x)
def hex_to_RGB(hex_str):
""" #FFFFFF -> [255,255,255]"""
#Pass 16 to the integer function for change of base
return [int(hex_str[i:i+2], 16) for i in range(1,6,2)]
def get_color_gradient(c1, c2, n):
"""
Given two hex colors, returns a color gradient
with n colors.
"""
assert n > 1
c1_rgb = np.array(hex_to_RGB(c1))/255
c2_rgb = np.array(hex_to_RGB(c2))/255
mix_pcts = [x/(n-1) for x in range(n)]
rgb_colors = [((1-mix)*c1_rgb + (mix*c2_rgb)) for mix in mix_pcts]
return ["#" + "".join([format(int(round(val*255)), "02x") for val in item]) for item in rgb_colors]
color1 = "#EB1410"
color2 = "#080606"
plt.figure(figsize=(12,7))
plt.scatter(x, y, color = get_color_gradient(color1, color2, len(x)))
plt.show()
you need to generate color based on the y value, so you should take the y value and use it to interpolate the color's R,G,B values separately using np.interp
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 4.*np.pi, 1000)
y = np.sin(x)
def hex_to_RGB(hex_str):
""" #FFFFFF -> [255,255,255]"""
#Pass 16 to the integer function for change of base
return [int(hex_str[i:i+2], 16) for i in range(1,6,2)]
color1 = "#EB1410"
color2 = "#080606"
def gradient_cmap(c):
c1_rgb = np.array(hex_to_RGB(color1)) / 255
c2_rgb = np.array(hex_to_RGB(color2)) / 255
R_map = [c1_rgb[0],c2_rgb[0]]
G_map = [c1_rgb[1],c2_rgb[1]]
B_map = [c1_rgb[2],c2_rgb[2]]
in_val = [np.amin(c),np.amax(c)]
R = np.interp(c,in_val,R_map).reshape([-1,1])
G = np.interp(c,in_val,G_map).reshape([-1,1])
B = np.interp(c,in_val,B_map).reshape([-1,1])
return np.hstack([R,G,B])
plt.figure(figsize=(12, 7))
plt.scatter(x, y, c=gradient_cmap(y))
plt.show()

Find closest point in 2D mashed array

To give y'all some context, I'm doing this inversion technique where I am trying to reproduce a profile using the integrated values. To do that I need to find the value within an array along a certain line(s). To exemplify my issue I have the following code:
fig, ax = plt.subplots(1, figsize = (10,10))
#Create the grid (different grid spacing):
X = np.arange(0,10.01,0.25)
Y = np.arange(0,10.01,1.00)
#Create the 2D array to be plotted
Z = []
for i in range(np.size(X)):
Zaux = []
for j in range(np.size(Y)):
Zaux.append(i*j + j)
ax.scatter(X[i],Y[j], color = 'red', s = 0.25)
Z.append(Zaux)
#Mesh the 1D grids:
Ymesh, Xmesh = np.meshgrid(Y, X)
#Plot the color plot:
ax.pcolor(Y,X, Z, cmap='viridis', vmin=np.nanmin(Z), vmax=np.nanmax(Z))
#Plot the points in the grid of the color plot:
for i in range(np.size(X)):
for j in range(np.size(Y)):
ax.scatter(Y[j],X[i], color = 'red', s = 3)
#Create a set of lines:
for i in np.linspace(0,2,5):
X_line = np.linspace(0,10,256)
Y_line = i*X_line*3.1415-4
#Plot each line:
ax.plot(X_line,Y_line, color = 'blue')
ax.set_xlim(0,10)
ax.set_ylim(0,10)
plt.show()
That outputs this graph:
I need to find the closest points in Z that are being crossed by each of the lines. The idea is to integrate the values in Z that are crossed by the blue lines and plot that as a function of slope of the lines. Anyone has a good solution for it? I've tried a set of for loops, but I think it's kind of clunky.
Anyway, thanks for your time...
I am not sure about the closest points thing. That seems "clunky" too. What if it passes exactly in the middle between two points? Also I already had written code that weighs the four neighbor pixels by their closeness for an other project so I am going with that. Also I take the liberty of not rescaling the picture.
i,j = np.meshgrid(np.arange(41),np.arange(11))
Z = i*j + j
class Image_knn():
def fit(self, image):
self.image = image.astype('float')
def predict(self, x, y):
image = self.image
weights_x = [1-(x % 1), x % 1]
weights_y = [1-(y % 1), y % 1]
start_x = np.floor(x).astype('int')
start_y = np.floor(y).astype('int')
return sum([image[np.clip(np.floor(start_x + x), 0, image.shape[0]-1).astype('int'),
np.clip(np.floor(start_y + y), 0, image.shape[1]-1).astype('int')] * weights_x[x]*weights_y[y]
for x,y in itertools.product(range(2),range(2))])
And a little sanity check it returns the picture if we give it it's coordinates.
image_model = Image_knn()
image_model.fit(Z)
assert np.allclose(image_model.predict(*np.where(np.ones(Z.shape, dtype='bool'))).reshape((11,41)), Z)
I generate m=100 lines and scale the points on them so that they are evenly spaced. Here is a plot of every 10th of them.
n = 1000
m = 100
slopes = np.linspace(1e-10,10,m)
t, slope = np.meshgrid(np.linspace(0,1,n), slopes)
x_max, y_max = Z.shape[0]-1, Z.shape[1]-1
lines_x = t
lines_y = t*slope
scales = np.broadcast_to(np.stack([x_max/lines_x[:,-1], y_max/lines_y[:,-1]]).min(axis=0), (n,m)).T
lines_x *= scales
lines_y *= scales
And finally I can get the "points" consisting of slope and "integral" and draw it. You probably should take a closer look at the "integral" it's just a ruff guess of mine.
%%timeit
points = np.array([(slope, np.mean(image_model.predict(lines_x[i],lines_y[i]))
*np.linalg.norm(np.array((lines_x[i,-1],lines_y[i,-1]))))
for i,slope in enumerate(slopes)])
plt.scatter(points[:,0],points[:,1])
Notice the %%timeit in the last block. This takes ~38.3 ms on my machine and therefore wasn't optimized. As Donald Knuth puts it "premature optimization is the root of all evil". If you were to optimize this you would remove the for loop, shove all the coordinates for line points in the model at once by reshaping and reshaping back and then organize them with the slopes. But I saw no reason to put myself threw that for a few ms.
And finally we get a nice cusp as a reward. Notice that it makes sense that the maximum is at 4 since the diagonal is at a slope of 4 for our 40 by 10 picture. The intuition for the cusp is a bit harder to explain but I guess you probably have that already. For the length it comes down to the function (x,y) -> sqrt(x^2+y^2) having different directional differentials when going up and when going left on the rectangle.

How to find the instance before a peak forms in a signal?

I am working with signal data and am trying to find the instance (or close to it) before a peak starts to form. For example:
The red stars and orange x's are currently calculated using scipy.signal.find_peaks to find the first minimum peak before two peaks greater than 50 in a row. The ideal location I want is the area with the red stars and the second and third orange x.
My problem is that sometimes there is not a minimum value right before that first hump forms and that causes a problem like with the first orange x on the left.
What would be a better method or a way to improve my current method to get that spot right before the hump forms (rough arrow location):
My current code looks something like this, and it runs for the blue and green lines separately:
step_peak, _ = find_peaks(z, height=60, distance=40)
step_min, _ = find_peaks(-1*z, height=-60)
contact = []
for i in range(len(step_peak)-1):
if step_peak[i+1] - step_peak[i] < 100:
for min in reversed(step_min):
if min < step_peak[i]:
contact.append(min)
break
This method works for about 90% of the entire dataset, there are only a few that end up like the first orange x that I need to account for.
Any help would be greatly appreciated.
First, let's look at the function scipy.signal.peak_widths. Without access to your data, I used a sample curve:
from scipy.signal import chirp, find_peaks, peak_widths
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 6 * np.pi, 1000)
x = np.sin(x) + 0.6 * np.sin(2.6 * x)
peaks, _ = find_peaks(x)
results_full = peak_widths(x, peaks, rel_height=1)
results_full[0] # widths
plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.hlines(*results_full[1:], color="C3")
plt.show()
We can parse the results of peak_widths to discard those values that are inside of another widths.
peak_begin = np.array(results_full)
peak_begin = peak_begin[:, np.argsort( peak_begin[2] ) ]
_, b = peak_begin.shape
width_to_delete = []
i= 1
while i < b:
if peak_begin[2][i] < peak_begin[3][i-1]:
peak_begin = np.delete(peak_begin,i,1)
b = b-1
else:
i = i+1
plt.plot(x)
plt.hlines(*results_full[1:], color="r")
plt.plot(peaks, x[peaks], "x")
plt.plot(peak_begin[2], peak_begin[1], "o", color="g")
plt.show()
I hope that I got what you want to achieve.

Why the two arguments of graphs are not consider as equal?

Let's say i have an object which I have to destroy by shooting (projectile motion). The position of the object is random (as for now, just integers, to make it easier). Even when my 'bullet' looks to be just in place, the loop doesn't break. Probably the program doesn't consider graph 1 and graph 2 as equal at any point.
I tried few things about that if condition but it nothing worked.
Can anyone tell me what I must add/change?
import matplotlib.pylab as plt
import numpy as np
import random
g = 10
c = []
d = []
fig = plt.figure()
L = random.randint(5.0,18.0)
while True:
try:
#velocity
v = float(input("What is the velocity?\n>"))
#angle
a = np.radians(float(input("What is the angle?\n>")))
z = np.sin(2*a)*v**2/g #max range
h = ((v**2*(np.sin(a))**2)/(2*g)) #max. height
x= np.linspace(0, z, 1000)
#y values
y = (x*np.tan(a) - (g*x**2)/(2*v**2*((np.cos(a))**2)))
ax = plt.axes(xlim=(0, 1.5*L), ylim=(0, 1.2*h))
plt.ion() #interactive graph
#previous tries
plt.plot(c,d, '.', color = 'lightgrey')
plt.pause(0.01)
#enemy object
graph1 = plt.plot(L, 0, 'o', color = 'r', markersize=30)
plt.pause(0.01)
#actual shoot
graph2 = plt.plot(x,y, '.', color = 'b', ms = 7)
plt.pause(0.01)
if np.any(graph2) == np.any(graph1):
print("You have destroyed the enemy object!")
plt.show()
break
else:
print("You've missed. Keep shooting!")
c.append(x)
d.append(y)
plt.show()
continue
except ValueError:
print("Sorry, I can't understand.")
You don't need to plot at all to find the intersection. In fact, I don't think matplotlib can help here. The returned value of plt.plot is a list containing a single Line2D object - you could get back your original x and y values by doing
x_new = graph1[0].get_xdata()
y_new = graph1[0].get_ydata()
However, you'd only do that if your code was for some reason analyzing plots generated by a completely different function and wasn't allowed to have the original data. In your case, just use your x and y directly and find the intersection. It looks like you might be trying to do
if np.any((y == 0) * (x == L)):
print "You have destroyed the enemy object!"
Which should check if any point (x,y) is located at (0,L). The * acts as an element-by-element 'and' operator for boolean arrays. Here are some more comprehensive answers about finding intersections of two arrays.
If you're trying to build a game, look at pygame. It has all kinds of methods to detect collisions much more easily than in numpy.

Loop patchwork in python3

I need to create a patchwork in Python 3. All I have left to do is create a loop which makes the design border the graphics window. I know I need a for loop however I am not sure how to do this.
This is what I have so far:
from graphics import *
def main():
height = eval(input("What is the height of the window"))
width = eval(input("What is the width of the window"))
colour = input("enter the colour of the patch")
win = GraphWin("Patch", 100*width, 100*height)
boat_x = 0
boat_y = 0
for x in range (4):
boat(win, boat_x, boat_y, colour)
boat_x = boat_x + 23
for i in range(height * 5):
boat(win, boat_x, boat_y, colour)
boat_x = boat_x + 24
for j in range(height * 5):
boat(win, boat_x, boat_y, colour)
boat_y = boat_y + 100
win.getMouse()
win.close()
def boat(win, x, y, colour):
body1 = Polygon(Point(1+x,95+y), Point(5+x,100+y),
Point(20+x,100+y), Point(24+x,95+y))
body1.draw(win)
line1 = Line(Point(13+x,95+y), Point(13+x,90+y))
line1.draw(win)
sail1 = Polygon(Point(1+x,90+y), Point(24+x,90+y), Point(13+x, 73+y))
sail1.setFill(colour)
sail1.draw(win)
body2 = Polygon(Point(1+x, 63), Point(5+x, 68),
Point(20+x,68), Point(24+x,63))
body2.draw(win)
line2 = Line(Point(13+x,63), Point(13+x,58))
line2.draw(win)
sail2 = Polygon(Point(1+x,58), Point(24+x, 58), Point(13+x,40))
sail2.setFill(colour)
sail2.draw(win)
body3 = Polygon(Point(1+x,28), Point(5+x,33),
Point(20+x,33), Point(24+x, 28))
body3.draw(win)
line3 = Polygon(Point(13+x,28), Point(13+x,23))
line3.draw(win)
sail3 = Polygon(Point(1+x,23), Point(24+x, 23), Point(13+x, 5))
sail3.setFill(colour)
sail3.draw(win)
main()
So far this creates the top border but nothing else.
I am also aware that the boat function isn't the most efficient way of drawing
When you say that you need to "make the design border the graphics window" I assume you want your boat design to be repeated several times along each edge of the window (that is, the top, bottom, left and right).
This should be doable in two loops. One will draw the top and bottom edges, the other two will draw the left and right edges. I'm not too sure how your drawing code works, so I'm guessing at some offsets here:
top = 0
bottom = (height-1) * 100
for x in range(0, width*100, 25):
boat(x, top, colour)
boat(x, bottom, colour)
left = 0
right = width * 100 - 25
for y in range(100, (height-1)*100, 100):
boat(left, y, colour)
boat(right, y, colour)
This should call your boat subroutine every 25 pixels across the top and bottom, and every 100 pixels along the left and right edges. Adjust the top, bottom, left and right values and the parameters in the range calls in the loops to make the spacing suit your needs (I just made it up). This code avoids drawing the corner items twice, though depending on how the drawing routine works that might not be necessary.

Categories