desdeo-vis’s documentation¶
desdeo-vis¶
Visualisations and Jupyter Notebook enabled preference selection widgets for the DESDEO interactive multiobjective optimization library.
Currently features:
- Parallel coordinate plots based on Vega v3.
- Preference selection for NIMBUS (first stage only).
Installation / Usage¶
Typically you should install this at the same time as DESDEO, by following the instructions there.
Development¶
Compilation¶
Run:
npm run watch
You will need to refresh your browser, and possibly reload the Jupyter kernel to see some changes.
Adding/modifying a notebook¶
Each notebook has two versions, one in the desdeo_notebooks
directory and one
in the desdeo_notebooks/output
directory. The version in the prior directory
should be scrubbed of all output and is the canonical copy. Currently they have
have to be kept in sync manually, e.g. by regenerating the output notebook from
the canonical version. When regenerating, make sure to save widget state with
Widgets > Save Notebook Widget State
.
Known issues¶
If you are developing using a virtualenv (recommended) you may have trouble widget Javascript from outside the virtualenv getting picked up, meaning you can’t test your changes. This is a problem when you have installed desdeo-vis outside the virtualenv either system-wide or per-user. Currently, there’s no clear way to isolate this Javascript, so the solution is to uninstall the other versions of desdeo-vis and make sure to only install it inside virtualenvs.
Release process¶
- Update the version number in
desdeo_vis/_version.py
andpackage.json
, and runnpm install
to update it inpackage-lock.json
too. - Add an entry to HISTORY.md.
- Make a release commit.
- Make a git tag of this commit with
git tag v$VERSION
- Push – including the tags with
git push && git push --tags
- Upload to PyPI with
rm -rf build/ && python setup.py sdist bdist_wheel
andtwine upload dist/*
Example notebooks¶
Run this example in your browser
Solving the river pollution problem using NIMBUS¶
Welcome to this notebook demonstrating the DESDEO interactive multi-objective optimisation framework.
In this notebook we will consider a toy problem dealing with water quality management, and the pollution produced by a fishery. We want to maximise the water quality as measured in two locations: the fishery and a downstream city (the measurements are based on dissolved oxygen concentration). Additionally, we want to maximise the ROI (Return On Investment) of the fishery. Simultaneously we want to minimise the additional tax which residents of the city must pay.
To run this example, you need to run each individual code block (the
ones saying In [ ]:
to their left) by clicking on each one and then
clicking “Run”. Please refer to the background section of the
documentation
for information about NIMBUS.
Imports¶
This first code snippet simply imports the parts of DESDEO we need for this notebook. We import optimisation methods, NIMBUS and the RiverPollution problem definition from the desdeo module, and visualisation and preference selection tools and widgets from the desdeo_vis module.
In [1]:
from desdeo.method.NIMBUS import NIMBUS
from desdeo.optimization import SciPyDE
from desdeo.problem.toy import RiverPollution
from desdeo_vis.widget import NimbusPrefWidget, ParplotWidget
Initial iteration and preference selection¶
First we initialise the RiverPollution problem and the NIMBUS solution
method. Then we get an initial result. We can plot solutions at any time
using parplot
.
In [2]:
problem = RiverPollution()
method = NIMBUS(problem, SciPyDE)
results = method.init_iteration()
ParplotWidget(results.objective_vars, problem)
Next, we will give our first preference based on NIMBUS. We construct a
NimbusPrefWidget
, save it to a variable and display it. You can now
specify your preferences using the displayed widget. If you’re not sure
how to use it, read the documentation on classification in
NIMBUS.
In [3]:
pref = NimbusPrefWidget(results.objective_vars, problem)
pref
Solutions based on preference¶
We can now generate a new set of results based on this preference. Note
that this will raise an InvalidNimbusPreferencesException
if you run
it while the above preferences are invalid.
In [4]:
results2_all = method.next_iteration(preference=pref.nimbus_clf(method))
ParplotWidget(results2_all.objective_vars, problem)
We might choose to generate less extra solutions…
In [5]:
results2_less = method.next_iteration(preference=pref.nimbus_clf(method), num_scalars=2)
ParplotWidget(results2_less.objective_vars, problem)
We can also choose a subset of scalarization functions from NIM, ACH, GUESS, STOM. These are the NIMBUS scalarization function and the NIMBUS version of the achievement, guess and satisficing trade-off functions respectively.
In [6]:
results2_spec = method.next_iteration(preference=pref.nimbus_clf(method), scalars=['NIM', 'GUESS', 'STOM'])
ParplotWidget(results2_spec.objective_vars, problem)
Generating intermediate solutions¶
If none of these solutions exactly satisfy us, we can generate and view solutions between two solutions we’ve generated so far. Here we generate 4 solutions between the solutions generated by the NIMBUS and GUESS scalarisation functions.
In [7]:
results3 = method.between(results2_spec.objective_vars[0], results2_spec.objective_vars[1], 4)
ParplotWidget(results3.objective_vars, problem)
Run this example in your browser
Solving the cylinder problem using NIMBUS¶
Let’s consider a cell shaped like a cylinder, that is, a circular cross-sectional prism. The shape of the cell is here determined by two quantities, its radius \(x_1\) and its height \(x_2\). We want to maximize the volume of the cylinder and minimize the surface area. In addition to this, cylinder’s height should be close to 15 units.
The volume of a cylinder is the product of its base area and height. A cylinder can be cut and unrolled into a rectangle and the surface area of this rectangle is the product of its height and the perimeter of the circle \(2\pi x_1 x_2\). The sum of the cylinder’s two flat circular caps is \(2\pi x_1^2\). The total surface area of the cylinder with flat circular ends is then \(2\pi x_1^2 + 2\pi x_1 x_2\).
Three functions can be made from the above information: the one describing the volume of the cylinder, the other telling the surface area and the last measuring the height difference.
So the problem is:
Let’s assume that the cylinder’s height must be greater or equal to its width. This information gives us the following constraint:
\(g(x) = 2x_1 - x_2 \leq 0\)
To run this example, you need to run each individual code block (the
ones saying In [ ]:
to their left) by clicking on each one and then
clicking “Run”. Please refer to the background section of the
documentation
for information about NIMBUS.
Imports¶
This first code snippet simply imports the parts of DESDEO we need for this notebook. We import optimisation methods, NIMBUS and the CylinderProblem problem definition from the desdeo module, and visualisation and preference selection tools and widgets from the desdeo_vis module.
In [1]:
from desdeo.method.NIMBUS import NIMBUS
from desdeo.optimization import SciPyDE
from desdeo.problem.toy import CylinderProblem
from desdeo_vis.widget import NimbusPrefWidget, ParplotWidget
Getting a solutions based on a preference¶
First we initialise the CylinderProblem
problem and the NIMBUS
solution method. Then we get an initial result. We can plot solutions at
any time using ParplotWidget
.
In [2]:
problem = CylinderProblem()
method = NIMBUS(problem, SciPyDE)
results = method.init_iteration()
ParplotWidget(results.objective_vars, problem)
The first solution we get from NIMBUS is reasonable. However, we want to increase the cylinder’s volume as much as possible, still keeping the surface area and height difference low.
To do this, first display a NimbusPrefWidget
. After executing the
cell, a widget will display which you can use as follows: * For now we
let the volume vary freely by selecting <>
from the leftmost
dropdown. * The next column has the preferences for the surface area
function. We want to know how much the volume will be when the surface
area is less than 1900, so we set the dropdown to >=
and type
1900
into the textbox next to it. * For height difference, we won’t
accept a worse solution than the current one, so we set the dropdown to
<=
.
In [3]:
pref = NimbusPrefWidget(results.objective_vars, problem)
pref
Now we can plot the solutions given by NIMBUS.
In [5]:
results2 = method.next_iteration(preference=pref.nimbus_clf(method))
ParplotWidget(results2.objective_vars, problem)
INFEASIBLE 277.360873
API documentation¶
desdeo_vis.plot |
This module contains the machinery for doing non-interactive plotting of multidimensional data. |
desdeo_vis.widget |
This module contains Jupyter widgets for interactively specifying preferences as well as interactively and non-interactively displaying solutions. |