Norm Sign Generator (rewrite) I

Norm Sign Generator Installation

Norm Sign Generator Software

Connecting points

An easy way to create a grid of points is to map all points to values between 0 and 1.

For the 3x3 grid from the Sign Generator above we have 3 values within 0 and 1, so 0, 0.5, 1 on every axis:

grid 3x3

Later on this points are multiplied by a factor to increase the size of the grid.

For a larger grid it may be easier to compute this values with np.linspace()

from flat import document, shape, rgb
from IPython.display import SVG, display
import random

def show(page):
    display(SVG(page.svg()))
    

# Document setup.
width, height = 200, 200
black = rgb(0, 0, 0)
factor = width

d = document(width, height, 'pt')

# Create points.
points_x = [0, 0.5, 1]
points_y = [0, 0.5, 1]

# Draw a line between 2 random points.
p = d.addpage()

# Get 2 random coordinates (4 points) and scale them
x1 = random.choice(points_x) * factor
x2 = random.choice(points_x) * factor
y1 = random.choice(points_y) * factor
y2 = random.choice(points_y) * factor
print(f"({x1/factor}|{y1/factor}) --> ({x2/factor}|{y2/factor})\n")

line = shape().stroke(black).line(x1, y1, x2, y2)
p.place(line)

show(p)
(0.5|1.0) --> (1.0|0.0)
_images/norm_sign_generator_1_2_1.svg

Draw a grid, simplify the list of points

For visualization we’ll add a background grid.
In addition we’ll use random.choices() instead of random.choice() to pick the desired amount of random points all together.

def draw_grid(page, x, y, width, height, color=rgb(200, 200, 200)):
    for elem in list(x):
        line = shape().stroke(color).line(elem, 0, elem, height)
        page.place(line)
    for elem in list(y):
        line = shape().stroke(color).line(0, elem, width, elem)
        page.place(line)
        
        
# Document setup.
width, height = 200, 200
black = rgb(0, 0, 0)
factor = width

d = document(width, height, 'pt')
p = d.addpage()

# Create points.
points_x = [0, 0.5, 1]
points_y = [0, 0.5, 1]
          
# Append factor to the list items.
points_x = [x*factor for x in points_x]
points_y = [y*factor for y in points_y]

# Draw a grid.
draw_grid(p, points_x, points_y, width, height)

# Draw a line between 2 random points.

# Instead of calling random.choice() multiply times, we can
# call random.choices() to receive multiple values (k).
x1, x2 = random.choices(points_x, k=2)
y1, y2 = random.choices(points_y, k=2)

print(f"({x1/factor}|{y1/factor}) --> ({x2/factor}|{y2/factor})\n")

line = shape().stroke(black).width(3).line(x1, y1, x2, y2)
p.place(line)


show(p)
(1.0|0.0) --> (1.0|0.5)
_images/norm_sign_generator_1_4_1.svg

Improve grid

Lines on the border of the grid/ page are truncated. We’ll add margin to the grid to improve the output.
We’ll use numpy’s linspace() function to generate a sequence of evenly distributed numbers in a given range.

linspace() documentation: https://numpy.org/doc/stable/reference/generated/numpy.linspace.html

import numpy as np

# Test: 5 values within 0 and 100
linear_1 = np.linspace(0, 100, 5)
print(f"5 values within 0 and 100: {linear_1}")

# Test: 5 values within 0+margin and 100-margin
margin = 10
linear_2 = np.linspace(0+margin, 100-margin, 5)
print(f"5 values within 0+margin ({margin}) and 100-margin ({margin}): {linear_2}")
5 values within 0 and 100: [  0.  25.  50.  75. 100.]
5 values within 0+margin (10) and 100-margin (10): [10. 30. 50. 70. 90.]
from flat import document, shape, rgb
import random
import numpy as np
from IPython.display import SVG, display

def show(page):
    display(SVG(page.svg()))

width = height = 300 # both variables share the same value
margin = 10
grid_size = 3

# We're working on an evenly distributed grid, so it's enough to 
# generate this points for one axis and pick points for both axis.
points = np.linspace(0+margin, width-margin, grid_size).astype(int)

d = document(width, height, 'pt')
p = d.addpage()

draw_grid(p, points, points, width, height)

for i in range(5):
    x1, x2, y1, y2 = random.choices(points, k=4)
    line = shape().stroke(rgb(0, 0, 0)).width(6).cap('round').line(x1, y1, x2, y2)
    p.place(line)
    
show(p)
_images/norm_sign_generator_1_7_0.svg

The code so far returns a problem. In the Sign Generator all lines are connected between neighboring points. In our code lines are connected between random points all over the grid, so the lines are often too long and don't belong to the list of allowed components.

Instead of working with single points, we'll create a list of all allowed lines in the following notebook.