As I mentioned in the last post, I think I will add squares and triangles to the mix of shapes available for random selection. Then look at how the selection of shapes affects gnarly style plots. Well perhaps a quick look at simple curves using all the shapes randomly selected by wheel.

Refactor spiro_plotlib and Test Module

I figured it was time these shape functions made their way into the the spirograph plotting package. Along with the two new curve generation functions and any related functions. So before moving on, I am going to do some refactoring of that package.

I added some new package variables to support the new functions. Then refactored set_spiro to account for them. I added the new shape functions and refactored them to use the global package variables as appropriate. I refactored the two curve generating functions to also use package variables as appropriate and to return the set of curves produced for each wheel to the caller.

And, there was one other issue I wanted to resolve. You may have noticed in the last post that the curve generated using ellipses looked very much like that generated using circles. That is a consequence of using get_radii for the widths and heights. This will result in a good many ellipses being almost circular rather than obviously elliptical. So, in the ellipse generator I am going to get a random valued multiplier, \(1.25 <= mult < 1.75\) and use it to enlarge either the width or the height argument. I will make the larger of the two larger yet. If they are equal, I’ll randomly select the one to increase.

Because I like to collect information, I append the modified widths/heights to package list variables. I then use those variables to print the final ellipse heights/widths to the terminal.

I started a new test module for this post. Copied over the necessary bits of code from the previous post’s module. And, refactored to use the new spiro_plotlib functions and variables.

I am not going to include the code in this post. It is afterall rather lengthy. And, if you have been writing the code along with me, you will be able to make the changes yourself. But, I will add a link to my version of the code at the end of the post.

Test Output

And, a test or two was of course required. Here’s one of them.

(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py -pm
tri: 3, k_f: 2, cgv: 1
widths: [1, 0.6406070622033768, 0.3804640068230001]
([1, 0.6406070622033768, 0.3804640068230001]),
heights: [1, 0.6197920191734487j, 0.4733774792736711]
([1, 0.6197920191734487, 0.4733774792736711]),
freqs: [1, 9, -7]
ln wd: 2, ln alpha: 0.9, ln keep: 2
ellipse widths: [1, 0.8577087955841012, 0.3804640068230001, 1.0878148523275541, 0.3804640068230001]
ellipse heights: [1.3307, 0.6197920191734487, 0.7637472250601409, 0.6197920191734487, 0.8227300589776403]
plot showing curves generated by each of 6 shape types and randomly selected shapes for each wheel for a given set of random curve parameters

‘Gnarly’ Plots

I added a parameter to determine whether the script should generate gnarly plots or simple curves. Then modified anywhere there was a plot generated to check the gnarly state and proceed accordingly. Fairly simple, as I had already been generating a random lines to keep variable. I also modified the function that generated the plot titles to add the value of that variable as appropriate. Gnarly plots are currently the default.

For one of the cases, that if block looked like the following.

  if p_gnarly:
    f_ttl = get_plt_ttl(shp=su, lk=ln_kp)
    plt.plot(t_xs[-ln_kp:], t_ys[-ln_kp:], alpha=alph, lw=ln_w)
    if xtra:
      plt.plot(t_xs[-1], t_ys[-1], alpha=alph)
  else:
    plt.plot(t_xs[-1], t_ys[-1], alpha=alph)

And here’s a number of examples.

Generating a figure with 8 subplots, at 540 points per subplot, does take a noticeable amount of time. Tried with lesser numbers of points but didn’t like the resulting images.

(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py -pm
tri: 6, k_f: 3, cgv: 1
widths: [1, 0.530161790917494, 0.4054635892855651, 0.20689825348373975j, 0.1640323745691004j, 0.15508685110636047j]
heights: [1, 0.5221108627882458, 0.26829793060644663j, 0.23705560514880392, 0.1565022613120265, 0.13477931180669667]
freqs: [4, -2, -11, -2, 7, 13]
ln wd: 16, ln alpha: 0.94, ln keep: 3
colormap: plt.cm.viridis
ellipse widths: [1, 0.735599484898023, 0.6976001053658147, 0.20689825348373975, 0.23522242513208994, 0.21006513982356526, 0.2704869770146033, 1, 0.6935049231140304, 0.21521402328029643]
ellipse heights: [1.3438, 0.5221108627882458, 0.26829793060644663, 0.31374309341444195, 0.1565022613120265, 0.13477931180669667, 0.13477931180669667, 1.3001, 0.26829793060644663, 0.13477931180669667]
plot showing gnarly curves generated by each of 6 shape types and randomly selected shapes for each wheel for a given set of random curve parameters
(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py -pm
tri: 3, k_f: 2, cgv: 1, points: 540
widths: [1, 0.7378150885197894, 0.687247845871461]
heights: [1, 0.6290848967781404, 0.6079902166906168j]
freqs: [3, -5, 1]
ln wd: 3, ln alpha: 0.84, ln keep: 2
colormap: plt.cm.PuBu_r
ellipse widths: [1.6865, 1.2439562392443648, 1.073000061759112]
ellipse heights: [1, 0.6290848967781404, 0.6079902166906168]
plot showing gnarly curves generated by each of 6 shape types and randomly selected shapes for each wheel for a given set of random curve parameters
(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py -rs
tri: 4, k_f: 3, cgv: 1, points: 540
widths: [1, 0.5377054048834958, 0.3801311865436369j, 0.24290198793804368]
heights: [1, 0.7141326648605296j, 0.5810123575144078j, 0.30107614087591267]
freqs: [1, 10, -5, 13]
ln wd: None, ln alpha: 0.66, ln keep: 2
current shape: e
colormap: plt.cm.GnBu_r
ellipse widths: [1, 0.5377054048834958, 0.3801311865436369, 0.24290198793804368]
ellipse heights: [1.6596, 1.0595586348535677, 0.9764493680387138, 0.4498980773108763]
plot showing gnarly curve generated by elliptical wheels
(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py
tri: 5, k_f: 5, cgv: 1, points: 540
widths: [1, 0.6409060234031296j, 0.42799281427896235j, 0.24455781079818184j, 0.12592841451022968]
heights: [1, 0.7451040066772976, 0.4811601708036922, 0.27569337290658147, 0.24136378432451636j]
freqs: [6, -4, 1, 11, -14]
ln wd: 18, ln alpha: 0.74, ln keep: 2
shapes used: ['c', 's', 'd', 't', 's']
colormap: plt.cm.GnBu_r
plot showing gnarly curve generated by randomly shaped wheels
(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py
tri: 3, k_f: 3, cgv: 1, points: 540
widths: [1, 0.5171896926900816j, 0.2947567641954297j]
heights: [1, 0.7070814710463607j, 0.6411047823657926j]
freqs: [4, -8, 10]
ln wd: 1, ln alpha: 0.88, ln keep: 2
shapes used: ['e', 't', 'd']
colormap: default
ellipse widths: [1.4332]
ellipse heights: [1]
plot showing gnarly curve generated by randomly shaped wheels
(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py
tri: 6, k_f: 3, cgv: 1, points: 1000
widths: [1, 0.5147813587531103, 0.3734176712993233, 0.2944492266522525j, 0.21250385303994024, 0.1501514943319673j]
heights: [1, 0.5033372670288552j, 0.28384992077912624, 0.2821617462309918, 0.23233961629456223j, 0.2198424638440262]
freqs: [1, -2, -11, 13, -2, 10]
ln wd: 11, ln alpha: 0.74, ln keep: 3
shapes used: ['e', 'd', 's', 'd', 'e', 'c']
colormap: plt.cm.PuBu_r
ellipse widths: [1.6894, 0.21250385303994024]
ellipse heights: [1, 0.38665958943741047]
plot showing gnarly curve generated by randomly shaped wheels
(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py
tri: 4, k_f: 4, cgv: 2, points: 1000
widths: [1, 0.6331477787825252j, 0.43908393532699785, 0.39381206320847073]
heights: [1, 0.5364877495770439, 0.3228686620374355, 0.31917860103617124j]
freqs: [-2, -14, -14, -10]
ln wd: 15, ln alpha: 0.91, ln keep: 2
shapes used: ['s', 'c', 't', 't']
colormap: plt.cm.viridis
plot showing gnarly curve generated by randomly shaped wheels

And why not a few more, all using a tetracuspid as the shape for each wheel.

(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py -rs
tri: 7, k_f: 3, cgv: 2, points: 1000
widths: [1, 0.5373497676855901, 0.4167527824078185, 0.34618097189543084, 0.18461799145616836, 0.1478211288241785, 0.125]
heights: [1, 0.5595606280691885, 0.5491096467063127, 0.3678391839317134j, 0.3313917979761779j, 0.28471065175490906j, 0.23157311505154896j]
freqs: [5, 8, -4, 11, -4, -1, 14]
ln wd: None, ln alpha: 0.69, ln keep: 3
current shape: t
colormap: plt.cm.hot
plot showing gnarly curve generated by tetracuspid wheels
(ani-3.10) PS R:\learn\py_play\spirograph> python s13.test.py -rs
tri: 3, k_f: 3, cgv: 2, points: 1000
widths: [1, 0.5129474842427393j, 0.4627698991149094]
([1, 0.5129474842427393, 0.4627698991149094]),
heights: [1, 0.7453230386851213, 0.6252067430942269j]
([1, 0.7453230386851213, 0.6252067430942269]),
freqs: [5, 11, -1]
ln wd: 3, ln alpha: 0.88, ln keep: 2
current shape: t
colormap: plt.cm.PuBu_r
plot showing gnarly curve generated by tetracuspid wheels

You know, I think I like the ones with the thinner lines over the ones with thick, overlapping lines. And the ones with less wheel activity. I also seem to prefer the ones with the final curve plotted over the gnarly plot. A good many of the ones I looked at end up having too many lines in the curve, or are way too crowded with the gnarly version.

Done

That’s it for this one. A little short on code, but a decent number of images.

That said, this post has lot’s of code for you to look at: Spirograph XIII: Code Multiple Wheel Shapes II

Until next time, have fun coding. And maybe playing with spirographs of all types.