Placing graphs in a landscape grid (a python challenge) - python

I would like to place subplots in matplotlib so that I do not know how many graphs are there (variable number of graphs).
The grid dimensions is R * C so that R <= C, and the grid is filled fromleft to right and from top to bottom.
The challenge is that I want to make a function that returns a tuple of the location (r, c) for the chart number n
A sample diagram of the needed functions is shown below where group represents n(r,c) i.e. the number n should output the tuple(r,c)
sample
0(0, 0) 1(0, 1) 4(0, 2) 9(0, 3) 16(0, 4)
2(1, 0) 3(1, 1) 5(1, 2) 10(1, 3) 17(1, 4)
6(2, 0) 7(2, 1) 8(2, 2) 11(2, 3) 18(2, 4)
12(3, 0) 13(3, 1) 14(3, 2) 15(3, 3) 19(3, 4)
20(4, 0) 21(4, 1) 22(4, 2) 23(4, 3) 24(4, 4)

x = 0
y = 0
print (x,y)
for i in range(1,5):
y = i
print [(x,y) for x in range(i)]
x = i
print [(x,y) for y in range(i+1)]
To add the numbers:
tuples=[]
x = 0
y = 0
n = 0
tuples.append((n,(x,y)))
for i in range(1,5):
y = i
for x in range(i):
n+=1
tuples.append((n,(x,y)))
x = i
for y in range(i+1):
n+=1
tuples.append((n,(x,y)))
print tuples

Related

How many boxes can we put to the big one?

I'm trying to work on simple algorithms.
I have 600 snacks and I have two kind of boxes 45 snacks inside and 60 snacks. We need to receive all the amount of options that we can do with this small boxes
I have this kind of code, but some how it doesn't work in a right way.
k = 0
for x in range(0,601):
for y in range(0, int(600 // 45) + 1):
for z in range(0, int(600 // 60) +1):
if x +45 * y + 45 * z == 600:
print(x,'45=',y,'60=',z)
k=k+1
print(k)
If I got you right it is simple math. You have 600 items and want use these 600 items in boxes size of 45 and size of 60. I don’t know what you use x for?
k=0
for y in range(0,20):
for z in range(0,20):
if 45 * y + 60 * z == 600
print('45=',y,'60=',z)
k = k + 1
print(k)
Result will be:
45= 0 60= 10
45= 4 60= 7
45= 8 60= 4
45= 12 60= 1
4
At a first glance, z seems to represent the box that can hold 60 snacks. So the line of code if x +45 * y + 45 * z == 600: does not seem ok. The multiplication factor for z should be 60, i.e., if x +45 * y + 60 * z == 600:
The answer is (EDIT: the solution is rewritten as functions):
Both functions return list of tuples with found combinations.
Both functions iterate only throw one box size and filter by second one.
The length of the list that return both functions is the amount of options
def box_comb(snacks, boxA, boxB):
res = []
for a in range(snacks // boxA + 1): # Iterate by boxA
free_space = snacks - boxA * a
if free_space % boxB == 0: # Filter by boxB
b = free_space // boxB # Calculate the count of boxB
res.append((a, b))
return res
# Try this
comb = box_comb(snacks=600,
boxA=60,
boxB=45)
print(comb)
print(f"Number of combinations = {len(comb)}")
The output:
[(1, 12), (4, 8), (7, 4), (10, 0)]
Number of combinations = 4
Single line solution:
The same algorithm written as single line solution
def box_comb_2(snacks, boxA, boxB):
return [(a, (snacks - a * boxA) // boxB) for a in range(snacks // boxA + 1) \
if (snacks - a * boxA) % boxB == 0]
# try this
comb = box_comb_2(snacks=600,
boxA=60,
boxB=45)
print(comb)
print(f"Number of combinations = {len(comb)}")
The output is
[(1, 12), (4, 8), (7, 4), (10, 0)]
Number of combinations = 4

I keep getting the error "index 2 is out of bounds for axis 0 with size 2" in my loop

I'm basically trying to sum a gradient here, see the screenshots I have attached for a better idea. Rho is an nx1 input vector, the screenshot I have attached shows the idea for a 3x1 rho vector but it really has an undefined length.
enter image description here
enter image description here
# JACOBIAN
def derivative(rho, a, A, tilde_k, x, y, vecinc, chi):
n = rho.shape[0]
result1 = np.array([n,1],complex)
result2 = np.array([n,1],complex)
result = np.array([n,1],complex)
u = np.zeros((n, 3))
W_tilde = np.array([3,3],complex)
loop1 = 0
loop2 = 0
for i in range(n):
for j in range(n):
u[i] = x[i] - y[j] # n x 3
W_tilde = A_matrix * chi.imag * A_matrix * G(u[i],k) * A_matrix # 3 x 3
ei_block = np.exp(1j * np.vdot(x[i], tilde_k)) * vecinc # 3 x 1
ej_block = np.exp(1j * np.vdot(x[j], tilde_k)) * vecinc # 3 x 1
eiT_block = np.matrix.getH(ei_block) # 1 x 3
mm = np.matmul(W_tilde, ej_block) # (3 x 3)(3 x 1) = 3 x 1
alpha_tilde = np.dot(eiT_block, mm) # (1 x 3)(3 x 1) = 1 x 1 = scalar
loop1 = loop1 + (2 * rho[i] * alpha_tilde * rho[j]) # scalar
if (i != j):
loop2 = loop2 + ((rho[j]**2) * alpha_tilde) # scalar
result1[i] = loop1
result2[i] = loop2
result = result1 + result2 # (n x 1) + (n x 1) = n x 1 vector
return result
I am getting "IndexError: index 2 is out of bounds for axis 0 with size 2" for the line, result1[i] = loop1. Pls help :(
That error means that you are attempting to access the third element (index 2) of an array with only two elements (size 2).
It looks like you're defining your arrays in a funny way; np.array([n,1],complex) creates an array of length 2, not n. What you want is probably np.zeros(n,complex), which will create an n-length array filled with 0s.

Using 'If' to run the loop again?

I am producing 2 arrays of random numbers that range from -3 to 3 (this would provide to be my x and y coordinates per say). However I want to produce a new set of numbers if the respective x and y is greater than my radius (which is 3) by using an if loop? What do I put in after my if loop to achieve this?
from physics import *
import random
N=3
x= zeros(N,float)
y= zeros(N,float)
for i in range (0, N):
x[i] = uniform(6)-3
y[i] = uniform(6)-3
if (x[n]*2+y[n]**2)**0.5 > 3:
Thanks
Most random library modules provide a routine to return a floating point number from a uniform distribution over the interval [0,1). To choose randomly from a uniform distribution over the interval [a,b), where b > a, you can just multiply by b-a, and then add a.
I'm not certain which modules you're importing in your example, so I'll give examples using the standard random module, as well as the numpy.random
random
import random
def rand_range(a, b):
return a + random.uniform() * (b - a)
x = [rand_range(-3, 3) for i in range(3)]
y = [rand_range(-3, 3) for i in range(3)]
numpy.random
Numpy allows one to vectorize operations for speed and clarity.
import numpy as np
def rand_range(a, b, size):
return a + np.random.random(size) * (b - a)
x = rand_range(-3, 3, (3))
y = rand_range(-3, 3, (3))
or, create an 2D array of 2 rows of 3 elements, and use unpacking
x, y = rand_range(-3, 3, (2, 3))
bounds checking
In order to ensure the points generated meet the criteria of being with 3 units of x, y = (0, 0), you can do something like the following:
x = []
y = []
for i in range(3):
xi, yi = 3, 3 #initally set candidates to fail check
while xi ** 2 + yi ** 2 > 9:
xi = rand_range(-3, 3)
yi = rand_range(-3, 3)
x.append(xi)
y.append(yi)
Given the underlying random method returns a value on the interval [0,1), these arrays should all pass the following assertion:
for xi, yi in zip(x,y):
assert xi**2 + yi**2 <= 9
Can't you just create a new range and then reset your index?
from physics import *
import random
N=3
x= zeros(N,float)
y= zeros(N,float)
for i in range (0, N):
x[i] = uniform(6)-3
y[i] = uniform(6)-3
if (x[n]*2+y[n]**2)**0.5 <= 3:
x = random.sample(range(-3, 3), n)
y = random.sample(range(-3, 3), n)
i = 0
#mtadd
I am answering my question because I found a way to solve it. However, I'm curious whether the way you solved it is more efficient than my process mtadd.
In my physics import is where the random and numpy module are stored, hence why it isn't used in my code.
from physics import *
N=3 #Number of point charges
x= zeros(N,float) #grid
y= zeros(N,float)
i=0
for i in range (0, N): #Loop to ensure two values are <= 3
while i < N:
x[i] = uniform(6)-3
y[i] = uniform(6)-3
if x[i] ** 2 + y[i] ** 2 <= 9:
i+=1
else:
i=0
print x,y
Thanks for the help guys

Animate flood fill in python

I have just finished with my food fill algorithm in python. It runs on an N*N matrix filled with integers. I would like to somehow animate it's workings. Is it somehow possible on the console? I think of something like updateing the nodes with a wait() inbetween the updates.
You could use something like this:
#! /usr/bin/python3
import time
m = [ [c for c in line] for line in '''............................
..XXXXXXXXXX...........XXX..
..X........X...........X.X..
..XXXXXX...X....XXXXXXXX.X..
.......X...X....X........X..
....XXXX...XXXXXX........X..
....X....................X..
....X.................XXXX..
....XXXXXXXXXXXXXXXXXXX.....'''.split ('\n') ]
def flood (matrix, start):
maxX = len (matrix [0] )
maxY = len (matrix)
tbf = [start]
while tbf:
x, y = tbf [0]
tbf = tbf [1:]
if x < 0 or x >= maxX or y < 0 or y >= maxY: continue
if matrix [y] [x] == 'X': continue
matrix [y] [x] = 'X'
tbf += [ (x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1) ]
print ('\x1b[0J\x1b[1;1H') #Clear screen and position cursor top left
for line in matrix: print (''.join (line) )
time.sleep (.2)
#flood (m, (0, 0) )
flood (m, (4, 2) )
This should work on any console that supports ANSI escape sequences (CSI). You can use the same CSI codes for outputting colours (Wiki).

Bezier Curve using static points

So I found this code on line and it does a random Bezier Curve which uses random points. I was trying to make it non random so that it would use static points I got it to use only 4 points which was easy. I have never used PIL before in python and in fact I am slowly learning python. And I have only really done front end work (html, javascript, css, etc) and I just wanted to know if some one can help me.
Here is the code I found on line:
# Random Bezier Curve using De Casteljau's algorithm
# http://en.wikipedia.org/wiki/Bezier_curve
# http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm
# FB - 201111244
import random
from PIL import Image, ImageDraw
imgx = 500
imgy = 500
image = Image.new("RGB", (imgx, imgy))
draw = ImageDraw.Draw(image)
def B(coorArr, i, j, t):
if j == 0:
return coorArr[i]
return B(coorArr, i, j - 1, t) * (1 - t) + B(coorArr, i + 1, j - 1, t) * t
n = 4 # number of control points
coorArrX = []
coorArrY = []
for k in range(n):
x = (0, imgx - 1)
y = (0, imgy - 1)
coorArrX.append(x)
coorArrY.append(y)
# plot the curve
numSteps = 10000
for k in range(numSteps):
t = float(k) / (numSteps - 1)
x = int(B(coorArrX, 0, n - 1, t))
y = int(B(coorArrY, 0, n - 1, t))
try:
image.putpixel((x, y), (0, 255, 0))
except:
pass
# plot the control points
cr = 3 # circle radius
for k in range(n):
x = coorArrX[k]
y = coorArrY[k]
try:
draw.ellipse((x - cr, y - cr, x + cr, y + cr), (255, 0, 0))
except:
pass
# image.save("BezierCurve.png", "PNG")
image.show() I add this so I can see it right away
Any help if at all would be great.
Ok The long detailed BS that began this all is below the long line. The resulting answer is here.
Your static points are x,y coordinates with the x values and y values placed in seperate arrays (coorArrx and coorArrY respectively) make sure to never use a value = imgx or imy.
# Random Bezier Curve using De Casteljau's algorithm
# http://en.wikipedia.org/wiki/Bezier_curve
# http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm
# FB - 201111244
import random
from PIL import Image, ImageDraw
imgx = 500
imgy = 500
image = Image.new("RGB", (imgx, imgy))
draw = ImageDraw.Draw(image)
def B(coorArr, i, j, t):
if j == 0:
return coorArr[i]
return B(coorArr, i, j - 1, t) * (1 - t) + B(coorArr, i + 1, j - 1, t) * t
# n = random.randint(3, 6) # number of control points
n=4
#coorArrX = []
#coorArrY = []
#for k in range(n):
# x = random.randint(0, imgx - 1)
# y = random.randint(0, imgy - 1)
# coorArrX.append(x)
# coorArrY.append(y)
coorArrX=[3,129,12,77]
coorArrY=[128,52,12,491]
# plot the curve
numSteps = 10000
for k in range(numSteps):
t = float(k) / (numSteps - 1)
x = int(B(coorArrX, 0, n - 1, t))
y = int(B(coorArrY, 0, n - 1, t))
try:
image.putpixel((x, y), (0, 255, 0))
except:
pass
# plot the control points
cr = 3 # circle radius
for k in range(n):
x = coorArrX[k]
y = coorArrY[k]
try:
draw.ellipse((x - cr, y - cr, x + cr, y + cr), (255, 0, 0))
except:
pass
image.show()
=.........................................................................................=
I am also something of a newcommer to all of this, and I REFUSE to look this up as I see it like you do...a learning experiencee.
But as I look at this code I see something strange
for k in range(n):
x = (0, imgx - 1)
y = (0, imgy - 1)
coorArrX.append(x)
coorArrY.append(y)
Are you sure this part is correct? imgx is defined as 500 elsewhere, and n is 4.
so this could read as
for k in range(4):
x = (0, 500 - 1)
y = (0, 500 - 1)
which (since these values never change at all in this code) means:
x = (0, 499)
y = (0, 499)
on every pass.
So each time they get to :
coorArrX.append(x)
coorArrY.append(y)
They simply keep adding new copies of the same data to the array, so when it is done the array looks like this (internally)
[(0, 499), (0, 499), (0, 499), (0,499)]
What makes this more confusing, is that coorArrX and coorArrY are A) Identical, and B) identical in their basic parts(that is each element is identical). Therefore, when you get to this part of the code:
# plot the control points
cr = 3 # circle radius
for k in range(n):
x = coorArrX[k]
y = coorArrY[k]
try:
draw.ellipse((x - cr, y - cr, x + cr, y + cr), (255, 0, 0))
except:
pass
and you substitute in the values in the arrays, you get:
# plot the control points
cr = 3 # circle radius
for k in range(n):
x = coorArrX[k]
y = coorArrY[k]
try:
draw.ellipse(((0, 499) - 3, (0, 499) - 3, (0, 499) + 3, (0, 499) + 3), (255, 0, 0))
except:
pass
Now this is the part that controls the drawing of the curved segments for the plot, but I do not see how centering an elispe on those impossible coordinate sets can draw anything?!
Broke down and did a copy paste test run. This code is purely bogus, either placed to dupe people into wasting time, or placed where OP found it for same reason.
But it was fun trying!!
From your description, the only problem seems to be about Python basics. I have rearranged the code as follows, so the only things that need to be touched are at bottom. Now, if you want to manually specify 4 control points, go ahead and do it (in the following code I have specified 4 of them myself as an example). You need to understand that, in the original code, coorArrX and coorArrY are just lists, which will hold 4 points each (x and y coordinates, respectively). If you are manually specifying them, there is no point in using a loop to write them. I hope this code is clear enough:
# Random Bezier Curve using De Casteljau's algorithm
# http://en.wikipedia.org/wiki/Bezier_curve
# http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm
# FB - 201111244
from PIL import Image, ImageDraw
def plot_curve(image, px, py, steps=1000, color=(0, 255, 0)):
def B(coord, i, j, t):
if j == 0:
return coord[i]
return (B(coord, i, j - 1, t) * (1 - t) +
B(coord, i + 1, j - 1, t) * t)
img = image.load()
for k in range(steps):
t = float(k) / (steps - 1)
x = int(B(px, 0, n - 1, t))
y = int(B(py, 0, n - 1, t))
try:
img[x, y] = color
except IndexError:
pass
def plot_control_points(image, px, py, radi=3, color=(255, 0, 0)):
draw = ImageDraw.Draw(image)
for x, y in zip(px, py):
draw.ellipse((x - radi, y - radi, x + radi, y + radi), color)
# Your fixed, manually specified, points.
n = 4
coord_x = [25, 220, 430, 410]
coord_y = [250, 10, 450, 40]
image = Image.new("RGB", (500, 500))
plot_curve(image, coord_x, coord_y)
plot_control_points(image, coord_x, coord_y)
image.save("BezierCurve.png")

Categories

Resources