As mentioned in the last post, I would like to have a clear line of separation between the command line spirograph app and the web spirograph app. That means I need to look at copying any variables and functions I am using from the command line app to the web app.
I decided to see what this might involve by searching through the web app modules looking for references to the command line app modules. Here’s a lengthy list of what I found.
Searching for: splt\.
sp_app_animate.py(37): rs = splt.f(0)
sp_app_animate.py(85): t_lim = sum(splt.r_rad) + 0.15
sp_app_animate.py(121): r_pts = splt.f(t[t_ndx])
sp_app_animate.py(128): circs = [Circle((0, 0), .1, fill=False, alpha=0) for i in range(splt.nbr_w)]
sp_app_animate.py(130): r_pts = splt.f(i)
sp_app_animate.py(136): for i in range(1, splt.nbr_w):
sp_app_data.py(429): splt.set_spiro(g.freqs, g.wds, g.hts, nbr_t=g.t_pts)
sp_app_data.py(435): t_xs, t_ys = splt.mk_curve(g.rds, shp=g.su)
sp_app_data.py(436): shape = f"{splt.shp_nm[g.su].lower()} ({g.su})"
sp_app_data.py(445): t_xs, t_ys, shape = splt.mk_rnd_curve(g.rds, su=shape)
sp_app_data.py(462): if l_shps[i] not in splt.shps:
sp_app_data.py(468): all_shp = list(splt.shps.keys())
sp_app_data.py(549): g.su = sau.rng.choice(list(splt.shp_nm.keys()))
sp_app_data.py(552): elif f_shp in splt.shp_nm:
sp_app_data.py(557): if f_shp == 'x' or f_shp in splt.shp_nm:
sp_app_data.py(560): g.su = sau.rng.choice(list(splt.shp_nm.keys()))
sp_app_data.py(565): # all_shp = list(splt.shps.keys())
sp_app_data.py(851): splt.set_spiro(g.freqs, g.wds, g.hts, nbr_t=g.t_pts)
sp_app_util.py(79): shape = f"{splt.shp_nm[g.su].lower()} ({g.su})"
sp_app_util.py(86): 'npts': g.t_pts, 'e_wds': splt.e_wds, 'e_hts': splt.e_hts
Found 42 occurrence(s) in 4 file(s), 13 ms
Searching for: (get_radii|get_freqs)
sp_app_data.py(12): from spiro_get_rand import get_radii, get_freqs
sp_app_data.py(418): g.wds = get_radii(g.n_whl)
sp_app_data.py(420): g.hts = get_radii(g.n_whl)
sp_app_data.py(425): g.cgv, g.freqs = get_freqs(nbr_w=g.n_whl, kf=g.k_f, mcg=g.cgv)
sp_app_lib.py(14): from spiro_get_rand import get_radii, get_freqs
sp_app_lib.py(1068): g.wds = get_radii(g.n_whl)
sp_app_lib.py(1070): g.hts = get_radii(g.n_whl)
sp_app_lib.py(1075): g.cgv, g.freqs = get_freqs(nbr_w=g.n_whl, kf=g.k_f, mcg=g.cgv)
Found 8 occurrence(s) in 2 file(s), 9 ms
I do think this refactor is going to cover more than moving some variable and functions to the web app modules. I think I might look at taking the module variables used in spiro_plotlib
(i.e. splt
) to my global variables module. And refactor the functions I copy over to use those variables rather than a more or less duplicate set in multiple modules.
A Look at the Current Process
The command line modules of interest are spiro_plotlib
alias splt
and spiro_get_rand
. In the latter, specifically the functions get_radii
and get_freqs
(see search results above).
Other aliases used below. sad
-> sp_app_data
. sap
-> sp_app_plot
.
Okay, for most routes it goes something like this:
- generate basic curve data, usually a call to
sp_app_data.get_curve_data
. - call to
sad.setup_image()
- call to
sad.proc_curve_form()
- call to
sad.init_curve()
, where for the general case- a number of curve parameters are generated
- call to
splt.set_spiro()
, that’s one of the command line app modules - if single wheel shape: call to
splt.mk_curve()
- this in turn calls the appropriate function for the given wheel shape, once for each wheel
- there is a function for each wheel type
- else if multiple wheel shapes: call to
splt.mk_rnd_curve()
- this in turn calls the appropriate function for the given wheel shapes, once for each wheel/shape
- returns curve data
- call to
- call to
sap.setup_image()
- sets some global values
- sets image margin with call to
sap.set_margins()
- then there is a call to an appropriate plotting function depending on the image type/route. For the cycling line width using colour between that would be
sap.cycle_lw_btw()
- none of these functions appear to call/use anything inspiro_plotlib
There’s a lot of code in these two modules that I would need to copy/move to new modules. So I think I will continue to use the spiro_plotlib
modules which I originally copied into the web app’s directory. I will rename it as sp_app_curve
. I may have also modified it, so a good reason to keep it as is.
And, I will move the two functions in spiro_get_rand
to sp_app_util
; and refactor them to use the rng
object.
I will try to refactor sp_app_curve
to use the variables in the global variables module rather than the current module variables. Doesn’t make sense to me to have the same information in two places. Though keeping the module variables may make the code easier to write and make it clearer to read. Finally, I will remove any functions and variables not used by the web app that may be being used by the command line app.
New Module
I renamed a copy of spiro_plotlib
to sp_app_curve
. So I now need to find all references to the former (imports and prefixes for function calls) to use the new module. Removing the old imports and adding a new one, import sp_app_curve as sacu
, as necessary. Replaced 15 occurrences in main
, 6 in sp_app_animate
, 12 in sp_app_data
and 3 in sp_app_util
. That’s many more than I expected. And, a quick test says things appear to work as before my refactoring.
Move Functions in spiro_get_rand
Okay, let’s get those two functions into sp_app_util
. I had thought about putting them in sp_app_data
as they generate data to be used in rendering spirograph curves. But, in the end went with the app utility module. Figured it would be okay either way. And this way, I have the rng
object as a module variable. No module referencing required.
There were a series of variables moved as well.
# specify min/max multipliers for circles each position, starting at the 2nd (i.e. index 1)
nw_min = [.5, .5] + [.5] * 13
nw_max = [.8, .75] + [1] * 13
min_rad = 1/8
Now the functions currently use calls to the np.random
object to generate the desired random values. I am refactoring all such calls to use the rng
object equivalent. In the name of consistency. Will only show one of the refactorings, the one with the most calls.
The original version is as follows.
def get_freqs(nbr_w, kf, mcg=None):
speeds = []
# mod congruency value
m_add = None
if mcg:
m_add = mcg
else:
# m_add = np.random.randint(1, kf - 2)
m_add = np.random.randint(1, kf)
speeds = [np.random.choice([m_add - kf, m_add, m_add + kf])]
for _ in range(1, nbr_w):
m_mult = np.random.randint(-4, 5)
speeds.append(m_mult * kf + m_add)
# I want to know m_add for plot titles
return m_add, speeds
And the refactored version, simple changes, follows.
def get_freqs(nbr_w, kf, mcg=None):
speeds = []
# mod congruency value
m_add = None
if mcg:
m_add = mcg
else:
# m_add = np.random.randint(1, kf - 2)
# m_add = np.random.randint(1, kf)
m_add = rng.integers(1, kf)
# speeds = [np.random.choice([m_add - kf, m_add, m_add + kf])]
speeds = [rng.choice([m_add - kf, m_add, m_add + kf])]
for _ in range(1, nbr_w):
# m_mult = np.random.randint(-4, 5)
m_mult = rng.integers(-4, 5)
speeds.append(m_mult * kf + m_add)
# I want to know m_add for plot titles
return m_add, speeds
set_spiro()
Now set_spiro()
really only sets a number of spiro_plotlib
module variables which are used by other functions to generate curve data.
def set_spiro(freqs, wds, hts, nbr_t=500, clrs=None, fig=None, ax=None):
global nbr_w, nbr_pts, sp_frq, sp_rds, r_rad, sp_wds, sp_hts, r_wds, r_hts, cycle, t, ax_a, fig_a, x_sp, y_sp, ln_sp, ln_rs
nbr_w, nbr_pts, sp_frq, sp_rds, sp_wds, sp_hts = len(wds), nbr_t, freqs, wds, wds, hts
r_rad = [max(np.real(rd), np.imag(rd)) for rd in sp_rds]
r_wds = r_rad
r_hts = [max(np.real(rd), np.imag(rd)) for rd in sp_hts]
t = np.linspace(0, 2*np.pi, nbr_t)
# print(f"\tset_spiro(nbr_t={nbr_t}) -> nbr_pts: {nbr_pts}")
if clrs:
cycle = clrs
if fig:
fig_a = fig
if ax:
ax_a = ax
x_sp = []
y_sp = []
ln_sp = None
ln_rs = None
What I want to do is use the variables that already exist in the global variables module. Add any that are missing. Then copy set_spiro()
to sp_add_data()
and refactor to use the variables in the global variables module.
I am sure you can already see this is going to a slow and painful refactoring given how many spiro_plotlib
functions use those module variables. I may not even be able to do it truly incrementally.
Done
After writing everything but this closing section, I started on some other bits of refactoring and/or enhancement. And sort of forgot all about what I was planning to do with respect to refactoring the web app modules.
So, for the past and present this post is done. I have left all those globals used in set_spiro
in the sp_app_curve
module for now.
May eventually get back to this particular refactoring idea/attempt.