Over the last few weeks (while working on the draft refactoring posts) I found the selection of colour maps I had chosen somewhat limited. So, while not a refactoring meant to reduce repetitive code and to make things a little easier to follow, I think I am going to look at refactoring colour map selection. I will include more colour maps. And allow for a totally random selection for the image and the background. Fully realizing that choice will likely result in numerous glaring colour combinations.

Back a Step in the Refactoring

In the last post, dealing with refactoring the code for the transform routes, I said “And I still have the clw_btw_t route to look at.” Well I did look at it. The remaining, unmodified code is entirely unique to that route. If I moved it to a function it would only be called by that one route. At least until I update my repeat function to work with all the spirograph image types. So, I decided to leave that route’s code untouched for now.

Refactor Colour Selection

Back to the matter at hand.

Add More Colour Maps

I am keeping the two ‘global’ colourmap lists: clr_opt and bgcm_mpl. I realize that I could get the first from the second by using bgcm_mpl.keys(). But I figured the list is fairly small and likely less resource consuming than repeatedly calling the key() function. Now of course I could have used a function to generate the first list from the second, but it was just as easy to copy the names from the relevant matplotlib page. Generating the second list took a touch longer.

And since I won’t, for the time being, be using bg_cmap, I commented out that block of code (not shown in diff below). But I expect at some point I will be adding code to skip some spirograph and background colour map combinations. At least the truly glaring ones.

@@ -73,12 +75,22 @@ dpi_opt = ['72', '100', '300', '600']
 sz_opt = ['8', '10', '12', '14']
 sz2mrg = {'10': 0.12, '12': 0.1, '14': 0.0857}

-clr_opt = ['autumn', 'bone', 'BuGn', 'BuPu', 'cividis', 'cubehelix',
-  'cool', 'copper', 'default', 'GnBu', 'gist_earth', 'gnuplot',
-  'hot', 'inferno', 'jet', 'magma', 'plasma', 'PuBu', 'PuBuGn',
-  'PuRd', 'rainbow', 'RdPu', 'summer', 'tab20', 'tab20c', 'terrain',
-  'turbo', 'twilight_shifted', 'viridis', 'winter', 'YlGnBu', 'YlOrRd']
-
+clr_opt = ['viridis', 'plasma', 'inferno', 'magma', 'cividis',
+           'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
+            'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', 'GnBu', 'PuBu', 'YlGnBu',
+            'PuBuGn', 'BuGn', 'YlGn', 'twilight', 'twilight_shifted', 'hsv',
+            'Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2', 'Set1', 'Set2', 'Set3',
+            'tab10', 'tab20', 'tab20b', 'tab20c',
+            'ocean', 'gist_earth', 'terrain', 'gist_stern', 'gnuplot', 'gnuplot2', 'CMRmap',
+            'cubehelix', 'brg', 'gist_rainbow', 'rainbow', 'jet', 'turbo', 'nipy_spectral', 'gist_ncar'
+          ]
+
 rcm = None    # colour to use if user specified one, otherwise use current colour again ???
 cycle = []    # list of colours for current colour map (rcm)
 c_ndx = 1
PS R:\learn\py_play\sp_fa> git diff sp_app_lib.py
diff --git a/sp_app_lib.py b/sp_app_lib.py
index 8dcf81b..e43f74b 100644
--- a/sp_app_lib.py
+++ b/sp_app_lib.py
@@ -18,55 +18,81 @@ import repeats as r

 rng = np.random.default_rng()

 bgcm_mpl = {
-  'autumn': plt.cm.autumn, 'bone': plt.cm.bone, 'BuGn': plt.cm.BuGn_r, 'BuPu': plt.cm.BuPu_r,
-  'cividis': plt.cm.cividis,
-  'cubehelix': plt.cm.cubehelix, 'cool': plt.cm.cool ,'copper': plt.cm.copper,
-  'default': plt.cm.tab10, 'GnBu': plt.cm.GnBu_r,
-  'gist_earth': plt.cm.gist_earth, 'gnuplot': plt.cm.gnuplot, 'gray': plt.cm.gray,
-  'Greys': plt.cm.Greys, 'hot': plt.cm.hot, 'hsv': plt.cm.hsv, 'inferno': plt.cm.inferno,
-  'jet': plt.cm.jet, 'magma': plt.cm.magma, 'ocean': plt.cm.ocean ,'plasma': plt.cm.plasma,
-  'PuBu': plt.cm.PuBu_r, 'PuBuGn': plt.cm.PuBuGn_r, 'PuRd': plt.cm.PuRd_r, 'rainbow': plt.cm.rainbow,
-  'RdPu': plt.cm.RdPu_r, 'reds': plt.cm.Reds,
-  'summer': plt.cm.summer, 'tab20': plt.cm.tab20, 'tab20c': plt.cm.tab20c, 'terrain': plt.cm.terrain,
-  'turbo': plt.cm.turbo, 'twilight_shifted': plt.cm.twilight_shifted, 'viridis': plt.cm.viridis,
-  'winter': plt.cm.winter, 'Wistia': plt.cm.Wistia, 'YlGnBu': plt.cm.YlGnBu_r, 'YlOrBr': plt.cm.YlOrBr_r,
-  'YlOrRd': plt.cm.YlOrRd_r
+  'viridis': plt.cm.viridis, 'plasma': plt.cm.plasma, 'inferno': plt.cm.inferno, 'magma': plt.cm.magma, 'cividis': plt.cm.cividis,
+  'Greys': plt.cm.Greys, 'Purples': plt.cm.Purples, 'Blues': plt.cm.Blues, 'Greens': plt.cm.Greens, 'Oranges': plt.cm.Oranges,
+  'Reds': plt.cm.Reds, 'YlOrBr': plt.cm.YlOrBr, 'YlOrRd': plt.cm.YlOrRd, 'OrRd': plt.cm.OrRd, 'PuRd': plt.cm.PuRd,
+  'RdPu': plt.cm.RdPu, 'BuPu': plt.cm.BuPu, 'GnBu': plt.cm.BuPu, 'PuBu': plt.cm.PuBu, 'YlGnBu': plt.cm.YlGnBu,
+  'PuBuGn': plt.cm.PuBuGn, 'BuGn': plt.cm.BuGn, 'YlGn': plt.cm.YlGn, 'twilight': plt.cm.twilight,
+  'twilight_shifted': plt.cm.twilight_shifted, 'hsv': plt.cm.hsv, 'Pastel1': plt.cm.Pastel1, 'Pastel2': plt.cm.Pastel2,+  'Paired': plt.cm.Paired, 'Accent': plt.cm.Accent, 'Dark2': plt.cm.Dark2, 'Set1': plt.cm.Set1,
+  'Set2': plt.cm.Set2, 'Set3': plt.cm.Set3, 'tab10': plt.cm.tab10, 'tab20': plt.cm.tab20, 'tab20b': plt.cm.tab20b,
+  'tab20c': plt.cm.tab20c, 'ocean': plt.cm.ocean, 'gist_earth': plt.cm.gist_earth, 'terrain': plt.cm.terrain,
+  'gist_stern': plt.cm.gist_stern, 'gnuplot': plt.cm.gnuplot, 'gnuplot2': plt.cm.gnuplot2, 'CMRmap': plt.cm.CMRmap,
+  'cubehelix': plt.cm.cubehelix, 'brg': plt.cm.brg, 'gist_rainbow': plt.cm.gist_rainbow, 'rainbow': plt.cm.rainbow,
+  'jet': plt.cm.jet, 'turbo': plt.cm.turbo, 'nipy_spectral': plt.cm.nipy_spectral, 'gist_ncar': plt.cm.gist_ncar,
 }

Refactor Background Colour Map Selection

Okay, let’s have the background colour map randomly chosen from the above.

PS R:\learn\py_play\sp_fa> git diff sp_app_lib.py
diff --git a/sp_app_lib.py b/sp_app_lib.py
index 8dcf81b..e43f74b 100644
--- a/sp_app_lib.py
+++ b/sp_app_lib.py
@@ -1361,17 +1396,20 @@ def proc_curve_form(f_data, i_typ):
     g.bg_cmnm = r.d_rpt[r.do_nbr]['c_bg']
     g.bg_cmap = bgcm_mpl[g.bg_cmnm]
   elif g.use_bb2 and g.use_rand_bg:
-    g.bg_cmnm = rng.choice(bg_cmap[g.rcm])
+    g.bg_cmnm = rng.choice(g.clr_opt)
     g.bg_cmap = bgcm_mpl[g.bg_cmnm]
   else:
     g.bg_cmnm = g.rcm
     g.bg_cmap = bgcm_mpl[g.rcm]

  if 'clw_pct' in f_data:
    g.use_pct = True if f_data['clw_pct'] == 'true' else False

Test

And a test image.

test image after initial refactoring of colour map options
Test #1: New Foreground and Background Colour Map Options

Not quite what I really want. Curve’s colour map is ‘magma’. Background colour map is ‘Set1’, which is one of the new ones just added. It belongs to a category of colourmaps called Qualitative. The Tab series of colourmaps I had already been using belong to this same category. Because of the way the Tab colour map affected the display of the background I had code that reduced the alpha value when a Tab colour map was selected for the background. I now need to modify the code to do that for all the colour maps in this category.

Reduce Background Alpha Value as Appropriate

So a new list in the sp_app_lib module, just after the bgcm_mpl dictionary. Not sure about the name, but…

bg_qualitatives = [
  'Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2', 'Set1', 'Set2', 'Set3',
  'tab10', 'tab20', 'tab20b', 'tab20c'
]

And some refactored code in a couple of places. The first is setting the alpha value for the background. I also took the opportunity to generally reduce the background alpha value for all colour maps.

PS R:\learn\py_play\sp_fa> git diff sp_app_lib.py
diff --git a/sp_app_lib.py b/sp_app_lib.py
index 8dcf81b..e43f74b 100644
--- a/sp_app_lib.py
+++ b/sp_app_lib.py
   if not g.do_rpt or not g.bg_lpha:
-    if "tab" in g.bg_cmnm or g.bg_cmnm == 'default':
+    if g.bg_cmnm in bg_qualitatives:
       g.bg_lpha = rng.integers(5, 15) / 100
     else:
-      g.bg_lpha = rng.integers(15, 33) / 100
+      g.bg_lpha = rng.integers(7, 21) / 100

I also had a slightly different approach to building the curve’s colour cycle for Tab type colour maps. So, that will also need to be modified to account for the larger category now included.

PS R:\learn\py_play\sp_fa> git diff sp_app_lib.py
diff --git a/sp_app_lib.py b/sp_app_lib.py
index 8dcf81b..e43f74b 100644
--- a/sp_app_lib.py
+++ b/sp_app_lib.py
@@ -1554,12 +1595,14 @@ def set_clr_map(ax, n_vals=None, cc=None):

   if g.DEBUG:
     print(f"\tset_clr_map: n_vals = {n_vals}, cc = {cc}, u_cmap = {u_cmap}")
+
   if not n_vals:
     n_vals = 16
   c_rng = n_vals // 2

   if not g.do_rpt or not g.cycle:
-    if u_cmap in ['default', 'tab20', 'tab20c', 'twilight_shifted']:
+    if u_cmap in bg_qualitatives:
       c_cycle = [bgcm_mpl[u_cmap](i) for i in np.linspace(0, 1, n_vals+1)][:-1]
     else:
       if c_rng % 2 == 0:
test image after refactoring selection of background alpha value
Test #2: Reduced Background Alpha Values

Not sure the two colour maps are compatible, but at least the background is not overpowering the spirograph image.

Foreground Light Colour Maps

While playing around, I eventually discovered another slight problem. A few of the colourmaps were pastels or otherwise quite light. They had a problem with most backgrounds. Here’s an example.

test image showing problem with pastel and other colour maps for spirograph
Test #3: Pastel Foregrounds?

This required some additional variables and additional code in a couple of places. I also took the opportunity to make the default spirograph alpha value a little stronger. I am adding a temporary alpha variable so that I can preserve the current alpha value if selected by the user. Only want to change it for this particular set of colour maps and only for the current image.

diff --git a/g_vars.py b/g_vars.py
index d61cf89..f7ee9f3 100644
--- a/g_vars.py
+++ b/g_vars.py
@@ -65,7 +65,9 @@ t_sy = False  # attempt to plot more symmetric curve, using current algorithm
 s_typ = 1     # method for attempted symmetry currently 1-11
 t_rx = False

-alph = 0.6    # default alpha value for plots
+alph = 0.75    # default alpha value for plots
+tmp_alph = 0.75   # temp storage for previous alpha value
 pz_ord = 9    # default zorder for plot

 npts_opt = ['1024', '2048', '3072', '4096']

Then I defined a new dictionary in the sp_app_lib module—right after the defintion for bg_qualitatives.

bg_lights = ['Pastel1', 'Pastel2', 'Set2', 'Set3']

In the main module, I added the following code to the setup_image and fini_image functions.

PS R:\learn\py_play\sp_fa> git diff main.py
diff --git a/main.py b/main.py
index bc4be98..0b1ff50 100644
--- a/main.py
+++ b/main.py
@ -123,6 +126,15 @@ def setup_image(ax):
   if g.u_agn:
     sal.cnt_btw = 1

+  # if colour map one of the lighter or pastel ones, increase curve alpha value
+  if g.rcm in sal.bg_lights:
+    g.tmp_alph = g.alph
+    g.alph = 1
+  else:
+    g.tmp_alph = g.alph
+
 def fini_image(fig, ax):
   ax.text(0.5, 0.01, "<C2><A9> koach (barkncats) 2022", ha="center", transform=ax.transAxes,
@@ -141,9 +153,17 @@ def fini_image(fig, ax):
   data = sal.fig_2_base64(fig)

   # if necessary reverse any change in plotting points by one of the routes
-  if int(g.u_pts) != g.t_pts:
+  chg_pts = not (g.do_rpt or g.do_rek)
+  # print(f"\tg.do_rpt = {g.do_rpt}, g.u_pts = {g.u_pts}, g.t_pts = {g.t_pts}, chg_pts = {chg_pts}")
+  if chg_pts and int(g.u_pts) != g.t_pts:
     g.t_pts = int(g.u_pts)
     g.rds = np.linspace(0, 2*np.pi, g.t_pts)
+    # print(f"\t\tplot points now: {g.t_pts}")
+
+  # reset global alpha value, save actually used value for data display
+  tmp_alph = g.alph
+  g.alph = g.tmp_alph
+  g.tmp_alph = tmp_alph

   return data

Eventually I realized I was displaying the incorrect alpha value on the spirograph display page.

PS R:\learn\py_play\sp_fa> git diff sp_app_lib.py
diff --git a/sp_app_lib.py b/sp_app_lib.py
index 8dcf81b..e43f74b 100644
--- a/sp_app_lib.py
+++ b/sp_app_lib.py
@@ -982,7 +1013,7 @@ def get_gnarly_dset(f_xs, f_ys, l_drp, frm_f, do_sym=False):

 def get_image_dtl(pg_ttl):
   c_d = {
-    'pttl': pg_ttl, 'ln_sz': g.ln_w, 'cmap': g.rcm, 'c_lph': g.alph, 'c_ndx': g.c_ndx,
+    'pttl': pg_ttl, 'ln_sz': g.ln_w, 'cmap': g.rcm, 'c_lph': g.tmp_alph, 'c_ndx': g.c_ndx,
     'dobg': g.use_bb2, 'bgcm': g.bg_cmnm, 'bg_lph': g.bg_lpha,
     'fig_sz': g.fig_sz, 'dpi': g.i_dpi, 'c_cyc': g.cycle, 'abg': g.abg,
   }
test image showing pastel spirograph after adding code to increase the alpha value for this set of colour maps
Test #4: Pastel Spirograph, Slight Improvement?

A marginal improvement at best. Decided to reduce the background alpha value for these foreground colour maps. Only took a small code change. In proc_curve_form I changed the appropriate line to the following.

if g.bg_cmnm in bg_qualitatives or g.rcm in bg_lights:
test image showing pastel spirograph after adding code to decrease the background alpha value for this set of colour maps
Test #5: Pastel Spirograph, Perhaps a Little Better

Done

Done for this one m’thinks.

Hope your refactoring efforts go a little better than mine.

May add a few images I like before publishing this post. Afterall that’s what this is all about—the spirographs not the code.

Resources