How can I transfer the data that my program generates to a new turtle program to use? - python

Seen below is the code for my iteration program. I want to be able to use turtle graphics to take each parameter (k) and have the equations output plotted against its corresponding k value. This should create a feigenbaum diagram if im not mistaken? My problem is, how can I get a turtle to plot these points for each k value, then connect them to the points from the neighbouring k values and so on?
def iteration(xstore):
global x0
x0=xstore
print (x0)
x0=float(input("x0:"))
n=float(input("max parameter value:"))
divison=float(input("divisons between parameters:"))
xv=x0
x1=0
k=0
while k<(n+divison):
print("K VALUE:"+str(k))
for i in range (0,20):
x1=x0+x0*k*(1-x0)
iteration(x1)
print ("________________________")
x0=xv
k=k+divison

Here is a feigenbaum diagram generated using tkinter. It is from the "open book project", visualizing chaos.
The program source is here; I converted it to python 3 and posted it hereunder. There is a lot for you to learn reading and understanding this code.
#
# chaos-3.py
#
# Build Feigenbaum Logistic map. Input start and end K
#
# python chaos-3.py 3.4 3.9
#
canWidth=500
canHeight=500
def setupWindow () :
global win, canvas
from tkinter import Tk, Canvas, Frame
win = Tk()
canvas = Canvas(win, height=canHeight, width=canWidth)
f = Frame (win)
canvas.pack()
f.pack()
def startApp () :
global win, canvas
import sys
# k1 = float(sys.argv[1]) # starting value of K
# k2 = float(sys.argv[2]) # ending value of K
x = .2 # is somewhat arbitrary
vrng = range(200) # We'll do 200 horz steps
for t in range(canWidth) :
win.update()
k = k1 + (k2-k1)*t/canWidth
# print("K = %.04f" % k)
for i in vrng :
p = x*canHeight
canvas.create_line(t,p,t,p+1) # just makes a pixel dot
x = x * (1-x) * k # next x value
if x <=0 or x >= 1.0 :
# print("overflow at k", k)
return
def main () :
setupWindow() # Create Canvas with Frame
startApp() # Start up the display
win.mainloop() # Just wait for user to close graph
k1 = 2.9
k2 = 3.8
main()

how can I get a turtle to plot these points for each k value
Here's a simple, crude, slow example I worked out using Python turtle:
from turtle import Screen, Turtle
WIDTH, HEIGHT = 800, 400
Kmin = 2.5
Kmax = 3.8
x = 0.6
screen = Screen()
screen.setup(WIDTH, HEIGHT)
screen.setworldcoordinates(Kmin, 0.0, Kmax, 1.0)
screen.tracer(False)
turtle = Turtle()
turtle.hideturtle()
turtle.penup()
k = Kmin
while k < Kmax:
for _ in range(HEIGHT//4):
x *= (1.0 - x) * k
turtle.goto(k, x)
turtle.dot(2)
x *= 1 + 1/(HEIGHT//4)
k *= 1 + 1/WIDTH
screen.tracer(True)
screen.exitonclick()
I hope it gives you some ideas about plotting functions using a turtle. (Of course, using matplotlib with numpy usually works out better in the end.)

Related

Numba: how to speed up numerical simulation requiring also GUI

I was just starting to learn about Numba to speed up for loops.
I've read it is impossible to call a non-jitted function from a numba jitted function. Therefore I don't think I can #jitclass(spec) my class or #njit the main algorithm function (compute()) leaving my code how it is, since every step of the simulation (onestep()) also changes the value of the pixel in the image tkinter.Photoimage, which is a Python type. So, I was wondering whether:
there is any possible logical change to the program which would separate GUI and numerical part enough to allow Numba to be applied;
there is any alternative to Tkinter compatible with Numba;
there is any alternative to Numba which I may benefit from.
Here is a simplified version of my code for now:
import tkinter as tk
import numpy as np
window = tk.Tk()
window.geometry("600x600")
canv_w= 480
square_w = 16 #size of one element of the matrix
canvas=tk.Canvas(window,width=480,height=480)
canvas.pack()
my_image=tk.PhotoImage(width=480,height=480)
canvas.create_image((3, 3),image=my_image,anchor="nw",state="normal")
running =0
def pixel(self, i,j):
if self.matrix[i,j]==-1:
temp="#cc0000" #red
elif self.matrix[i,j]==0:
temp= "#fffafa" #white
elif self.matrix[i,j]==1:
temp="#7CFC00" #green
my_image.put(temp,to=(i*square_w,j*square_w,(i+1)*square_w,(j+1)*square_w))
class myClass:
def __init__(self, size):
self.L=size
self.matrix=np.random.choice([-1, 0, 1], (self.L,self.L), p=[0.45,0.1,0.45])
self.white_number=len(np.where(self.matrix==0)[0])
self.iteration=0
for i in range(self.L):
for j in range(self.L):
pixel(self,i,j)
def onestep(self):
whites=np.where(self.matrix==0)# find position of all white squares
my_v= np.random.choice(self.white_number)# randomly pick one white square...
x=whites[0][my_v]
y=whites[1][my_v]
num= np.random.choice([0,1,2,3]) #...randomly pick one of its 4 neighbours
neighbour=[[(x + 1)% self.L, y], [x, (y + 1) % self.L], [(x - 1)% self.L, y], [x, (y - 1)% self.L]]
#swap with neighbour
self.matrix[x,y]=self.matrix[neighbour[num][0],neighbour[num][1]]
self.matrix[neighbour[num][0],neighbour[num][1]]=0
pixel(self,x,y) #update the pixel the white square has left
pixel(self,neighbour[num][0],neighbour[num][1]) #update the pixel the white atom has jumped to
def compute(self):
if running:
for j in range(1, self.white_number + 1):
self.onestep()
self.iteration+=1
window.after(1000,self.compute)
running=1
myObj=myClass(30)
myObj.compute()
window.mainloop()
there is any alternative to Numba which I may benefit from.
cython exists, and is more mature than numba, but it requires a compiler, so you only make compiled binaries, not JIT the functions, it provides static typing and it removes the interpreter overhead.
there is any possible logical change to the program which would separate GUI and numerical part enough to allow Numba to be applied
you actually can call a non-jitted function using numba objmode, but it still has some constraints, instead consider spliting each jitted function into a jitable part and a non-jitable part as shown
import tkinter as tk
import numpy as np
import numba
window = tk.Tk()
window.geometry("600x600")
canv_w = 480
square_w = 16 # size of one element of the matrix
canvas = tk.Canvas(window, width=480, height=480)
canvas.pack()
my_image = tk.PhotoImage(width=480, height=480)
canvas.create_image((3, 3), image=my_image, anchor="nw", state="normal")
running = 0
def pixel(matrix, i, j):
if matrix[i, j] == -1:
temp = "#cc0000" # red
elif matrix[i, j] == 0:
temp = "#fffafa" # white
elif matrix[i, j] == 1:
temp = "#7CFC00" # green
my_image.put(temp, to=(i * square_w, j * square_w, (i + 1) * square_w, (j + 1) * square_w))
#numba.njit
def _onestep(matrix, white_number, L):
whites = np.where(matrix == 0) # find position of all white squares
my_v = np.random.choice(white_number) # randomly pick one white square...
x = whites[0][my_v]
y = whites[1][my_v]
num = np.random.choice(np.array((0, 1, 2, 3))) # ...randomly pick one of its 4 neighbours
neighbour = [[(x + 1) % L, y], [x, (y + 1) % L], [(x - 1) % L, y], [x, (y - 1) % L]]
# swap with neighbour
matrix[x, y] = matrix[neighbour[num][0], neighbour[num][1]]
matrix[neighbour[num][0], neighbour[num][1]] = 0
return x,y,neighbour[num][0],neighbour[num][1]
class myClass:
def __init__(self, size):
self.L = size
self.matrix = np.random.choice([-1, 0, 1], (self.L, self.L), p=[0.45, 0.1, 0.45])
self.white_number = len(np.where(self.matrix == 0)[0])
self.iteration = 0
for i in range(self.L):
for j in range(self.L):
pixel(self.matrix, i, j)
def onestep(self):
x,y,z1,z2 = _onestep(self.matrix, self.white_number, self.L)
pixel(self.matrix, x, y) # update the pixel the white square has left
pixel(self.matrix, z1, z2) # update the pixel the white atom has jumped to
def compute(self):
if running:
for j in range(1, self.white_number + 1):
self.onestep()
self.iteration += 1
window.after(1000, self.compute)
running = 1
myObj = myClass(30)
myObj.compute()
window.mainloop()
here onestep is not jitted, while _onestep that does the heavy-lifting is jitted.
there is some speedup (11 msec with numba vs 19 msec without numba per frame) in your program because most of the time is spent drawing, not in computation, so it won't benefit from any more "compiling".
the better approach would be to store all your screen data as 2d array and manipulate it in numba then redraw your entire screen in python at once instead of part by part.
cython would probably be able to get more optimized code out of this as it can mix python and non-python objects in the same function and remove the loop overhead, but writing code for it is harder than numba.

Is there any way I can avoid Turtle slowing down the more lines it has to print?

I made a program to generate a random 2D array of 1s and 0s that I then print as green "land" tiles above a blue background to generate a little 'map'. I've tried to optimise the code as much as I know how but when I try to print anything above 100x100, it slows down by a LOT. If I set it to print line by line, I see that it's taking quite a lot longer to print lines the more of the map turtle has already printed. I don't know why this is (I don't know much about turtle or rendering in general) but I would quite like to know how to solve this problem.
If this is not possible, could I have recommendations for other libraries/languages that I could try this in? I'd like to do more programs like this and I don't mind learning something new. :)
Here is my code:
import turtle
import random
import time
d = turtle.Turtle()
d.ht()
wn = turtle.Screen()
wn.setup(width=0.45,height=0.8,startx=800,starty=50)
wn.bgcolor("#002240")
turtle.tracer(0,0)
d.penup()
interval = 10
def square(col) :
d.pendown()
d.color(col)
d.begin_fill()
for i in range(4) :
d.fd(interval)
d.right(90)
d.end_fill()
d.penup()
size = int(input("Enter map size "))
custom_interval = input("Custom interval? ")
if custom_interval != '' :
interval = int(custom_interval)
int_by_size = interval * size
start_gen = time.time()
data = []
for i in range(size) :
gen_line = []
[gen_line.append(random.randint(0,1)) for i in range(size)]
data.append(gen_line)
end_gen = time.time()
print("GEN DONE IN",end_gen-start_gen)
d.goto(-int_by_size/2,int_by_size/2)
start_draw = time.time()
d.pendown()
d.color("blue")
d.begin_fill()
for i in range(4) :
d.fd(int_by_size)
d.right(90)
d.end_fill()
d.penup()
for y,line in enumerate(data) :
for x,tile in enumerate(line) :
if tile == 1 :
square("green")
d.fd(interval)
else :
d.fd(interval)
#Comment out to print entire map at once
turtle.update()
d.backward(int_by_size)
d.sety(d.ycor()-interval)
end_draw = time.time()
print("DRAW DONE IN",end_draw-start_draw)
wn.exitonclick()
My rework of your code below speeds up the drawing by an order of magnitude by switching from drawing to stamping and other tricks:
from turtle import Screen, Turtle
from random import randint
import time
CURSOR_SIZE = 20
interval = 10
size = int(input("Enter map size: "))
custom_interval = input("Custom interval: ")
if custom_interval != '':
interval = int(custom_interval)
int_by_size = interval * size
screen = Screen()
screen.setup(width=0.45, height=0.8, startx=800, starty=50)
screen.bgcolor('#002240')
screen.tracer(False)
x, y = interval/2 - int_by_size/2, int_by_size/2 - interval/2
start_gen = time.time()
data = [(randint(False, True) for _ in range(size)) for _ in range(size)]
print("GEN DONE IN", time.time() - start_gen)
start_draw = time.time()
turtle = Turtle()
turtle.hideturtle()
turtle.shape('square')
turtle.penup()
turtle.color('blue')
turtle.shapesize(int_by_size / CURSOR_SIZE)
turtle.stamp()
turtle.color('green')
turtle.shapesize(interval / CURSOR_SIZE)
turtle.goto(x, y)
for line in data:
dx = x
for tile in line:
if tile:
turtle.setx(dx)
turtle.stamp()
dx += interval
# Comment out to print entire map at once
screen.update()
y -= interval
turtle.goto(x, y)
print("DRAW DONE IN", time.time() - start_draw)
screen.tracer(True)
screen.exitonclick()
Some of my optimizations you may need to undo, like making the data a list of generators instead of a list of lists (speeds up data generation but is only good for a single pass.) Also, remember that a window size of width=0.45, height=0.8 is relative to the size of your screen -- other folks running on other screens will get a different size window.

Improving Chaos Game efficiency

I've written this script to use the turtle module to replicate the Chaos Game I saw on Numberphile's channel. There are a large amount of dots being drawn to actually make it work well in a larger scale. I assume the large amount of dots is what causes the program to begin running slower after a bit and I was wondering if anyone could help me come up with a workaround for this.
I'm open for any kind of solution, as long as the controls remain the same and the number of vertexes can be any number above 3.
If someone doesn't know what the Chaos Game is, it's a game where you have polygon with any amount of vertexes. At first you place a dot inside the polygon, randomly choose one of the vertexes and draw a new dot halfway in-between the dot you just placed earlier and the randomly chosen vertex. You keep repeating this process and each time you'll use the newly drawn dot.
In this script I've also included a rule to make sure it doesn't choose the same vertex two times in a row to form nice fractals with more than 3 vertexes. 3 vertexes actually forms the Sierpinski triangle.
Here's a link to Numberphile's video: https://www.youtube.com/watch?v=kbKtFN71Lfs
As you can probably tell, I'm somewhat new to Python and coding in general.
Full code:
import turtle as t
import tkinter as tk
from tkinter import ttk
from random import randint
wn = t.Screen()
wn.colormode(255)
t.pu();t.ht();t.speed(0)
plist = []
l = 0
val = 0
pb=ttk.Progressbar(orient="horizontal",length=wn.window_width(),mode="determinate")
pb.pack(side=tk.BOTTOM)
pb["value"]=0
def Clear():
t.clear()
plist = []
def Dot(x, y):
t.goto(x, y)
t.dot(5, (0, 0, 255))
plist.append(t.pos())
def Run(x, y):
wn.onscreenclick(None)
wn.tracer(0, 0)
l = len(plist)
pb["maximum"]=l*1000
xyc = randint(0, l-1)
xyc_old = 0
for _ in range(l*10):
xyc = randint(0, l-1)
for i in range(100):
xyc = randint(0, l-1);
if l >= 4:
while xyc == xyc_old:
xyc = randint(0, l-1);
xyc_old = xyc;
t.goto((t.pos()[0]+plist[xyc][0])/2, (t.pos()[1]+plist[xyc][1])/2);
t.dot(2, (255, 0, 0));
pb["value"]+=1;
pb.update()
wn.update()
plist.clear()
wn.onscreenclick(Dot, btn=1)
wn.onscreenclick(Run, btn=3)
wn.onscreenclick(Dot, btn=1)
wn.onscreenclick(Run, btn=3)
wn.onkey(Clear, "c")
wn.listen()
wn.mainloop()
I feel like my coding style is very different from a lot of the people on here, but I hope that isn't an issue.
Thank you!
I assume the large amount of dots is what causes the program to begin
running slower after a bit and I was wondering if anyone could help me
come up with a workaround for this.
Surprisingly, no. It's your own instrumentation (progress bar) slowing you down. Comment out:
pb.update()
and watch what happens.
I feel like my coding style is very different from a lot of the people
on here, but I hope that isn't an issue.
It's an issue where it overlaps with bad coding style. E.g. lack of white space, use of semicolons, effective no-ops in the code, etc. My rework of your code:
from turtle import Screen, Turtle
import tkinter as tk
from tkinter import ttk
from random import randrange
def clear():
turtle.clear()
plist.clear()
def dot(x, y):
turtle.goto(x, y)
turtle.dot(5, 'blue')
plist.append(turtle.position())
def run(x, y):
screen.onscreenclick(None, btn=1)
screen.onscreenclick(None, btn=3)
screen.onkey(None, 'c')
length = len(plist)
flag = length >= 4
pb['maximum'] = length * 1000
xyc_old = 0
for _ in range(length * 100):
for _ in range(10):
xyc = randrange(length)
if flag:
while xyc == xyc_old:
xyc = randrange(length)
xyc_old = xyc
x, y = turtle.position()
dx, dy = plist[xyc]
turtle.goto((x + dx) / 2, (y + dy) / 2)
turtle.dot(2)
pb['value'] += 10
pb.update()
plist.clear()
pb['value'] = 0
screen.onscreenclick(dot, btn=1)
screen.onscreenclick(run, btn=3)
screen.onkey(clear, 'c')
plist = []
screen = Screen()
screen.tracer(False)
turtle = Turtle()
turtle.hideturtle()
turtle.setundobuffer(None)
turtle.color('red')
turtle.penup()
pb = ttk.Progressbar(orient='horizontal', length=screen.window_width(), mode='determinate')
pb.pack(side=tk.BOTTOM)
pb['value'] = 0
screen.onscreenclick(dot, btn=1)
screen.onscreenclick(run, btn=3)
screen.onkey(clear, 'c')
screen.listen()
screen.mainloop()
Other changes include:
The plist = [] in Clear() won't work without a global plist. Use plist.clear() instead.
You also need to disable (and reenable) wn.onkey(Clear, "c") during Run otherwise your user can break the program. You also need to disable the two mouse buttons independently.
You really want randrange(), not randint().

drawing a slope in random circles python

So my program is designed to manipulate certain coordinates in order to create this image:
So basically my program draw a bunch of random circles and I have to manipulate the line of equation to create the red sections. So far my image is the following:
I can't seem to figure out how to add another line equation to create the other red section. Any help would be greatly appreciated!
# using the SimpleGraphics library
from SimpleGraphics import *
# tell SimpleGraphics to only draw when I use the update() function
setAutoUpdate(False)
# use the random library to generate random numbers
import random
# size of the circles drawn
diameter = 15
resize(600, 400)
##
# returns a vaid color based on the input coordinates
#
# #param x is an x-coordinate
# #param y is a y-coordinate
# #return a colour based on the input x,y values for the given flag
##
def define_colour(x,y):
##
#add your code to this method and change the return value
slopeOne = (200 - 300)/(0-150)
b = 0 - (slopeOne * 200)
slopeTwo = (0-300)/(200 - 800)
b = 150 - (slopeTwo * 40)
lineEquationOne = (slopeOne * x) + b
lineEquationTwo = (slopeTwo * x) + b
if y > lineEquationOne:
return "red"
elif y > lineEquationTwo:
return "red"
else:
return 'white'
######################################################################
#
# Do NOT change anything below this line
#
######################################################################
# repeat until window is closed
while not closed():
for i in range(500):
# generate random x and y values
x = random.randint(0, getWidth())
y = random.randint(0, getHeight())
# set colour for current circle
setFill( define_colour(x,y) )
# draw the current circle
ellipse(x, y, diameter, diameter)
update()
You're almost there. Add back in the commented lines for your second slope and equation and make sure your variable names match up. Then you just need to add an OR condition for your if statement to set the color based on each equation.
# using the SimpleGraphics library
from SimpleGraphics import *
# tell SimpleGraphics to only draw when I use the update() function
setAutoUpdate(False)
# use the random library to generate random numbers
import random
# size of the circles drawn
diameter = 15
resize(600, 400)
##
# returns a valid color based on the input coordinates
#
# #param x is an x-coordinate
# #param y is a y-coordinate
# #return a colour based on the input x,y values for the given flag
##
def define_colour(x, y):
slopeOne = (200 - 300) / (0 - 150)
b = 0 - (slopeOne * 200)
slopeTwo = (200 - 300) / (0 - 150)
b2 = -50 - (slopeTwo * 200)
lineEquationOne = (slopeOne * x) + b
lineEquationTwo = (slopeTwo * x) + b2
if (y > lineEquationOne) | (y < lineEquationTwo):
return "white"
else:
return 'red'
######################################################################
#
# Do NOT change anything below this line
#
######################################################################
# repeat until window is closed
while not closed():
for i in range(500):
# generate random x and y values
x = random.randint(0, getWidth())
y = random.randint(0, getHeight())
# set colour for current circle
setFill(define_colour(x, y))
# draw the current circle
ellipse(x, y, diameter, diameter)
update()

Randomly orientated lines drawn off a random point in python

I'm trying to create python program that has several vertical lines which act as boundaries where randomly generated points or "dots" (as referred to in the code) which draw a straight line at a random degree. If the straight line intersects with one of the vertical "boundaries" I want to make it change colour. I have a picture of what I am trying to achieve which will probably explain my situation a bit clearer. The code I post below has drawn the "vertical boundaries" and has the points randomly generated within the region, however that is where I am stuck.
What I am aiming to achieve:
Example of program
My current Code:
setup(750,750)
screen_size = 750
max_coord = (screen_size - 30) / 2
### change the number of dots you have via that variable
num_dots = 500
bgcolor('yellow')
dot_size=5
reset() # Create an empty window
pi = Turtle()
hideturtle()
def parallel_lines(number):
pi.pensize(2)
pi.pencolor('black')
width = pi.window_width()
height = pi.window_height()
pi.setheading(90)
pi.penup()
pi.setposition(width/-2, height/-2)
for i in range(1, number +2):
pi.pendown()
pi.forward(height)
pi.penup()
pi.setposition(width/-2+i*(width/(number+1)),height/-2)
parallel_lines(7)
## centre turtle back in the middle of the page
goto(0,0)
### list to hold the dots
x_coords = []
y_coords = []
### Draw the dots via randomint
penup()
color("blue")
for dot_num in range(num_dots):
dot_pos_x = randint (-max_coord, max_coord)
dot_pos_y = randint (-max_coord, max_coord)
goto(dot_pos_x, dot_pos_y)
dot(dot_size)
x_coords.append(dot_pos_x)
y_coords.append(dot_pos_y)
done()
Thank you in advance for anyone that can help.
Here's an implementation of the program the OP describes. If there is a line intersection, it uses Python 3 turtle's undo feature to remove the line and redraw it in the alternate color:
from turtle import Turtle, Screen
from random import randint, randrange
SCREEN_SIZE = 750
PLANK_COUNT = 8
PINHEAD_SIZE = 5
FLOOR_COLOR = "yellow"
DEFAULT_COLOR = "blue"
CROSSING_COLOR = "red"
screen = Screen()
screen.setup(SCREEN_SIZE, SCREEN_SIZE)
screen.bgcolor(FLOOR_COLOR)
# configure numbers to replicate Lazzarini's setup
NUMBER_PINS = 3408
PIN_LENGTH = 78.125
PLANK_WIDTH = screen.window_width() / PLANK_COUNT
def parallel_lines(turtle, width, height):
turtle.penup()
turtle.setheading(90)
turtle.sety(height / -2)
x_coordinates = []
for i in range(PLANK_COUNT + 1):
x = i * PLANK_WIDTH - width / 2
turtle.setx(x)
turtle.pendown()
turtle.forward(height)
turtle.penup()
turtle.left(180)
x_coordinates.append(x)
return x_coordinates
pi = Turtle(visible=False)
pi.speed("fastest")
x_coordinates = parallel_lines(pi, screen.window_width(), screen.window_height())
def crosses(x0, x1, coordinates):
for coordinate in coordinates:
if x0 <= coordinate <= x1 or x1 <= coordinate <= x0:
return True
return False
previous_crossings = crossings = 0
max_coord = screen.window_width() / 2
for pin in range(NUMBER_PINS):
x0, y0 = randint(-max_coord, max_coord), randint(-max_coord, max_coord)
pi.color(DEFAULT_COLOR)
pi.goto(x0, y0)
pi.dot(PINHEAD_SIZE)
pi.setheading(randrange(360))
pi.pendown()
pi.forward(PIN_LENGTH)
if crosses(x0, pi.xcor(), x_coordinates):
pi.undo()
pi.color(CROSSING_COLOR)
pi.dot(PINHEAD_SIZE)
pi.forward(PIN_LENGTH)
crossings += 1
pi.penup()
if previous_crossings != crossings:
estimate = (2 * PIN_LENGTH * pin) / (PLANK_WIDTH * crossings)
print(estimate)
previous_crossings = crossings
screen.exitonclick()
Now for the rest of the story. What the OP didn't mention is that this is a drawing of planks in a floor, and we're dropping pins onto it, keeping track of how many cross lines in the flooring, as a means of estimating the value of PI (π)!
Read about Buffon's needle for details. The gist is the probability of a pin crossing a line is a function of PI so we can turn the equation around, drop actual (or virtual) pins, to estimate PI.
The program outputs the running estimate for PI (π), based on pins dropped so far, to the console:
...
3.121212121212121
3.1215970961887476
3.1370772946859904
3.134418324291742
3.131768953068592
3.1381381381381384
3.1384892086330933
3.1358467983243568
3.1451612903225805
3.1454979129397733
3.1458333333333335
3.1491384432560903
3.1465005931198102
3.1438721136767316
3.144208037825059
3.144542772861357
3.1419316843345113

Categories