As previously mentioned, one of the things I did to generate a variation on the mosaic like images was to apply a multiplier to one of the datarows in each pairing to try and generate larger colour areas. While still using multiple colour sections for each datarow pairing.
I will again be using spirograph related code from that earlier project. Which, as usual for this series of posts, I will not display.
Try to Generate Larger Colour Areas
You may have noticed that the call to btw_n_apart()
included the paramter mlt=g.bw_m
. The use of data value multipliers is already included in the code for that function. And, the global bw_m
controls whether or not to use multipliers. The default is not to do so.
New Form Field
Okay, let’s give the user the choice. I.E. a new form field. Once again pretty easy, a simple radio button field; with two choices. So in get_curve.html
I added the following after the field for the number of colours for each datarow pairing.
<div class="radio">
<p style="margin-left:1rem;margin-top:0;"><b>Use data multipliers when creating image</b></p>
<p>
<label for="mno">No: </label>
<input type="radio" name="r_mlt" id="mno" value="false" />
<label for="myes">Yes: </label>
<input type="radio" name="r_mlt" id="myes" value="true" />
</p>
</div>
Though I did have to mess the CSS for this form section. And, resorted to in-line CSS which is likely not a good thing. But, I just didn’t feel like working that much on the CSS stylesheet. Though perhaps easier than I think.
And, in proc_curve_form()
I added this bit of code.
if i_typ == 'mosaic':
... ...
if 'r_mlt' in f_data:
g.bw_m = True if f_data['r_mlt'] == 'true' else False
Minor Route Refactor
And, the only refactoring I had to make in the route was to pass the appropriate data to disp_image.html
so that it could be displayed on screen.
p_data = {'pttl': pg_ttl, 'n_whl': g.n_whl, 'ln_sz': g.ln_w, 'shape': t_shp,
'cmap': g.rcm, 'agn': g.u_again, 'bdx': g.bw_dx, 'bol': g.bw_o,
'bcs': g.bw_s, 'bmlt': g.bw_m, 'mlts': sal.c_mlts
}
Minor Refactor of Page Templates
I decided to show the multipliers to the user if they selected using them.
{% if type == 'mosaic' %}
{% set w_rows = "adjacent datarows" if p_data['bdx'] == 1 else "datarows {} apart".format(p_data['bdx']) %}
<p>You requested colouring between {{ w_rows }} {{ "with" if p_data['bol'] else "without" }} overlap.
Using {{ p_data['bcs'] }} colour sections per datarow pairing.
{% if p_data['bmlt'] %}
Multipliers in use: {{ p_data['mlts'] }}.
{% endif %}
</p>
{% endif %}
And, I made the images on the home page into links as well as the text above them.
Some Examples
And you know, that was pretty much it. Rather easy when most of the hard code was produced previously. So, a few examples.
The first one uses 7 tetracuspid shaped wheels. Multipliers: [1.8, 2.0, 1.2, 1.4, 1.1, 1.2, 1.4]. 48 colour sections per datarow pairing with a colour map of plasma.
The next one uses 9 wheels with shapes: [’t’, ’t’, ‘c’, ‘r’, ‘r’, ‘q’, ’t’, ‘q’, ’s’]. Multipliers: [1.6, 2.6, 2.4, 2.2, 1.2, 1.4, 1.4, 1.2, 1.0]. 48 colour sections per datarow pairing with a colour map of gnuplot. You can see those first tetracuspid wheel shapes dominating the final result.
The next one uses 11 rhombus shaped wheels. Multipliers: [1.8, 1.8, 1.8, 1.2, 2.6, 1.2, 1.4, 1.5, 1.1, 1.0, 1.0]. 32 colour sections per datarow pairing with a colour map of rainbow.
One last one. 11 ellipse shaped wheels. Multipliers: [1.8, 2.4, 2.2, 2.2, 2.2, 1.2, 1.1, 1.0, 1.6, 1.0, 1.5]. 16 colour sections per datarow pairing with a colour map of twilight_shifted.
Personally, I think using the multipliers enhances the images. But, eye of the beholder and all that.
Major Refactor of Image Display Page
Bit of an aside. I decided to move all the image details, currently displayed before the image, after the image. Afterall the image is the priority, shouldn’t need to scroll down to see it. And, I added considerably more information (in case I ever want to try and replicate one of them in my personal command line app).
To help with this I wrote two functions. I plan to have two or three sections following the image. One for the underlying curve data (e.g. number wheels, shape, k_fold symmetry, frequencies). One for the basic plotting info (e.g. colour map, line width). And possibly one for specific information related to the current image type. The functions will return a dictionary with the data for the the curve and image information section, which will be passed on to the template. Don’t want to be adding all that code to the routing functions. The image type specific data is still being genereated in the route code.
New Functions
Very simple and straightforward. But, removes repetition in each of the routes.
def get_curve_dtl():
if len(g.su) == 1:
shape = f"{splt.shp_nm[g.su].lower()} ({g.su})"
else:
shape = g.su
c_d = {
'n_whl': g.n_whl, 'shape': shape, 'k_f': g.k_f, 'cgv': g.cgv,
'freqs': g.freqs, 'wds': g.wds, 'hts': g.hts, 'agn': g.u_again
}
return c_d
def get_image_dtl(pg_ttl):
c_d = {
'pttl': pg_ttl, 'ln_sz': g.ln_w, 'cmap': g.rcm
}
return c_d
Refactor Routes
I’ll only show you the mosaic route, as the others are all similar. The only dictionary being coded in the route, is for the route’s image type specific data. Didn’t think a new function would really help in this case.
# Used to look like this
p_data = {'pttl': pg_ttl, 'n_whl': g.n_whl, 'ln_sz': g.ln_w, 'shape': t_shp,
'cmap': g.rcm, 'agn': g.u_again, 'bdx': g.bw_dx, 'bol': g.bw_o,
'bcs': g.bw_s, 'bmlt': g.bw_m, 'mlts': sal.c_mlts
}
return render_template('disp_image.html', sp_img=data, type='mosaic', p_data=p_data)
# Now looks like this
c_data = sal.get_curve_dtl()
i_data = sal.get_image_dtl(pg_ttl)
p_data = {'bdx': g.bw_dx, 'bol': g.bw_o, 'bcs': g.bw_s,
'bmlt': g.bw_m, 'mlts': sal.c_mlts
}
return render_template('disp_image.html', sp_img=data, type='mosaic', c_data=c_data, i_data = i_data, p_data=p_data)
Refactor Display Template
And finally a significant refactoring of the disp_image.html
template. Decided to switch from paragraphs to lists to display the information. That did involve a touch of refactoring in the CSS stylesheet (which I am not going to show here).
The whole of the template now looks like this.
{% extends 'base.html' %}
{% block title %}{{ i_data['pttl'] }}{% endblock %}
{% block content %}
<h2>{{ i_data['pttl'] }}</h2>
<img src='data:image/png;base64,{{ sp_img }}'/>
<p>
{% if type == 'basic' %}
<a href="{{ url_for('sp_basic') }}">Back</a>
{% elif type == 'gnarly' %}
<a href="{{ url_for('sp_gnarly') }}">Back</a>
{% elif type == 'mosaic' %}
<a href="{{ url_for('sp_mosaic') }}">Back</a>
{% endif %}
</p>
<h3>Curve Parameters</h3>
{% if c_data['agn']%}
<p>The previous curve data is being reused for this image.</p>
{% endif %}
<ul class="dots">
<li>Wheels: {{ c_data['n_whl'] }} wheels (shape(s): {{ c_data['shape'] }})</li>
<li>Symmetry: k_fold = {{ c_data['k_f'] }}, congruency = {{ c_data['cgv'] }}</li>
<li>Frequencies: {{ c_data['freqs'] }}</li>
<li>Widths: {{ c_data['wds'] }}</li>
<li>Heights: {{ c_data['hts'] }}</li>
</ul>
{% if type in ['gnarly', 'mosaic'] %}
<h3>Image Type Parameters</h3>
{% if type == 'gnarly' %}
<ul class="dots">
<li>Drop data rows: {{ p_data['d_nbr'] }} {{ 'datarows' if p_data['d_nbr'] > 1 else 'datarow' }}</li>
<li>From: dropped from the '{{ p_data['d_end'] }}' of the curve dataset</li>
</ul>
{% endif %}
{% if type == 'mosaic' %}
{% set w_rows = "adjacent datarows" if p_data['bdx'] == 1 else "datarows {} apart".format(p_data['bdx']) %}
<ul class="dots">
<li>Colouring: between {{ w_rows }} {{ "with" if p_data['bol'] else "without" }} overlap</li>
<li>Sections: {{ p_data['bcs'] }} colour sections per datarow pairing</li>
{% if p_data['bmlt'] %}
<li>Multipliers: {{ p_data['mlts'] }}</li>
{% endif %}
</ul>
{% endif %}
{% endif %}
<h3>Drawing Parameters</h3>
<ul class="dots">
<li>Colour map: {{ i_data['cmap'] }}</li>
<li>Line width (if used): {{ i_data['ln_sz'] }}</li>
</ul>
{% endblock %}
And, it now looks like the following.
Done
That’s enough for this one. Had planned to do something else before I decided to upgrade the image information shown on the display page. Will see next time.
Until then, keep those fingers dancing.