Using Flask for Scientific Web Applications

Bootstrap HTML style

The Bootstrap framework for creating web pages has been very popular in recent years, both because of the design and the automatic support for responsive pages on all sorts of devices. Bootstrap can easily be used in combination with Flask. The template file view_bootstrap.html is identical to the former view_table.html, except that we load the Bootstrap CSS file and include in comments how to add the typical navigation bar found in many Bootstrap-based web pages. Moreover, we use the grid layout functionality of Bootstrap to control the placement of elements (name, input field, label, and error message) in the input form.

The template looks like

<!DOCTYPE html>
<html lang="en">


<link href=
"http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"
rel="stylesheet">

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  TeX: {
     equationNumbers: {  autoNumber: "AMS"  },
     extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
  }
});
</script>
<script type="text/javascript" src=
"http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
<!--
<nav class="navbar navbar-default" role="navigation">
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
    <ul class="nav navbar-nav">
       {% for text, url in some_sequence %}
       <li><a href="/{{url}}">{{ text }}</a></li>
       {% endfor %}
       </ul>
</div>
</nav>
-->

<h2>Damped sine wave</h2>

This web page visualizes the function \(
u(t) = Ae^{-bt}\sin (w t), \hbox{ for } t\in [0,T]
\).

<p>
<form class="navbar-form navbar-top" method="post" action="">
  <div class="form-group">
  {% for field in form %}
    <div class="row">
     <div class="input-group">
      <label class="col-xs-1 control-label">
      <span class="input-group-addon"> \( {{ field.name }} \) </span>
      </label>
      <div class="col-xs-2">
      {{ field(class_="form-control") }}
      </div>
      <div class="col-xs-3">
        {{ field.label }}
      </div>
      {% if field.errors %}
        {% for error in field.errors %}
          <div class="col-xs-3">
            <div style="color: red;">{{ error }}</div>
          </div>
        {% endfor %}
      {% endif %}
     </div>
    </div>
  {% endfor %}
<br/>
<input type="submit" value="Compute" class="btn btn-default">
</form>

<p>
{% if result != None %}
<img src="{{ result }}" width="400">
{% endif %}
</html>

The input fields and fonts now get the typical Bootstrap look and feel:

The only special feature in this template is the need to pass a CSS class form-control to the field object in the part that defines the input field. We also use the standard input-group-addon style in the name part of the Bootstrap form. A heading Damped sine wave was added to demonstrate the Bootstrap fonts.

It is easy to switch to other Bootstrap styles, e.g., those in the "Bootswatch family": "http:bootswatch.com":

<link href=
"http://netdna.bootstrapcdn.com/bootswatch/3.1.1/X/bootstrap.min.css"
rel="stylesheet">

where X can be journal, cosmo, flatly, and other legal Bootswatch styles. The journal style looks like this:

While view_bootstrap.html makes use of plain Bootstrap HTML code, there is also a higher-level framework, called Flask-Bootstrap that combines Flask and Bootstrap. Installation of this extension is done by sudo pip install flask-bootstrap.

After app = Flask(__name__) we need to do

from flask_bootstrap import Bootstrap
Bootstrap(app)

We introduce a command-line argument to control whether we want the plain view or the Bootstrap view. The complete controller.py file then looks like

from model import InputForm
from flask import Flask, render_template, request
from compute import compute
import sys

app = Flask(__name__)

try:
    template_name = sys.argv[1]
except IndexError:
    template_name = 'view_plain'

if template_name == 'view_flask_bootstrap':
    from flask_bootstrap import Bootstrap
    Bootstrap(app)

@app.route('/vib1', methods=['GET', 'POST'])
def index():
    form = InputForm(request.form)
    if request.method == 'POST' and form.validate():
        result = compute(form.A.data, form.b.data,
                         form.w.data, form.T.data)
    else:
        result = None

    return render_template(template_name + '.html',
                           form=form, result=result)

if __name__ == '__main__':
    app.run(debug=True)

The template employs new keywords extends and block:

{% extends "bootstrap/base.html" %}

{% block styles %}
{{super()}}
<style>
    .appsize { width: 800px }
</style>

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  TeX: {
     equationNumbers: {  autoNumber: "AMS"  },
     extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
  }
});
</script>
<script type="text/javascript" src=
"http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
{% endblock %}

<!--
{% block navbar %}
<nav class="navbar navbar-default" role="navigation">
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
    <ul class="nav navbar-nav">
       {% for f in some_sequence %}
       <li><a href="/{{f}}">{{f}}</a></li>
       {% endfor %}
       </ul>
</div>
</nav>
{% endblock %}
-->

{% block content %}

<h2>Damped sine wave</h2>

This web page visualizes the function \(
u(t) = Ae^{-bt}\sin (w t), \hbox{ for } t\in [0,T]
\).

<p>
<form class="navbar-form navbar-top" method="post" action="">
  <div class="form-group">
  {% for field in form %}
    <div class="row">
     <div class="input-group appsize">
      <label class="col-sm-1 control-label">
      <span class="input-group-addon"> \( {{ field.name }} \) </span>
      </label>
      <div class="col-sm-4">
      {{ field(class_="form-control") }}
      </div>
      <div class="col-sm-4">
        {{ field.label }}
      </div>
      {% if field.errors %}
        {% for error in field.errors %}
          <div class="col-sm-3">
            <div style="color: red;">{{ error }}</div>
          </div>
        {% endfor %}
      {% endif %}
     </div>
    </div>
  {% endfor %}
<br/>
<input type="submit" value="Compute" class="btn btn-default">
</form>

<p>
{% if result != None %}
<img src="{{ result }}" width="500">
{% endif %}
</html>
{% endblock %}

It is important to have the MathJax script declaration and all styles within {% block styles %}.

It seems easier to apply plain Bootstrap HTML code than the functionality in the Flask-Bootstrap layer.