The only person that I know has been reading this series of posts was always a touch discomposed by the asymmetry of the images. Which is very much the outcome of how the data is generated (from the angles around wheels), the use of wheels of various shapes and the order in which things are plotted. And, in the case of the gnarly plots a whole bunch of other complications.

But, because he has been so supportive of my experiment, I decided to play around a little and see what I might be able to do about reducing the visual asymmetry. I primarily focused on the new version of the “cycling line width” images. Though in fact, once the method is activated, it would be applied to any image style I selected. Just don’t think it would do much for all the various image types.

Attempt #1

I decided I’d reverse the order of the second half of the plotting data. I do so for all the data rows, not just the final one used for producing this type of image.

Again, the current state of my do-it-all module is bloody awful and most embarrassing. So, I will show some of the code additions/modifications, but there will be no complete module for viewing or downloading.

I have a function that I use to generate the gnarly curve data given a complete set of x and y data for each wheel for the given curve. Its signature was get_gnarly_dset(f_xs, f_ys, l_drp, frm_f). I added a new parameter: get_gnarly_dset(f_xs, f_ys, l_drp, frm_f, do_sym=False). If do_sym is true the function will, for each row in the data, call another function, get_sym_curve(f_x). It in fact does so twice, once for the x data and again for the y data.

I decided to plot the reversed half first, rather than in its initial 2nd postition. I felt that even if the change did not improve the visual symmetry, it would hopefully look a little different. Which in and of itself might give me another option for generating images.

def get_sym_curve(f_x):
  m_pt = t_pts // 2
  r_x = [*f_x[m_pt:][::-1], *f_x[:m_pt]]
  return r_x

Since I generate the gnarly dataset for every loop of the module, I can use it to generate a hopefully more symmetrical image. I added a global variable to control whether symmetrical image attempts are on or off. I can flipflop the variable through the modules command line interface.

Example Results

I am going to show you a few examples of the results with some different plot types. For each example you will see an image of a base version, followed by one with an attempt to improve symmetry using the above method. You decide if the visual symmetry is improved or not.

Most of these will be using the scatter plot cycling line width style of plots. But I do have one “gnarly” as well. The method doesn’t work as well with the gnarly style. They will look different as I haven’t provided myself with a way to easily control colours or marker sizes/types.

They all use 1,000 plotting points and four cycles for colours and markers.

  1. Simulated curve with cycling line width using scatter plot, single random shape. Wheels: 12 (Circle), max marker size: 5500.
cycling line width image with attempt to improve symmetry
do sym: False => reverse 2nd half
cycling line width image with attempt to improve symmetry
do sym: True => reverse 2nd half
  1. Simulated curve with cycling line width using scatter plot, random shape for each wheel. Wheels: 5 (‘c’, ‘r’, ‘r’, ‘q’, ‘c’).
cycling line width image with attempt to improve symmetry
do sym: False => reverse 2nd half, max marker size:
cycling line width image with attempt to improve symmetry
do sym: True => reverse 2nd half, max marker size:
  1. Simulated curve with cycling line width using scatter plot, single random wheel shape, random marker shape. Wheels: 7 (Tetracuspid).
cycling line width image with attempt to improve symmetry
do sym: False => reverse 2nd half, max marker size: 2500
cycling line width image with attempt to improve symmetry
do sym: True => reverse 2nd half, max marker size: 1500
  1. Simulated curve with cycling line width using scatter plot, random shape for each wheel, random marker shape. Wheels: 4 (‘c’, ’s’, ’s’, ‘c’).
cycling line width image with attempt to improve symmetry
do sym: False => reverse 2nd half, max marker size: 3500
cycling line width image with attempt to improve symmetry
do sym: True => reverse 2nd half, max marker size: 1500

Extra image for this one. Wanted to show the effect marker size had on the resulting image. In this cases, seems to create a touch more visual symmetry with the larger marker size.

cycling line width image with attempt to improve symmetry
do sym: True => reverse 2nd half, max marker size: 10500
  1. The last one is a variation on gnarly plots. It uses a random subset of the available data, and in a random order. Which does affect the resulting image. Though, in general, gnarly plots don’t seem to be made much more symmetrical. Wheels: 5 (‘c’, ’s’, ’s’, ‘c’).

Again I don’t control the number of rows selected or their plotting order. So the images are not the same in that respect.

cycling line width image with attempt to improve symmetry
do sym: False => reverse 2nd half, rows: [4 0 3 1]
cycling line width image with attempt to improve symmetry
do sym: True => reverse 2nd half, rows: [0 3 4]

Improved, I don’t know. But definitely a hint of added symmetry in each case.

Expanded Attempt

Okay, I decided to try some other rearrangements of the plotting order. This entailed a fair bit of refactoring. With the addition of new variables and command line options to allow me to control what happens. I added options for the attempted symmetry variations and the number of cycles to be used for colour and/or “line thickness”.

Here’s the code showing the list of symmetry attempts. Well, the final list. I tested the first six before, before adding the last two.

s_typs = ["n/a",
  "reverse 2nd half",
  "reverse 1st half",
  "reverse middle half",
  "reverse 2nd and 4th quarters",
  "reverse 1st and 3rd quarters",
  "reverse 1st and 4th quarters",
  "reverse 1st, 3rd, 5th and 7th eighths",
  "reverse 2nd, 4th, 6th and 8th eighths"
]

The refactored function, get_sym_curve(), looks like this.

def get_sym_curve(f_x, typ_s):
  m_pt = t_pts // 2
  s4_pt = t_pts // 4
  e4_pt = t_pts * 3 // 4
  s8 = [t_pts // 8, s4_pt, t_pts * 3 // 8, m_pt, t_pts * 5 // 8, e4_pt, t_pts * 7 // 8]

  if typ_s == 1:
    m_pt = t_pts // 2
    r_x = [*f_x[m_pt:][::-1], *f_x[:m_pt]]
  elif typ_s == 2:
    m_pt = t_pts // 2
    r_x = [*f_x[:m_pt][::-1], *f_x[m_pt:]]
  elif typ_s == 3:
    r_x = [*f_x[s4_pt:e4_pt][::-1], *f_x[:s4_pt], *f_x[e4_pt:]]
  elif typ_s == 4:  
    r_x = [*f_x[e4_pt:][::-1], *f_x[s4_pt:m_pt][::-1], *f_x[:s4_pt], *f_x[m_pt:e4_pt]]
  elif typ_s == 5:
    r_x = [*f_x[m_pt:e4_pt][::-1], *f_x[:s4_pt][::-1], *f_x[s4_pt:m_pt], *f_x[e4_pt:]]
  elif typ_s == 6:
    r_x = [*f_x[e4_pt:][::-1], *f_x[:s4_pt][::-1], *f_x[s4_pt:m_pt], *f_x[m_pt:e4_pt]*f_x[e4_pt:][::-1]]
  elif typ_s == 7:
    r_x = [*f_x[s8[5]:s8[6]][::-1], *f_x[s8[3]:s8[4]][::-1], *f_x[s8[1]:s8[2]][::-1], *f_x[:s8[0]][::-1],
      *f_x[s8[0]:s8[1]], *f_x[s8[2]:s8[3]],*f_x[s8[4]:s8[5]], *f_x[s8[6]:]
    ]
  elif typ_s == 8:
    r_x = [*f_x[s8[6]:][::-1], *f_x[s8[4]:s8[5]][::-1], *f_x[s8[2]:s8[3]][::-1], *f_x[s8[0]:s8[1]][::-1],
      *f_x[:s8[0]], *f_x[s8[1]:s8[2]], *f_x[s8[3]:s8[4]], *f_x[s8[5]:s8[6]]
    ]

  return r_x

I won’t get into the other code changes I made to get things working the way I wanted. Nor discuss all the debugging that was required due to my logical errors and typos.

Examples

I used the same curve parameters and plot type for each of the following. Unfortunately I couldn’t control the colours nor the maximum size and/or type for the marker(s) being used in the plots. So some visual inconsistencies between images. But, hopefully, you will be able to see what is different in each version.

I will start by displaying the basic spirograph curve and the un-symmetric version of the simulated cycling line width curve.

Other than the first, they are all simulated curve with cycling line width using scatter plot, single random shape. Wheels: 8 (Circle). They all use 8 colour/marker size cycles at 1,000 plotting points.

cycling line width image with attempt to improve symmetry
base spirograph curve
cycling line width image with attempt to improve symmetry
do sym: False => reverse 1st half, max marker size: 1488

From here on I use the different methods to try to generate a sense of real symmetry.

cycling line width image with attempt to improve symmetry
do sym: True => reverse 2nd half, max marker size: 1488
cycling line width image with attempt to improve symmetry
do sym: True => reverse 1st half, max marker size: 2480

And, as one might expect, the above is essentially the reverse of the previous image.

cycling line width image with attempt to improve symmetry
do sym: True => reverse middle half, max marker size: 4464

A completely different look. With perhaps a bit more obvious symmetry.

cycling line width image with attempt to improve symmetry
do sym: True => reverse 2nd and 4th quarters, max marker size: 5456
cycling line width image with attempt to improve symmetry
do sym: True => reverse 1st and 3rd quarters, max marker size: 2480

Looks almost like a 90° rotation of the preceding image. (If we ignore the change in colours and such.)

cycling line width image with attempt to improve symmetry
do sym: True => reverse 1st and 4th quarters, max marker size: 2480

Okay, that approach certainly doesn’t appear to work for this particular curve. You’d think if reversing the middle half sort of worked, that this approach would also work. Afterall it is basically just reversing the other half of the image.

But does look like, in general, flipping quarters rather than halfs might get us closer to a symmetrical image.

cycling line width image with attempt to improve symmetry
reverse 1st, 3rd, 5th and 7th eighths, max marker size: 9486
cycling line width image with attempt to improve symmetry
reverse 2nd, 4th, 6th and 8th eighths, max marker size: 10478

And it would seem flipping eights gets us even closer to a symmetrical look than flipping quarters. I am sure there is some very good geometrical explanation, but at the moment I don’t see it.

Perhaps I’ll try sixteenths.

Done M’thinks

Looks like it is, at least with some curves, possible to generate something that looks more or less symmetrical. Especially with the simulated cycling line width images. Happens much less frequently with the gnarly style images. Which is why you only saw one compariosn of that image type in this post.

Not much in the way of code. But, if you’ve been coding along with me, I am sure you will be able to use what little is in this post for your own purposes. But, lots of images and took plenty of time, bug fixes, repeated image generation and conversion to produce this post. So I am going to call it for this one. But I believe there will yet be another post in the series.

Gary, I hope your engineering induced proclivity for symmetry found some peace with a few of these images. And, once again, thank you for providing me with the incentive to pursue this post’s experiment.