Long before this will get published, I looked back at some old images. And, a group of them made me feel they should be included in my spirograph app. They are a variation on the cycling line width using scatter plot image type. Currently in the app only I only use circle shaped markers for the scatter plots. But in my local python module I experimented with using the other marker types. And some of those generated some, to me, interesting images. So, I have decided to add them to the on-line app.

Other Marker Types

It was fairly simple to get the /spirograph/basic_clw route to use alternate marker types. I simply added g.mrk_rnd = True to the route function before I made the call to sal.cycle_lw(). And bingo. Though I also had to fix a bug in my code in that function.

I had the following in the function.

  if g.mrk_rnd:
    m1 = rng.choice(g.poss_mrkrs)
    # 50% of the time use different marker for 2nd plotting loop
    if rng.integers(0, 1) == 1:
      m2 = rng.choice(g.poss_mrkrs)
    else:
      m2 = m1
  else:
    m1= 'o'

Which of course never ever set m2 to something different to m1. That’s because rng.integers(0, 1) always returns 0. So, I changed that to if rng.integers(0, 2) == 1: and bingo!

Image Boundaries

But, I had issues with the generated spirograph at times exceeding the image limits or very nearly so. Would make it hard to print and frame should I wish to do so. I have whenever generating the images tried to maintain a margin that would allow for the matting to overlap the coloured background. But, because I am using various shapes and sizes of markers for the scatter plot some times the markers were big enough to exceed my default margin(s). As it turns out, something I didn’t realize, some of the markers are taller than they are wide or wider than they are tall. Which is, of course, another complication.

I started out trying to estimate and hardcode the margin size given a range of marker sizes. And applying a bit of extra for certain marker shapes. Really not a sustainable approach. So I started searching for some way to use arithmetic to help me out.

There’s a couple of different numbers that could get involved. But as I am changing the marker size for each block of colour, I am setting the marker size using the s parameter of the method call to scatter() on the current plot axes.

It turns out this number is an area like value. It’s square root determines the number of points for each dimension of the marker. Well, rather for the possible bounding box for the marker. But there are those exceptions. However, if I work out the width of the box, in points, and compare that to the width of drawing area, in points, I should get some idea of what my new plot margins should be.

So let’s give that a go. I added the following just below the above code and before I plotted anything and/or called autoscale(). I do the latter just before starting the loops doing the plotting.

  m_pts = mx_sz**0.5
  ppd= 72. / axt.figure.dpi
  img_ext = axt.get_window_extent().width
  x_mrg = m_pts / img_ext
  y_mrg = x_mrg
  axt.margins(x_mrg, y_mrg, tight=None)

And, that actually seems to work rather well. A few images have larger looking margins than I would like. And in some cases the margins aren’t quite big enough. This I believe is related to where in the curve the maximum marker sizes are plotted. If they are more often inside the curve rather than on the outside edges, the margins look larger. This can also happen from side to side or top to bottom. The bottom quite often has what looks to be a smaller margin.

cycling line width example using scatter plot and alternate marker types
CLW using alternate scatterplot markers

In the above image the marker types are ‘D’ and ‘*’. ‘D’ is one of the problematic marker types. The other is ’d’. In the image you can see that the top margin looks a fair bit smaller than the bottom one. And the left one looks a little bit smaller than the right margin. That is mostly due to the fact that the largest ‘D’ markers at the outside edges of the spirograph are at the top and on the left. The next section will hopefully clarify why that is the case.

Compare Marker ‘Sizes’

Based on something I read I decided to plot a series of square markers of a given size, then overplot them with each of the marker types I am using, g.poss_mrkrs. Here’s the code and the resulting graph. After my first plot, I added to horizontal and vertical lines to help me figure out the difference in x and y dimensions. Manually adjusting the position until I got what looked to be about right.

import matplotlib.pyplot as plt

import g_vars as g

fig, ax = plt.subplots()

ax.set_ylim(1, 5)
nbr_mrkr = 1
y = 4

ax.axvline(22.8, lw=1, c='k')
ax.axhline(2.66, lw=1, c='k')

for mrkr in g.poss_mrkrs:
  ax.scatter([nbr_mrkr * 10],[y], s=1000, marker='s', c='#ccc')
  ax.scatter([nbr_mrkr * 10],[y], s=1000, marker=mrkr, c='b')

  nbr_mrkr += 1
  if nbr_mrkr % 6 == 0:
    y -= 1
    nbr_mrkr = 1

plt.show()
chart comparing marker coverage by marker type
Comparing Marker Types

As you can see, the ‘D’ marker extents beyond the box in both directions and the ’d’ marker only in the y direction. My code to determine a suitable autoscaling margin would not cover those extensions. And, if the largest markers where along an axis at the outside edges of the spirograph, the margin would disappear.

Fix or No Fix?

Case in point.

Cycling Line Width
    Marker 1: d
    Marker 2: D
    Maximum marker size: 7500
    Half marker cycle frequency: 256 based on 4 cycles
    Starting position: 0
    Axes margin: 0.15035163260146503
cycling line width example showing effect of D and d type markers on margins
CLW showing effect of 'D' and 'd' type markers

With the largest diamonds at the top and bottom, the top and bottom margins disappear. This is due to the portions of the diamonds extending beyond the ‘marker box’ I was using to calculate the adjusted margin value.

But I have decided not to worry about adding a correction for those marker types. If I decide to repeat any such image, I can deal with the issue at that time. For on-line display in the app, not a problem.

Examples

A few examples of ones I liked to close out this post.

cycling line width by scatterplot using various marker types
CLW by scatterplot using various marker types
Cycling Line Width
    Marker 1: 4
    Marker 2: 4
    Maximum marker size: 9500
    Half marker cycle frequency: 51 based on 20 cycles
    Starting position: 0
    Axes margin: 0.12
cycling line width by scatterplot using various marker types
CLW by scatterplot using various marker types
Cycling Line Width
    Marker 1: 4
    Marker 2: 4
    Maximum marker size: 8500
    Half marker cycle frequency: 256 based on 4 cycles
    Starting position: 0
    Axes margin: 0.105
cycling line width by scatterplot using various marker types
CLW by scatterplot using various marker types
Cycling Line Width
    Marker 1: h
    Marker 2: 2
    Maximum marker size: 5500
    Half marker cycle frequency: 64 based on 16 cycles
    Starting position: 0
    Axes margin: 0.11000000000000001
cycling line width by scatterplot using various marker types
CLW by scatterplot using various marker types
Cycling Line Width
    Marker 1: p
    Marker 2: 1
    Maximum marker size: 8500
    Half marker cycle frequency: 73 based on 14 cycles
    Starting position: 0
    Axes margin: 0.12650000000000003

Done

That’s it for this one. Next time I will look at adding this image type to my repeat route. Will need to account for the changed margins. Likely a new or refactored drawing function as well.

Resources