Make a web application that reads two numbers from a web page,
adds the numbers, and prints the sum in a new web page.
Package the necessary files that constitute the application
in a tar file.
Filename: `add2.tar.gz`

.

Suppose you have tabular data in a file:

```
# t y error
0.0000 1.2345 1.4E-4
1.0000 0.9871 -4.9E-3
1.2300 0.5545 8.2E-3
```

That is, there is a comment line with headings for the various
columns, and then floating-point values are listed with an
arbitrary number of columns and rows. You want to upload such
a data file to a web application and have the each column, from
the second one, plotted against the the values in the first column.
In the particular example, `y`

and `error`

should be plotted against
`t`

, yielding two curves.

The web application may have one field: the name of the file to upload.
Search for constructions on how to upload a files and write this
application. Generate a suitable data file for testing purposes.
Filename: `upload.tar.gz`

.

The purpose of this exercise is to write a web application that can visualize any user-given formula. For example, in the interface below,

the user has

- specified a curve \( \sin (x) \) (
`sin(x)`

) to be plotted - specified the \( x \) interval to be \( [0,2\pi] \) (
`[0, 2*pi]`

) - clicked
*Compute*to get a blue line with the sine curve - specified a new formula \( \sin(x)e^{-x} \) (
`sin(x)*exp(-x)`

) - chosen
*No*as the answer to*Erase all curves?* - clicked
*Compute*to have the \( \sin(x)e^{-x} \) drawn with green line without erasing the previous curve

You may use the `vib1`

app from the section Programming the Flask application
with the `view_errcheck.html`

template as starting point.
Preferably, let plots be created as strings, as explained for the `vib2`

app in the section Avoiding plot files.

The *Formula* and *Domain* fields need to be `TextField`

objects,
and the compute function must perform an `eval`

on the user's input.
The *Erase* field is a `SelectField`

object with selections *Yes* and
*No*. The former means that the compute function calls the `figure`

function in Matplotlib before creating a new plot. If this is not
done, a new formula will be plotting in the same figure as the last one.
With the Yes/No selection, it is possible either plot individual curves
or compare curves in the same plot.

Performing `eval`

on the user's input requires that names like
`sin`

, `exp`

, and `pi`

are defined. The simplest approach is to
do a

```
from numpy import *
```

in the top of the file containing the compute function. All the names
from `numpy`

are then available as global variables and one can simply
do `domain = eval(domain)`

to turn the string `domain`

coming from
the *Domain* text field into a Python list with two elements.

A better approach is not to rely on global variables, but run `eval`

in the `numpy`

namespace:

```
import numpy
domain = eval(domain, numpy.__dict__)
```

The evaluation of the formula is slightly more complicated if `eval`

is to be run with the `numpy`

namespace. One first needs
to create \( x \) coordinates:

```
x = numpy.linspace(domain[0], domain[1], 10001)
```

Now, `eval(formula, numpy.__dict__)`

will not work because a formula
like `sin(x)`

needs both `sin`

and `x`

in the namespace. The latter
is not in the namespace and must be explicitly included. A new namespace
can be made:

```
namespace = numpy.__dict__.copy()
namespace.update({'x': x})
formula = eval(formula, namespace)
```

You should add tests when evaluating and using the strings from input as these may have wrong syntax.

Filename: `plot_formula.tar.gz`

.

This exercise develops a web application that can plot Taylor polynomial
approximations of *any* degree
to *any* user-given formula. You should do
Exercise 3: Plot a user-specified formula first as many of the techniques there
must be used and even further developed in the present exercise.

The figure below shows an example of what one can do in the web app:

Here, the user has

- filled in the formula \( \sin(x) \) (
`sin(x)`

) - specified
*N*to be 3 - clicked
*Compute*to get the formula \( \sin(x) \) plotted together with the Taylor polynomial approximation of degree 3, expanded around \( x=0 \) - changed
*N*to 5 - chosen
*No*for the question*Erase all curves?* - clicked
*Compute*to have the series expansion of degree 5 plotted in the same plot - changed
*N*to 10 - clicked
*Compute*to have the series expansion of degree 10 plotted in the same plot

`sympy`

to produce Taylor polynomial expansions of arbitrary
expressions. Here is a session demonstrating how to obtain the
series expansion of \( e^{-x}\sin (\pi x) \) to 2nd degree.

```
>>> import sympy as sp
>>> x = sp.symbols('x')
>>> f = sp.exp(-x)*sp.sin(sp.pi*x)
>>> f.series(x, 0, 3)
pi*x - pi*x**2 + O(x**3)
>>> sp.latex(f.series(x, 0, 3))
'\\pi x - \\pi x^{2} + \\mathcal{O}\\left(x^{3}\\right)'
>>> fs = f.series(x, 0, 3).removeO() # get rid of O() term
>>> fs
-pi*x**2 + pi*x
>>> f_func = sp.lambdify([x], fs) # make Python function
>>> f_func(1)
0.0
>>> f_func(2)
-6.283185307179586
```

Basically, the steps above must be carried out to create a Python
function for the series expansion such that it can be plotted.
A similar `sp.lambdify`

call on the original formula is also necessary
to plot that one.

However, the challenge is that the formula is available only as a
string, and it may contain an independent variable whose name is also
only available through a string from the web interface. That is, we
may give formulas like `exp(-t)`

if `t`

is chosen as independent
variable. Also, the expression does not contain function names
prefixed with `sympy`

or `sp`

, just plain names like `sin`

, `cos`

,
`exp`

, etc. An example on `formula`

is `cos(pi*x) + log(x)`

.

**a)**
Write a function

```
def formula2series2pyfunc(formula, N, x, x0=0):
```

that takes a `sympy`

formula, and integer `N`

, a `sympy`

symbol `x`

and another `sympy`

symbol `x0`

and returns
1) a Python function for `formula`

, 2) a Python function for the
series expansion of degree `N`

of the formula around `x0`

, and
3) a LaTeX string containing the formula for the series expansion.

Put the function in a file `compute.py`

. You should thereafter be able to run
the following session:

```
>>> import compute
>>> import sympy as sp
>>> from sympy import *
>>> t = symbols('t')
>>> formula = exp(-2*t)
>>> f, s, latex = compute.formula2series2pyfunc(formula, 3, t)
>>> latex
'- \\frac{4 t^{3}}{3} + 2 t^{2} - 2 t + 1'
>>> import matplotlib.pyplot as plt
>>> import numpy as np
>>> t = np.linspace(0, 2)
>>> plt.plot(t, f(t), t, s(t))
[<matplotlib.lines.Line2D at 0x7fc6c020f350>,
<matplotlib.lines.Line2D at 0x7fc6c020f5d0>]
>>> plt.show()
```

The resulting plot is displayed below.

The series expansion is obtained by `formula.series(x, x0, N)`

,
but the output contains an `O()`

term which makes it impossible to
convert the expression to a Python function via `sympy.lambify`

.
Use

```
series = formula.series(x, x0, N+1).removeO()
```

to get an expression that can be used as argument to `sympy.lambdify`

.
We use `N+1`

since `N`

in the `series`

function refers to the degree
of the `O()`

term, which is now removed.

For the LaTeX expression it is natural to have the `O()`

term:

```
latex = sympy.latex(formula.series(x, x0, N+1))
```

because then the terms start with the lowest order (and not the highest
order as is the case when `removeO()`

is used).

**b)**
Write the compute function:

```
def visualize_series(
formula, # string: formula
independent_variable, # string: name of independent var.
N, # int: degree of polynomial approx.
xmin, xmax, ymin, ymax, # strings: extent of axes
legend_loc, # string: upper left, etc.
x0='0', # string: point of expansion
erase='yes', # string: 'yes' or 'no'
):
```

Converting the string `formula`

to a valid `sympy`

expression is
challenging. First, create a local variable for a `sympy`

symbol
with the content of
`independent_variable`

as name, since such a variable is needed
with performing `eval`

on `formula`

. Also introduce a variable `x`

to point to the same `sympy`

symbol. Relevant code is

```
# Turn independent variable into sympy symbol, stored in x
import sympy as sp
exec('x = %s = sp.symbols("%s")' %
(independent_variable, independent_variable))
```

Evaluating `formula`

in the namespace of `sympy`

(so that all the `sin`

,
`exp`

, `pi`

, and similar symbols are defined properly as `sympy`

objects) needs a merge of the `sympy`

namespace and the variable for
the `sympy`

symbol representing the independent variable:

```
namespace = sp.__dict__.copy()
local = {}
local[independent_variable] = x
namespace.update(local)
formula = eval(formula, namespace)
```

Turning `x0`

into a valid `sympy`

expression is easier: `x0 = eval(x0, sp.__dict__)`

.

Note that in the web interface, the minimum and maximum values on the axis
can be mathematical expressions such as `2*pi`

. This means that these
quantities must be strings that are evaluated in the `numpy`

namespace, e.g.,

```
import numpy as np
xmin = eval(xmin, np.__dict__)
```

Getting the legends right when plotting multiple curves in the same
plot is a bit tricky. One solution is to have a global variable `legends`

that is initialized to `[]`

and do the following inside the compute function:

```
import matplotlib.pyplot as plt
global legends
if erase == 'yes': # Start new figure?
plt.figure()
legends = []
if not legends:
# We come here every time the figure is empty so
# we need to draw the formula
legends.append('$%s$' % sp.latex(formula))
plt.plot(x, f(x))
```

Here, `f`

is the Python function for computing the `numpy`

variant
of the expression in `formula`

.

Use the test block in the file to call the compute function several
times with different values of the `erase`

parameter to test that
the erase functionality is correct.

**c)**
Write the remaining files. These have straightforward content if
Exercise 3: Plot a user-specified formula is done and understood.

Filename: `Taylor_approx.tar.gz`

.

`gen`

app
Add a new argument `x_axis`

to the `compute`

function in the
`gen`
application from the section Autogenerating the code. The `x_axis`

argument measures the extent
of the \( x \) axis in the plots in terms of the number of standard
deviations (default may be 7). Observe how the web interface
automatically adds the new argument and how the plots adapt!

The purpose of this exercise is to look into web apps with multipe submit buttons. More precisely, we want a web app that can perform two actions: add \( a+b \) and multiply \( pq \). There should be two parts of the open web page:

- Two fields for \( a \) and \( b \) and an
`Add`

button. Clicking on`Add`

brings up a new line below add:`Sum: 3`

if \( a+b=3 \). - Two fields for \( p \) and \( q \) and a
`Multiply`

button. Clicking on`Multiply`

brings up a new line below add:`Product: 5`

if \( pq=5 \).

Make two input form classes, say `AddForm`

and `MulForm`

in `model.py`

.
Since it suffices to fill in either \( a \) and \( b \) or \( p \) and \( q \), all
fields cannot be required.
Let the controller process both classes and collect the two forms
and two results in a `form`

dictionary and a `result`

dictionary
that is passed on the to the `view.html`

file.

To detect which "subapp" (add or multply) that was used, one can
give a name to the submit button and in the controller check which
of the submit buttons that was pressed (and then perform the associated
computation and update of results). In `view.html`

:

```
<input type="submit" name="btn" value="Add"></form>
...
<input type="submit" name="btn" value="Multiply"></form>
```

In `controller.py`

:

```
if request.method == 'POST' and f.validate() and \
request.form['btn'] == 'Multiply':
result['mul'] = mul(f.p.data, f.q.data)
```

Filename: `addmul.tar.gz`

.

`gen`

app with more data types
In the `gen`
application from the section Autogenerating the code,
use the `label`

argument in the form field objects to add an
information of the type of data that is to be supplied in the
text field. Extend the `model.py`

file to also handle
lists, tuples, and Numerical Python arrays. For these three
new data types, use a `TextField`

object and run `eval`

on the text in the `view.py`

file.
A simple test is to extend the `compute`

function with an
argument `x_range`

for the range of the \( x \) axis, specified as
an interval (2-list or 2-tuple).
Filename: `gen_ext.tar.gz`

.

Given a `compute`

with a set of positional and keyword
arguments, the purpose of this exercise is to *automatically* generate the
Flask files `model.py`

and `controller.py`

. Use the Python `inspect`

module, see the section Autogenerating the code, to extract
the positional and keyword arguments in `compute`

, and use this
information to construct the relevant Python code in strings. Write
the strings to `model.py`

and `controller.py`

files. Assume as
in the section Autogenerating the code that the user provides
a file `view_results.html`

for defining how the returned object
from the `compute`

function is to be rendered.

Test the code generator on the `compute`

function in the `vib1`

application to check that the generated
`model.py`

and `controller.py`

files are correct.
Filename: `generate_flask.py`

.

The Bokeh Python library works very well with Flask. The purpose of this exercise is to make a web app where one can explore how parameters in a function influence the function's shape. Given some function \( f(x;p_0,p_1,\ldots,p_n) \), where \( x \) is the independent variable and \( p_0,p_1,\ldots,p_n \) are parameters, we want to create a user interface with a plot field and text fields or sliders for \( p_0,p_1,\ldots,p_n \) such that altering any parameter immediately updates the graph of the \( f \) as a function of \( x \). The Bokeh web side contains a demo: for the specific function $$ f(x;x_0,A,\phi,\omega)= x_0 + A\sin(\omega (x + \phi)).$$ However, this project is about accepting any function \( f(x;p_0,p_1,\ldots,p_n) \) and creating tailored Flask/Bokeh code of the type in the demo. The user must specify a Python function for \( f \):

```
def f(x, p):
x_0, A, phi, omega = p
return x_0 + A*sin(omega*(x - phi))
```

where `p`

is a list of parameter values. In addition, the user must
provide info about each parameter: the name, a range or a number,
and if range, a default value. Here is an example:

```
p_info = [
('offset', [-2, 2], 0),
('amplitude', [0, 5], 2.5),
('phase', 0),
('frequency', [1, 10], 1)]
```

Parameters with an interval range get a slider for setting the value,
while parameters with only a number, as for `phase`

in this example,
get a text field where the user can alter the number.

The user must also provide a suitable range for the \( x \) axis. As test case beyond the example above, try a Gaussian function with this input from the user:

```
import numpy as np
def gaussian(x, p):
mu, sigma = p
return 1./(sigma*np.sqrt(2*np.pi))*\
np.exp(-0.5*(x - mu)**2/sigma**2)
p_info = [
('mean', [-2, 2], 0),
('standard deviation', [0.1, 4], 1)]
x_axis = [-10, 10]
```

Filename: `expore_func.tar.gz`

.

- Flask website
- Flask Quick Start
- Flask tutorial
- The Flask Mega-Tutorial by M. Grinberg
- WTForms Documentation
- The Jinja2 templating language
- The Werkzeug library
- An Introduction to Python's Flask Framework by L. Polepeddi
- Discover Flask, Part I - Setting up a Static Site
- Flaskr: A Minimal Blog Application: Code, Explanation
- Flask Login with Facebook, Twitter, and OpenID
- Lightweight Python Apps with Flask, Bootstrap, and Heroku by R. Shea
- How to Structure Large Flask Applications
- Explore Flask by R. Picard (online book)
- Flask Mega Tutorial for Data Scientists
- Quick Flask++ tutorial
- Flask-Bootstrap with documentation, basic usage and example
- Skulpt: Interactive Python in the browser (but no support for
`numpy`

,`scipy`

, or`matplotlib`

)