Latest Blog Posts http://localhost/latest.atom/ 2022-10-16T23:55:00Z http://localhost/ Werkzeug Better select forms with django and Bootstrap 5 http://localhost/blog/better-select-form-django/ 2022-10-16T23:55:00Z 2022-10-16T23:55:00Z <p><img class="rounded mx-auto shadow-lg d-block" src="../../static/img/kelly-sikkema-hLit2zL-Dhk-unsplash-small.jpg" alt="web design"></p> <p class="text-muted small text-end">Photo by <a href="https://unsplash.com/@kellysikkema?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Kelly Sikkema</a> on <a href="https://unsplash.com/s/photos/user-interaction?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a> </p> <hr> <p>I enjoy working with <a href="https://www.djangoproject.com/">Django</a> for many reasons but mostly since I can focus on what I want my app to do and django happily takes care of the rest. In 2022 it's probably not the sexiest choice when it comes to web frameworks, but there are good reasons it is still as popular as it is. There is a recent wave of excitement about server side rendering frameworks thanks to a new batch of tools like <a href="https://htmx.org/">HTMX</a>, <a href="https://www.django-unicorn.com/">django-unicorn</a> and <a href="https://github.com/jonathan-s/django-sockpuppet">django-sockpuppet</a> that give django superpowers and put into question the <code>React</code> based paradigm for building apps. But that's a digression for another time.</p> <p>Django takes care of a lot of stuff behind the scenes and that is a solid productivity boost. Being a mature framework means that is has opinions (mostly for very good reasons) and provides you with defaults that are sensible in most o the cases. There are however cases when it's worth to make some changes to improve end-user experience.</p> <p>One such aspect is the default UI widget for selecting items. I am of course talking about <a href="https://en.wikipedia.org/wiki/Drop-down_list">dropdowns</a>. They have been around since forever and although being familiar they are usually not the best choice when it comes to modern UX standards. Out in the wild you can find professionals suggesting <a href="https://www.nngroup.com/articles/drop-down-menus/">caution when using dropdowns</a> and calls to <a href="https://adrianroselli.com/2020/03/stop-using-drop-down.html">stop using drop-downs</a> at all. </p> <p>Personally I would like to adhere to good UX practices as far as I can and although my level of comfort increases with proximity to backend side of things I cannot be annoyed by all the low hanging fruit that sometimes plague otherwise good products. Wanting things to look good without a massive design effort is one of the reasons I usually reach for a frontend framework, most often <a href="https://getbootstrap.com/">bootstrap</a>. With django that means using <a href="https://github.com/django-crispy-forms/django-crispy-forms">django crispy forms</a> to get the forms looking sharp and consistent with an extra line in the template.</p> <h2>Making choices</h2> <p>One of the things I was recently working on is a django-based dashboard where I wanted to have the option to choose the aggregation level between: <code>daily</code>, <code>weekly</code>, <code>monthly</code> aggregates. Of course my first pass was the default <code>forms.Select</code> widget that is a dropdown. Once I saw the result on the screen though, I felt something is off, and that this should probably be improved. Usually I try to move on until I have a working prototype that I can iterate over. Following the Kent Beck's principle</p> <blockquote class="blockquote text-center py-5">make it work, make it right, make it fast</blockquote> <p>When I got everything wired up and working it seemed like a good time get back to the select widget and scratch that itch. </p> <p>On the django side I had a form to represent the choices </p> <div class="codehilite"><pre><span></span><code><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span> <span class="k">class</span> <span class="nc">FrequencyForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span> <span class="n">choices</span> <span class="o">=</span> <span class="p">[</span> <span class="p">(</span><span class="s2">&quot;1D&quot;</span><span class="p">,</span> <span class="s2">&quot;Daily&quot;</span><span class="p">),</span> <span class="p">(</span><span class="s2">&quot;1W&quot;</span><span class="p">,</span> <span class="s2">&quot;Weekly),</span> <span class="p">(</span><span class="s2">&quot;1M&quot;</span><span class="p">,</span> <span class="s2">&quot;Monthly&quot;</span><span class="p">)</span> <span class="p">]</span> <span class="n">freq</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">ChoiceField</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s2">&quot;Frequency&quot;</span><span class="p">,</span> <span class="n">choices</span><span class="o">=</span><span class="n">choices</span><span class="p">)</span> </code></pre></div> <p>which was being rendered in a template with pretty standard django</p> <div class="codehilite"><pre><span></span><code>{% load crispy_forms_tags %} ... {{ form|crispy }} </code></pre></div> <p>The effect isn't surprising either</p> <div class="row mb-5"> <div class="col-md-4 mx-auto"> <div id="div_id_freq" class="mb-3"> <label for="id_freq" class="form-label requiredField"> Frequency<span class="asteriskField">*</span> </label> <select name="freq" class="select form-select" id="id_freq"> <option value="1D">Daily</option> <option value="1W" selected="">Weekly</option> <option value="1M">Monthly</option> </select> </div> </div> </div> <p>I didn't want for the options to be hidden, so the next best thing was to switch to a radio select by changing the for widget to <code>RadioSelect</code> and keeping the template as is</p> <div class="codehilite"><pre><span></span><code><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span> <span class="k">class</span> <span class="nc">FrequencyForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span> <span class="n">choices</span> <span class="o">=</span> <span class="p">[</span> <span class="p">(</span><span class="s2">&quot;1D&quot;</span><span class="p">,</span> <span class="s2">&quot;Daily&quot;</span><span class="p">),</span> <span class="p">(</span><span class="s2">&quot;1W&quot;</span><span class="p">,</span> <span class="s2">&quot;Weekly),</span> <span class="p">(</span><span class="s2">&quot;1M&quot;</span><span class="p">,</span> <span class="s2">&quot;Monthly&quot;</span><span class="p">)</span> <span class="p">]</span> <span class="n">freq</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">ChoiceField</span><span class="p">(</span> <span class="n">label</span><span class="o">=</span><span class="s2">&quot;Frequency&quot;</span><span class="p">,</span> <span class="n">choices</span><span class="o">=</span><span class="n">choices</span><span class="p">,</span> <span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">RadioSelect</span><span class="p">(),</span> <span class="p">)</span> </code></pre></div> <p>This gives</p> <div class="row mb-5"> <div class="col-md-4 mx-auto"> <div id="div_id_freq" class="mb-3"> <label class="form-label requiredField">Frequency<span class="asteriskField">*</span></label> <div> <div class="form-check"> <input type="radio" class="form-check-input" name="freq" value="1D" id="id_freq_0" required=""> <label for="id_freq_0" class="form-check-label"> Daily </label> </div> <div class="form-check"> <input type="radio" class="form-check-input" name="freq" value="W" id="id_freq_1" required="" checked=""> <label for="id_freq_1" class="form-check-label"> Weekly </label> </div> <div class="form-check"> <input type="radio" class="form-check-input" name="freq" value="MS" id="id_freq_2" required=""> <label for="id_freq_2" class="form-check-label"> Monthly </label> </div> </div> </div> </div> </div> <p>Bettter but I still wasn't happy with the result. When looking for inspiration I found <a href="https://www.learnui.design/blog/4-rules-intuitive-ux.html">this post</a> suggesting a segmented button that reminded me of what I saw in latest <a href="https://getbootstrap.com/docs/5.0/components/button-group/#checkbox-and-radio-button-groups">Bootstrap 5 docs</a> so I decided to give it a go since I was already using Bootstrap.</p> <p>Looking at the example from Bootstrap it became clear that I would have to render the form manually. The example I started from was this:</p> <div class="codehilite"><pre><span></span><code><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn-group&quot;</span> <span class="na">role</span><span class="o">=</span><span class="s">&quot;group&quot;</span> <span class="na">aria-label</span><span class="o">=</span><span class="s">&quot;Basic radio toggle button group&quot;</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;radio&quot;</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn-check&quot;</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;btnradio&quot;</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;btnradio1&quot;</span> <span class="na">autocomplete</span><span class="o">=</span><span class="s">&quot;off&quot;</span> <span class="na">checked</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">label</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn btn-outline-primary&quot;</span> <span class="na">for</span><span class="o">=</span><span class="s">&quot;btnradio1&quot;</span><span class="p">&gt;</span>Radio 1<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;radio&quot;</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn-check&quot;</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;btnradio&quot;</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;btnradio2&quot;</span> <span class="na">autocomplete</span><span class="o">=</span><span class="s">&quot;off&quot;</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">label</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn btn-outline-primary&quot;</span> <span class="na">for</span><span class="o">=</span><span class="s">&quot;btnradio2&quot;</span><span class="p">&gt;</span>Radio 2<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;radio&quot;</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn-check&quot;</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;btnradio&quot;</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;btnradio3&quot;</span> <span class="na">autocomplete</span><span class="o">=</span><span class="s">&quot;off&quot;</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">label</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn btn-outline-primary&quot;</span> <span class="na">for</span><span class="o">=</span><span class="s">&quot;btnradio3&quot;</span><span class="p">&gt;</span>Radio 3<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span> </code></pre></div> <p>which looks like </p> <div class="row justify-content-center py-5"> <div class="col text-center"> <div class="btn-group" role="group" aria-label="Basic radio toggle button group"> <input type="radio" class="btn-check" name="btnradio" id="btnradio1" autocomplete="off" checked> <label class="btn btn-outline-primary" for="btnradio1">Radio 1</label> <input type="radio" class="btn-check" name="btnradio" id="btnradio2" autocomplete="off"> <label class="btn btn-outline-primary" for="btnradio2">Radio 2</label> <input type="radio" class="btn-check" name="btnradio" id="btnradio3" autocomplete="off"> <label class="btn btn-outline-primary" for="btnradio3">Radio 3</label> </div> </div> </div> <p>Pretty nice! I went ahead and updated my template and instead of the <code>{{ form|crispy }}</code> elements I went ahead and unfolded the form and added the classes and attributes to render the button group:</p> <div class="codehilite"><pre><span></span><code><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn-group&quot;</span> <span class="na">role</span><span class="o">=</span><span class="s">&quot;group&quot;</span> <span class="na">aria-label</span><span class="o">=</span><span class="s">&quot;Basic radio toggle button group&quot;</span><span class="p">&gt;</span> {% for choice in form.freq %} {{ choice.tag }} <span class="p">&lt;</span><span class="nt">label</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn btn-outline-primary&quot;</span> <span class="na">for</span><span class="o">=</span><span class="s">&quot;{{ choice.id_for_label }}&quot;</span><span class="p">&gt;</span>{{ choice.choice_label }}<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span> {% endfor %} <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span> </code></pre></div> <p>Everything looked nice when rendered however when clicking on the buttons they wouldn't stay selected as they should. They would change back to unselected which was annoying. I had to compare the original HTML with my rendered version to realize that the <code>&lt;input&gt;</code> tags in my case were missing s <code>class="btn-check"</code> attribute, so I modified the form to have that added </p> <div class="codehilite"><pre><span></span><code><span class="k">class</span> <span class="nc">FrequencyForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span> <span class="n">choices</span> <span class="o">=</span> <span class="p">[</span> <span class="p">(</span><span class="s2">&quot;1D&quot;</span><span class="p">,</span> <span class="s2">&quot;Daily&quot;</span><span class="p">),</span> <span class="p">(</span><span class="s2">&quot;1W&quot;</span><span class="p">,</span> <span class="s2">&quot;Weekly),</span> <span class="p">(</span><span class="s2">&quot;1M&quot;</span><span class="p">,</span> <span class="s2">&quot;Monthly&quot;</span><span class="p">)</span> <span class="p">]</span> <span class="n">freq</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">ChoiceField</span><span class="p">(</span> <span class="n">label</span><span class="o">=</span><span class="s1">&#39;Category&#39;</span><span class="p">,</span> <span class="n">choices</span><span class="o">=</span><span class="n">choices</span><span class="p">,</span> <span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">RadioSelect</span><span class="p">(</span><span class="n">attrs</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;class&#39;</span><span class="p">:</span><span class="s1">&#39;btn-check&#39;</span><span class="p">}),</span> <span class="p">)</span> </code></pre></div> <p>Adding that attribute to the form did the trick. With that little tweak I was able to achieve way better UX and eliminate and unnecessary dropdown. </p> <div class="row justify-content-center py-5"> <div class="col text-center"> <div class="btn-group" role="group" aria-label="Basic radio toggle button group"> <input type="radio" class="btn-check" name="freqbtnradio" id="freqbtnradio1" autocomplete="off" checked> <label class="btn btn-outline-primary" for="freqbtnradio1">Daily</label> <input type="radio" class="btn-check" name="freqbtnradio" id="freqbtnradio2" autocomplete="off"> <label class="btn btn-outline-primary" for="freqbtnradio2">Weekly</label> <input type="radio" class="btn-check" name="freqbtnradio" id="freqbtnradio3" autocomplete="off"> <label class="btn btn-outline-primary" for="freqbtnradio3">Monthly</label> </div> </div> </div> <p>This was it for me but in case you have a few more choices to select from (maybe 5-9 items) and you still would like to present them to the user this might not be a good choice since button group will most likely be too wide for small screens and overflow. </p> <p>In this case you can switch to splitting choices into individual buttons and arranging them in a grid rather than a single row. Then your CSS framework can take over and manage the responsive layout for smaller screens where you probably want to either switch to a more vertical layout or a grid layout.</p> <p>Let me add two more choices to my original form to illustrate how could it look like</p> <div class="codehilite"><pre><span></span><code><span class="k">class</span> <span class="nc">FrequencyForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span> <span class="n">choices</span> <span class="o">=</span> <span class="p">[</span> <span class="p">(</span><span class="s2">&quot;1D&quot;</span><span class="p">,</span> <span class="s2">&quot;Daily&quot;</span><span class="p">),</span> <span class="p">(</span><span class="s2">&quot;1W&quot;</span><span class="p">,</span> <span class="s2">&quot;Weekly),</span> <span class="p">(</span><span class="s2">&quot;1M&quot;</span><span class="p">,</span> <span class="s2">&quot;Monthly&quot;</span><span class="p">)</span> <span class="p">(</span><span class="s2">&quot;1Q&quot;</span><span class="p">,</span> <span class="s2">&quot;Quarterly&quot;</span><span class="p">)</span> <span class="p">(</span><span class="s2">&quot;1Y&quot;</span><span class="p">,</span> <span class="s2">&quot;Yearly&quot;</span><span class="p">)</span> <span class="p">]</span> <span class="n">freq</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">ChoiceField</span><span class="p">(</span> <span class="n">label</span><span class="o">=</span><span class="s1">&#39;Category&#39;</span><span class="p">,</span> <span class="n">choices</span><span class="o">=</span><span class="n">choices</span><span class="p">,</span> <span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">RadioSelect</span><span class="p">(</span><span class="n">attrs</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;class&#39;</span><span class="p">:</span><span class="s1">&#39;btn-check&#39;</span><span class="p">}),</span> <span class="p">)</span> </code></pre></div> <p>In the template we need to wrap all choice fields in a <code>row</code> and each input + label tag in a <code>col</code> with appropriate widths for each display breakpoint. This is bootstrap specific so check out <a href="https://getbootstrap.com/docs/5.2/layout/breakpoints/">bootstrap layout</a> if you want to know more. </p> <div class="codehilite"><pre><span></span><code><span class="p">&lt;</span><span class="nt">form</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;row&quot;</span><span class="p">&gt;</span> {% for choice in form.freq %} <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;col-4 col-md-3 col-lg-2&quot;</span><span class="p">&gt;</span> {{ choice.tag }} <span class="p">&lt;</span><span class="nt">label</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;btn btn-outline-primary&quot;</span> <span class="na">for</span><span class="o">=</span><span class="s">&quot;{{ choice.id_for_label }}&quot;</span><span class="p">&gt;</span>{{ choice.choice_label }}<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span> {% endfor %} <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span> </code></pre></div> <p>This is now rendered as independent radio buttons </p> <div class="row justify-content-center py-5"> <div class="col text-center"> <form> <div class="row justify-content-center"> <div class="col-4 col-md-3 col-lg-2 py-2"> <input type="radio" class="btn-check" name="choice" id="radio-1" value="1D"> <label class="btn btn-outline-primary btn-lg" for="radio-1">Daily</label> </div> <div class="col-4 col-md-3 col-lg-2 py-2"> <input type="radio" class="btn-check" name="choice" id="radio-2" value="1W"> <label class="btn btn-outline-primary btn-lg" for="radio-2">Weekly</label> </div> <div class="col-4 col-md-3 col-lg-2 py-2"> <input type="radio" class="btn-check" name="choice" id="radio-3" value="1M"> <label class="btn btn-outline-primary btn-lg" for="radio-3">Monthly</label> </div> <div class="col-4 col-md-3 col-lg-2 py-2"> <input type="radio" class="btn-check" name="choice" id="radio-4" value="1Q"> <label class="btn btn-outline-primary btn-lg" for="radio-4">Quartely</label> </div> <div class="col-4 col-md-3 col-lg-2 py-2"> <input type="radio" class="btn-check" name="choice" id="radio-5" value="1Y"> <label class="btn btn-outline-primary btn-lg" for="radio-5">Yearly</label> </div> </div> </form> </div> </div> <h2>Summary</h2> <p>If you're using django and a css framework like bootstrap it does not take much effort to adapt your forms and improve overall user experience and at the same time conform to modern standard for look and feel of your web app. If you have similar quick improvements please share below since I'm always on the lookout for how to improve usability.</p> <hr> Datasets beat Models http://localhost/blog/datasets-beat-models/ 2021-06-24T12:00:00Z 2021-06-24T12:00:00Z <p><img class="rounded mx-auto shadow-lg d-block" src="../../static/img/1624540361257.jpeg" alt="datasets beat models"></p> <hr> <p>I know it’s easy to get carried away by all the shiny, sophisticated ML models out there, but we need to have a serious conversation about datasets. In most industrial applications of ML it’s the datasets that limit performance not model complexity. </p> <p>Lack of high quality training datasets is the biggest challenge for industrial machine learning right now. That should not be surprising if you consider how much bigger the supply of models is compared to datasets. A big portion of the ML algorithms development happens thanks to open source and academic communities which gladly publish their work in exchange for reputation points. In contrast, developing and curating datasets is often less valued and not as glamorous. </p> <p>My experience from working on data-driven solutions for industrial problems is that there is no shortage of data and huge volumes are available in raw form; however converting them into training and validation datasets is what usually blocks ML/AI progress. </p> <p>I won't be controversial if I attribute 80% of a data scientist's time to what is collectively termed preprocessing, cleaning or structuring the data. The result of all of those activities is a dataset that hopefully accurately represents reality and can serve as ground truth for model development and evaluation. Creating high quality datasets however takes effort, skills and a right blend of domain knowledge and experience with data.</p> <p>This is exactly what we are passionate about at unifai. We are approaching dataset development as an engineering practice and we are creating high quality datasets to increase adoption of machine learning in the industry. Our experience in data science, data engineering, software development and heavy asset industry puts us in a unique position to deliver datasets with a perfect mix of domain knowledge.</p> <p>Unifai is not alone in betting on datasets, one of the biggest names in AI: Andrew Ng recently started promoting a more data-centric view of AI instead of the model-centric view. In a recent announcement together with landing.ai and deeplearning.ai he launched a competition that focuses on improving data while keeping the model fixed to inspire new methods for improving data.</p> <p>Get in touch with me if you share similar challenges or if you're sitting on piles of raw data and your organization wants to get some quick wins with machine learning.</p> <hr> <p>This post was originally published on <a href="https://www.linkedin.com/pulse/datasets-beat-models-lukasz-mentel">LinkedIn</a>.</p> Zeolite pore size oddity http://localhost/blog/zeolite-pore-size-oddity/ 2017-10-31T12:00:00Z 2017-10-31T12:00:00Z <p>One of the ways to classify zeolites is usually by the size of their pore openings given in the peculiar unit of T atom count. T atom stands for tetrachedrally coordinated atoms, usually the term lumps together silicon and aluminum in case of zeolites or aluminum and phosphorus in case of aluminumphpsphates. The structural units characterising pores are usually rings from which the tube-like channels are formed (as shown below) and therefore the as described as <em>n</em> membered rings or <em>n</em>MR in short. Where <em>n</em> can be as small as 4 and as large as 20.</p> <p>[picture of 8MR, 10MR and 12MR with a corresponding tube]</p> <p>By inspecting the figure below showing the distribution of ring sizes among the known zeolite structures it is easy to see that 8, 10, and 12 MR structures dominate over the remaining topologies. Which justifies the why this parameter might serve as a good classification. It should also be taken into account that for most of the interesting applications topologies with MR &lt; 8 are not intersting since molecules cannot enter the small channels and channels larger than 14 would have very similar properties.</p> <p>IUPAC classification into nano, micro and mesoporous structures in a <a href="https://doi.org/10.1351/pac199466081739">technical report</a>.</p> <p>It is customary to call 8, 10 and 12MR, <em>small</em>, <em>medium</em> and <em>large</em> pore zeolites suggesting that this classification provides distinct groups of similar characteristing being size. While intuitively and qualitatively correct, applying it directly can lead to incorrect insights since this MR measure provides limited structural information. A closer inspection of each class revelas that in each class there is a distribution of sizes as evaluated by different criteria actually associated with a more functional definition of pore size.</p> <p>apply clustering based on size largst cavity diameter (LCD) and some other features related to functional size and compare them to the classification based on MR and see which are misclassified.</p> Superimpose chemical structures http://localhost/blog/superimpose-structures/ 2017-09-28T12:00:00Z 2017-09-28T12:00:00Z <p>I was struggling recently how to present multiple chemical structures that differed slightly in their geometry but </p> <div class="codehilite"><pre><span></span><code><span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">re</span> <span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">OrderedDict</span> <span class="kn">from</span> <span class="nn">ase</span> <span class="kn">import</span> <span class="n">Atoms</span> <span class="kn">import</span> <span class="nn">ase.io</span> <span class="k">def</span> <span class="nf">read_structures</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">fpatt</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span> <span class="sd">&#39;&#39;&#39;</span> <span class="sd"> Read all the structures from `path` that match the `fpatt` pattern</span> <span class="sd"> &#39;&#39;&#39;</span> <span class="n">fpatt</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">fpatt</span><span class="p">)</span> <span class="n">out</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;II&#39;</span><span class="p">:</span> <span class="n">OrderedDict</span><span class="p">(),</span> <span class="s1">&#39;III&#39;</span><span class="p">:</span> <span class="n">OrderedDict</span><span class="p">(),</span> <span class="s1">&#39;IV&#39;</span><span class="p">:</span> <span class="n">OrderedDict</span><span class="p">()}</span> <span class="k">for</span> <span class="n">fname</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">path</span><span class="p">):</span> <span class="n">m</span> <span class="o">=</span> <span class="n">fpatt</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">fname</span><span class="p">)</span> <span class="k">if</span> <span class="n">m</span><span class="p">:</span> <span class="n">symbol</span><span class="p">,</span> <span class="n">oxs</span> <span class="o">=</span> <span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="n">out</span><span class="p">[</span><span class="n">oxs</span><span class="p">][</span><span class="n">symbol</span><span class="p">]</span> <span class="o">=</span> <span class="n">ase</span><span class="o">.</span><span class="n">io</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">fname</span><span class="p">))</span> <span class="k">else</span><span class="p">:</span> <span class="k">if</span> <span class="n">verbose</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;ERROR &#39;</span><span class="p">,</span> <span class="n">fname</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Read: &#39;</span><span class="p">,</span> <span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s1">&#39;</span><span class="si">{}</span><span class="s1">: </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">))</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">out</span><span class="o">.</span><span class="n">items</span><span class="p">()]))</span> <span class="k">return</span> <span class="n">out</span> <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span> <span class="n">path</span> <span class="o">=</span> <span class="s1">&#39;AlPO-5-H&#39;</span> <span class="n">patt</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;([A-Za-z]+)\(([IV]+)\)-AlPO-5-O2-H\.traj&#39;</span> <span class="n">halpo</span> <span class="o">=</span> <span class="n">read_structures</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">patt</span><span class="p">)</span> <span class="n">atoms</span> <span class="o">=</span> <span class="n">Atoms</span><span class="p">()</span> <span class="k">for</span> <span class="n">me</span><span class="p">,</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">halpo</span><span class="p">[</span><span class="s1">&#39;IV&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="n">atoms</span> <span class="o">=</span> <span class="n">atoms</span> <span class="o">+</span> <span class="n">a</span> <span class="n">transmittances</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.8</span><span class="p">]</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">atoms</span><span class="p">)</span> <span class="n">ase</span><span class="o">.</span><span class="n">io</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">&#39;Me-AlPO-5-H.pov&#39;</span><span class="p">,</span> <span class="n">atoms</span><span class="p">,</span> <span class="n">rotation</span><span class="o">=</span><span class="s1">&#39;-15y&#39;</span><span class="p">,</span> <span class="n">show_unit_cell</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">run_povray</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">display</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">pause</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">canvas_width</span><span class="o">=</span><span class="mi">1024</span><span class="p">,</span> <span class="n">camera_type</span><span class="o">=</span><span class="s1">&#39;perspective&#39;</span><span class="p">,</span> <span class="n">transmittances</span><span class="o">=</span><span class="n">transmittances</span><span class="p">)</span> <span class="n">ase</span><span class="o">.</span><span class="n">io</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">&#39;Me-AlPO-5-H_0y.pov&#39;</span><span class="p">,</span> <span class="n">atoms</span><span class="p">,</span> <span class="n">rotation</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="n">show_unit_cell</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">run_povray</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">display</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">pause</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">canvas_width</span><span class="o">=</span><span class="mi">1024</span><span class="p">,</span> <span class="n">camera_type</span><span class="o">=</span><span class="s1">&#39;perspective&#39;</span><span class="p">,</span> <span class="n">transmittances</span><span class="o">=</span><span class="n">transmittances</span><span class="p">)</span> </code></pre></div> <p>Rendering the scenes for multiple structures was a bit too slow for my laptop so I had to use a supercomputer to speed things up.</p> <p>This is a bit of a special case since the structures are taken from a periodic crystals and therefore all have the same unit cell size. It simpifies things a lot since then all the coordinates are given with respect to origin of the unit cell which is the same for all the materials. For (non-periodic) molecules we would have to align the molecules first since their coordinates can be defined with respect to different origins. One possible solution is to minimize the <a href="https://en.wikipedia.org/wiki/Root-mean-square_deviation_of_atomic_positions">root mean square deviation</a> between the structures in order to realign them which is usually done using the <a href="https://doi.org/10.1107/S0567739476001873">Kabsch</a> algorithm. For those curious to see it in practice e is also a python available <a href="https://github.com/charnley/rmsd">rmsdpy</a>.</p> Debian 9 http://localhost/blog/debian9/ 2017-06-18T12:00:00Z 2017-06-18T12:00:00Z <p>For quite some time I've been using <a href="https://www.debian.org/">Debian</a> as my main (and only) operating system. When I started my adventure into the unix world Debian was not my first choice and I had to go through a few different distributions to finally realize where I feel most comfortable. Before Debian I've tried some of the popular distros such as <a href="http://crux.nu/">crux</a>, <a href="https://www.ubuntu.com/">Ubuntu</a>, <a href="https://www.archlinux.org/">Arch linux</a>, <a href="https://linuxmint.com/">linux Mint</a>, <a href="https://www.linuxmint.com/download_lmde.php">LMDE</a> but I didn't stick to any of them for long. At the time of writing <a href="https://www.debian.org/">Debian</a> is second on </p> <p>On June 17th <a href="https://www.debian.org/News/2017/20170617">Debian 9 codename <em>stretch</em> was released</a>.</p> <div style="text-align:center;padding-top: 30px;padding-bottom: 30px;"> <a href="https://www.debian.org/News/2017/20170617"> <img src="https://wiki.debian.org/DebianArt/Themes/softWaves?action=AttachFile&do=get&target=wikiBanner.png" alt="Debian Stretch graphic"> </a></div> <blockquote> <p><em>After 26 months of development the Debian project is proud to present its new stable version 9 (code name Stretch), which will be supported for the next 5 years thanks to the combined work of the Debian Security team and of the Debian Long Term Support team.</em></p> </blockquote> <p>Some of the main changes that I was most excited about included:</p> <ul> <li>new <a href="https://www.kernel.org/">kernel</a></li> <li>update to <a href="https://xfce.org/">XFCE</a> 4.12</li> <li>updated gcc, gfortran</li> <li>ffmpeg</li> <li><a href="https://www.libreoffice.org/">libreoffice</a> </li> <li><a href="http://www.vim.org/">vim</a></li> </ul> <p>The extended list of updates can be found in the <a href="https://www.debian.org/News/2017/20170617">release notes</a> or in the <a href="https://www.debian.org/releases/stretch/amd64/release-notes/ch-whats-new.en.html">what's new</a></p> <p>The update process itself was not very involved and included just a few steps that most of the linux users should be familiar with.</p> <p>in <code>/etc/apt/sources.list</code> I replaced all the instances of <code>jessie</code> to <code>stretch</code> and did the standard</p> <p>from jessie to stretch</p> <div class="codehilite"><pre><span></span><code>sudo apt-get update sudo apt-get upgrade sudo apt full-upgrade </code></pre></div> <p>Before diving in and doing the update it might be worth while to read the [official upgrade guide] just in case something goes wrong during your installation.</p>