pygames / drawing circle that bounces off walls - python-3.x

b1 = {'rect':pygame.Rect(300, 80, 50, 100), 'color':RED, 'dir':UPRIGHT}
b2 = {'rect':pygame.Rect(200, 200, 20, 20), 'color':GREEN, 'dir':UPLEFT}
b3 = {'rect':pygame.Rect(100, 150, 60, 60), 'color':BLUE, 'dir':DOWNLEFT}
b4 = {'rect':pygame.draw.circle((300, 50), 20, 0,), 'color':PURPLE, 'dir':DOWNRIGHT}
blocks = [b1, b2, b3]
# draw the block onto the surface
pygame.draw.rect(windowSurface, b['color'], b['rect'])
pygame.draw.circle(windowSurface, b['color'], (300, 50), 20, 0)
Brand new to pygames (programming in general). This is one of our first assignments, to edit a simple program that bounces squares off the walls. We are to add a circle but I'm not able to figure out how to fit it into the pre-existing dict structure for the rectangles. I'm getting the following error, what am I not seeing:
Traceback (most recent call last):
File "C:\Users\CA115\Downloads\animation1.py", line 32, in <module>
b4 = {'rect':pygame.draw.circle((300, 50), 20, 0,), 'color':PURPLE, 'dir':DOWNRIGHT}
TypeError: function takes at least 4 arguments (3 given)

A quick look at Pygame's documentation shows that you are providing less parameters than expected. In general, that's all Python is telling you when it said "TypeError: function takes at least 4 arguments (3 given)".
A little more detail: In line 32, as your error trace specifies, what causes the problem is the dictionary entry 'rect':pygame.draw.circle((300, 50), 20, 0,). From the documentation I linked, you should be able to figure out what went wrong here.
Another hint. Since you said that you are new to programming in general, you should note that the parameters for pygame.Rect and pygame.draw.circle have a significant difference: Rect takes in all primitive Python values ("numbers") while circle needs a particular object.

Related

Find start/stop location of sharp cumulative events

Here is an example set of data:
EDIT: Included some more data.
x = [0, 5, 6,15, 20, 40, 73,
100,101,102,103,104,105,106,108,111,115,
116,117,118,119,120,123,124,125,126,127,
128,129,130,131, 150,161,170, 183, 194,
210, 234, 257, 271,272,273,274, 275,276,
277,278,279,280,281,282,283,284,285,287,
288,291,292,293,294,295,296,297,298,300,301,
302,303,304,305,306,307,308,309,310,311,
340, 351, 358, 360, 380, 390, 400,401,
402,403, 404, 405, 408, 409, 413, 420,
425,426,427,428,429,430,431,432,433,434,435,
436, 440, 450, 455]
y = np.arange(1, len(x)+1)
Here is what the data visually looks like and has the potentially for each sharp increase to be longer. The last sharp increase also has a pause, but I would like it to still be considered one set of data. Black dots are the gradient.
I am attempting to find the the start/end x-values for each sharp increase in cumulative counts. So the output should be an array of indexes, like what Riley has done.
A vectorized method would be ideal to help with any time constraints to quickly go through data. Here is rough outline of what has been done so far within a pandas dataframe.
Shift the "x-data" and take a difference
See if sequential differences are below a threshold to create logic array
Do rolling sum on logic array with so Trues will continue add to count
Find when rolling sum exceeds another threshold
Compare with previous value to ensure it is increase/decreasing for start/stop times
Add times to index list
It seems a little finicky on some of the rolling averages and isn't as quick as I would like. Multiplying some of these large arrays with logic arrays seems to take a good amount of time.
EDIT: Here is the code Riley has provided and offers an excellent start. It is also only a couple lines a code, versus my method above was almost 50 or so.
rate_threshold = 0.25
min_consecutive = 8
above_rate = np.gradient(y,x) >= rate_threshold
sequence_diff = np.diff(np.lib.stride_tricks.sliding_window_view(above_rate, window_shape=min_consecutive).all(axis=1).astype(int))
intervals = np.hstack([np.argwhere(sequence_diff==1) + 1, np.argwhere(sequence_diff==-1) + min_consecutive-1])
The new issue comes from the final sharp increase of data. Two sets of start/end points are returned, where the desired would just be one.
My initial thought is to include some kind of average routine with the sliding window to account for these drops in the gradient so the end is so hard set.
Not sure what your desired output would look like, so let's start with this, verify it does it what you want it to, then go from there
rate_threshold = 1
min_consecutive = 5
above_rate = np.diff(y)/np.diff(x) >= rate_threshold
sequence_diff = np.diff(sliding_window_view(above_rate, window_shape=min_consecutive).all(axis=1).astype(int))
intervals = np.hstack([np.argwhere(sequence_diff==1) + 1, np.argwhere(sequence_diff==-1) + min_consecutive-1])
intervals is a 2d numpy array of indices whose 2 columns are first index, and last index in a sequence (of length min_consecutive) of rates above the threshold
array([[ 7, 12],
[16, 20],
[22, 29],
[39, 52],
[56, 62],
[64, 74]], dtype=int64)

How to fill the area near the y axis in a plot?

I need to plot two features of a dataframe where df['DEPTH'] should be inverted and at y-axis and df['SPECIES'] should be at x-axis. Imagining that the plot would be a variant line, I would like to fill with color the area near the y-axis (left side of the line). So I wrote some code:
df = pd.DataFrame({'DEPTH': [100, 150, 200, 250, 300, 350, 400, 450, 500, 550],
'SPECIES':[12, 8, 9, 6, 10, 7, 4, 3, 1, 2]})
plt.plot(df['SPECIES'], df['DEPTH'])
plt.fill_between(df['SPECIES'], df['DEPTH'])
plt.ylabel('DEPTH')
plt.xlabel('SPECIES')
plt.ylim(np.max(df['DEPTH']), np.min(df['DEPTH']))
I tried 'plt.fill_between', but then the left part of the plot doesn't get all filled.
Anyone knows how can the filled part (blue color) reach the y-axis?
Instead of fill_between, you can use fill_betweenx. It will start filling from 0 by default, thus you need to set your x limit to be 0 too.
plt.plot(df['SPECIES'], df['DEPTH'])
# changing fill_between to fill_betweenx -- the order also changes
plt.fill_betweenx(df['DEPTH'], df['SPECIES'])
plt.ylabel('DEPTH')
plt.xlabel('SPECIES')
plt.ylim(np.max(df['DEPTH']), np.min(df['DEPTH']))
# setting the lower limit to 0 for the filled area to reach y axis.
plt.xlim(0,np.max(df['SPECIES']))
plt.show()
The result is below.

Risk scoring in python

I have a metric to detect fraud, say calls, transfer rate, aux time, and so on.
I have grouped them into bins based on quartiles and now I have to give ratings from 1 to 5 based on bins. For example: calls > 150 assign ranking as 1, calls <=150 and >=300 as 2 and so on. Likewise for all the metrics.
I tried the following:
np.where(x.Calls<=125.8,1,
np.where(x.Calls>=153.2 & x.Calls<=190.0,2,np.where(x.Calls>=190.0 & x.Calls<=235.0,3,np.where(x.Calls>=235.0 & x.Calls<=304.4,4,np.where(x.Calls>=304.4,5,0))))
Error:
File "<ipython-input-32-41fe2292e308>", line 2
np.where(x.Calls>=153.2 & x.Calls<=190.0,2,np.where(x.Calls>=190.0 &
x.Calls<=235.0,3,np.where(x.Calls>=235.0 &
x.Calls<=304.4,4,np.where(x.Calls>=304.4,5,0))))
^ SyntaxError: unexpected EOF while parsing
I want the code to take the range of values from the quartiles got and give ratings to it on its own.
Your specific error indicates that you have left some parentheses open.
But you're getting this error because the nested np.where approach is really hard to implement (and therefore debug and maintain). So it's worth thinking about other ways.
The rules you want to implement aren't totally clear to me, but I think np.digitize might help you make progress. It 'quantizes' your data: you give it an array-like of bins, and it returns the bin each value of an array appears in. It works like this:
>>> import numpy as np
>>> a = np.array([55, 99, 65, 121, 189, 205, 211, 304, 999])
>>> bins = [100, 200, 300]
>>> np.digitize(a, bins=bins)
array([0, 0, 0, 1, 1, 2, 2, 3, 3])

Image Filter which uses the highest occurence of pixel values

I want to use an image filter, which should replace the pixel it's dealing with with the highest occurence of the neighbors.
For example if the pixel has the value 10, and the 8 neighbors have 9, 9, 9, 27, 27, 200, 200, 210, then it should pick 9, because 9 has the highest occurence in the neighborhood. It also should consider the pixel itself, too. So for example if the pixel has the value 27 and the 8 neighbors have 27, 27, 30, 30, 34, 70, 120, 120 then it should pick 27, because 27 is there 3 times, including the pixel itself.
I also should have the option to choose the size of the kernel.
I didn't find a filter like that. Is there one? Or do i have to create it on my own? I use opencv with python.
Background information:
I can't just use Median filter, because my images are different. I have gray images with 3 to 6 different gray values. Therfore i can't use some morphological transformations. I don't get the result i want. The median filter would pick the median value, because the idea is that the values represent the image in the right way. But my images are the result of kmeans and the 3-6 different gray values don't have a logical connection.
You can use the modal filter in skimage, example here, documentation here.
Or if your needs differ slightly, you could experiment with the generic_filter() in scipy (documentation here) along these lines:
#!/usr/bin/env python3
import numpy as np
from PIL import Image
from scipy.ndimage import generic_filter
from scipy import stats
# Modal filter
def modal(P):
"""We receive P[0]..P[8] with the pixels in the 3x3 surrounding window"""
mode = stats.mode(P)
return mode.mode[0]
# Open image and make into Numpy array - or use OpenCV 'imread()'
im = Image.open('start.png').convert('L')
im = np.array(im)
# Run modal filter
result = generic_filter(im, modal, (3, 3))
# Save result or use OpenCV 'imwrite()'
Image.fromarray(result).save('result.png')
Note that OpenCV images are completely interchangeable with Numpy arrays, so you can use OpenCV image = imread() and then call the functions I am suggesting above with that image.
Keywords: Python, PIL, Pillow, skimage, simple filter, generic filter, mean, median, mode, image, image processing, numpy

Where does this timestamp come from? (LED priority signal)

I have this code and it runs two times fine, while on third call I get an error, as if I would have passed Timestamp. I only ever pass Tuple or None.
from pprint import pprint
from gpiozero import RGBLED
def signal(pri, newcolor):
signal.priority[pri] = newcolor
pprint(signal.priority)
try: signal.led.color = next(color for color in signal.priority if color is not None)
except StopIteration: signal.led.color = (0,0,0)
signal.led = RGBLED(red=11, green=9, blue=10)
signal.priority = 2*[None]
Output is following
[None, (0, 1, 0)]
[None, (0, 0, 1)]
[None, (1, 1, 0)]
Traceback (most recent call last):
File "/home/pi/zrcrasp.py", line 137, in <module>
signal(1, (1,1,0))
File "/home/pi/zrcrasp.py", line 10, in signal
try: signal.led.color = next(color for color in signal.priority if color is not None)
TypeError: 'Timestamp' object is not callable
Background
Function is used by various part of program to signal any kind of error, but if high priority short red blink ends, the lower priority green should continue. If there is no lower priority - None , then led will be turned off (this is the except statement for)
Lowest index is the highest priority.

Resources