Plotting a sequence with lines at 90 degree angles in Matplotlib

Viewed 442

I want to plot Recamán's sequence (more info on the sequence here) in a way where a line with a length equal to the first element is drawn, then a line is drawn perpendicular and starting at the end of the first line, with a length equal to the second element, et cetera.

My code is as follows:

import matplotlib.pyplot as plt
import numpy as np
import math

def pal(point, angle, length): #this plots a line starting at (point), with
    # unpack the first point    #certain angle and length
    x, y = point

    # find the end point
    endy = y + length * math.sin(math.radians(angle)) #calculates change in y and adds to starting value
    endx = x + length * math.cos(math.radians(angle)) #calculates change in x and adds to starting value

    # plots the line with the starting coordinate and the calculated end coordinate
    ax.plot([x, endx], [y,endy])

# end of plot function code

#this is where the elements of the recaman sequence get calculated and added to an array
recaman = []
crn = 0
elements = 100

for i in range(1, elements):
    recaman.append(crn)
    if (crn - i in recaman) or (crn - i < 0):
        crn = crn + i
    else:
        crn = crn - i
#end of recaman calculation

x = 0
y = 0
angle = 0
length = 0

fig, ax = plt.subplots() #creating figure
for i in range(1, elements):
    length = recaman[i-1]   #obtain length of next line
    pal((x, y), angle, length)  #((starting coordinate),
                                # angle of line relative to x-axis, length of line)
    if angle == 270: #resets angle to 0 to complete one full rotation
        angle = 0
    else:
        angle = angle + 90 #adds 90 to angle to draw perpendicular line

    y = y + length * math.sin(math.radians(angle)) #moves the new starting point to the old end point
    x = x + length * math.cos(math.radians(angle))
plt.show()

Expected result looks like this: Manual drawing of expected results

Actual result is, well, not that: Results

I've intensely studied my code several times trying to figure out what I'm doing wrong but it all looks good to me. A need the help of someone with a keener eye than mine.

2 Answers

Just need to reorder some statements. Pull your x and y update equations before you update the angle.

    y = y + length * math.sin(math.radians(angle))  # moves the new starting point to the old end point
    x = x + length * math.cos(math.radians(angle))

    if angle == 270:  # resets angle to 0 to complete one full rotation
        angle = 0
    else:
        angle = angle + 90  # adds 90 to angle to draw perpendicular line

enter image description here

Slightly different approach by hardcoding the directions into a cycler that gives back the directions North - West - South - East - North etc. Allows us to directly keep the plotting in the loop that calculates the sequence. For fun and entertainment, I made it also show the plot interactively so that we can see the development of the sequence.

import matplotlib.pyplot as plt
from itertools import cycle

#this iterator cycles through the four directions
NWSE = cycle([[0, 1], [-1, 0], [0, -1], [1, 0]])

fig, ax = plt.subplots()

plt.ion()
plt.show()

recaman = []
crn = 0
elements = 100
#xy keeps track of the coordinates to plot as [[x1, x2], [y1, y2]]
xy= [[0, 0], [0, 0]]

for i in range(1, elements):
    recaman.append(crn)
    if (crn - i in recaman) or (crn - i < 0):
        crn = crn + i
    else:
        crn = crn - i
    
    #plotting
    xy = [[coordxy[1], coordxy[1] + direction * crn] for coordxy, direction in zip(xy, next(NWSE))]
    plt.plot(*xy)
    #here you can speed it up with smaller values
    plt.pause(0.2)

input("press key")
plt.close()

The output is, unsurprisingly, the same: enter image description here

Related