Source code for menpowidgets.menpofit.options
import ipywidgets
from traitlets.traitlets import Dict
from menpowidgets.abstract import MenpoWidget
from menpowidgets.options import AnimationOptionsWidget
from menpowidgets.tools import SlicingCommandWidget
from menpowidgets.style import (format_font, format_box,
map_styles_to_hex_colours)
[docs]class ResultOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting options when visualizing a fitting result.
The widget consists of the following parts from `ipywidgets`:
== ============== ======================= =========================
No Object Property (`self.`) Description
== ============== ======================= =========================
1 `RadioButtons` `mode` Subplot mode flag
2 `Checkbox` `render_image` Image rendering flag
3 `VBox` `mode_render_image_box` Contains 1, 2
4 `Latex` `shape_buttons[0]` 'Shape:' str
5 `ToggleButton` `shape_buttons[1]` Initial shape toggle
6 `ToggleButton` `shape_buttons[2]` Final shape toggle
7 `ToggleButton` `shape_buttons[3]` Ground truth shape toggle
8 `HBox` `shape_selection` Contains 4, 5, 6, 7
== ============== ======================= =========================
Note that:
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* The selected values are stored in the ``self.selected_values`` `trait`
which is a `list`.
* To set the styling of this widget please refer to the :meth:`style` and
:meth:`predefined_style` methods.
* To update the handler callback function of the widget, please refer to
the :meth:`replace_render_function` method.
Parameters
----------
has_gt_shape : `bool`
Whether the fitting result object has the ground truth shape.
has_initial_shape : `bool`
Whether the fitting result object has the initial shape.
has_image : `bool`
Whether the fitting result object has the image.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
It must have signature ``render_function(change)`` where ``change`` is
a `dict` with the following keys:
* ``type`` : The type of notification (normally ``'change'``).
* ``owner`` : the `HasTraits` instance
* ``old`` : the old value of the modified trait attribute
* ``new`` : the new value of the modified trait attribute
* ``name`` : the name of the modified trait attribute.
If ``None``, then nothing is assigned.
style : `str` (see below), optional
Sets a predefined style at the widget. Possible options are:
============= ============================
Style Description
============= ============================
``'minimal'`` Simple black and white style
``'success'`` Green-based style
``'info'`` Blue-based style
``'warning'`` Yellow-based style
``'danger'`` Red-based style
``''`` No style
============= ============================
Example
-------
Let's create a fitting result options widget and then update its state.
Firstly, we need to import it:
>>> from menpowidgets.menpofit.options import ResultOptionsWidget
Now let's define a render function that will get called on every widget
change and will dynamically print the selected options:
>>> from menpo.visualize import print_dynamic
>>> def render_function(change):
>>> s = "Final: {}, Initial: {}, GT: {}, Image: {}, Subplots: {}".format(
>>> wid.selected_values['render_final_shape'],
>>> wid.selected_values['render_initial_shape'],
>>> wid.selected_values['render_gt_shape'],
>>> wid.selected_values['render_image'],
>>> wid.selected_values['subplots_enabled'])
>>> print_dynamic(s)
Create the widget with some initial options and display it:
>>> wid = ResultOptionsWidget(has_gt_shape=True,
>>> has_initial_shape=True, has_image=True,
>>> render_function=render_function,
>>> style='info')
>>> wid
By changing the various widgets, the printed message gets updated. Finally,
let's change the widget status with a new set of options:
>>> wid.set_widget_state(has_gt_shape=True, has_initial_shape=False,
>>> has_image=False, allow_callback=True)
"""
def __init__(self, has_gt_shape, has_initial_shape, has_image,
render_function=None, style='minimal'):
# Initialise default options dictionary
render_image = True if has_image else False
default_options = {'render_final_shape': True,
'render_initial_shape': False,
'render_gt_shape': False,
'render_image': render_image,
'subplots_enabled': True}
# Assign properties
self.has_gt_shape = None
self.has_initial_shape = None
self.has_image = None
# Create children
self.mode = ipywidgets.RadioButtons(
description='Figure mode:',
options={'Single': False, 'Multiple': True},
value=default_options['subplots_enabled'])
self.render_image = ipywidgets.Checkbox(
description='Render image',
value=default_options['render_image'])
self.mode_render_image_box = ipywidgets.VBox(
children=[self.mode, self.render_image], margin='0.2cm')
self.shape_buttons = [
ipywidgets.Latex(value='Shape:', margin='0.2cm'),
ipywidgets.ToggleButton(description='Initial', value=False),
ipywidgets.ToggleButton(description='Final', value=True),
ipywidgets.ToggleButton(description='Groundtruth', value=False)]
self.shape_selection = ipywidgets.HBox(children=self.shape_buttons,
align='center', margin='0.2cm',
padding='0.2cm')
# Create final widget
children = [self.mode_render_image_box, self.shape_selection]
super(ResultOptionsWidget, self).__init__(
children, Dict, default_options,
render_function=render_function, orientation='horizontal',
align='start')
# Set values
self.add_callbacks()
self.set_widget_state(has_gt_shape, has_initial_shape, has_image,
allow_callback=False)
# Set style
self.predefined_style(style)
def _save_options(self, change):
self.selected_values = {
'render_initial_shape': (self.shape_buttons[1].value and
self.has_initial_shape),
'render_final_shape': self.shape_buttons[2].value,
'render_gt_shape': (self.shape_buttons[3].value and
self.has_gt_shape),
'render_image': (self.render_image.value and self.has_image),
'subplots_enabled': self.mode.value}
[docs] def add_callbacks(self):
r"""
Function that adds the handler callback functions in all the widget
components, which are necessary for the internal functionality.
"""
self.render_image.observe(self._save_options, names='value',
type='change')
self.mode.observe(self._save_options, names='value', type='change')
for w in self.shape_selection.children[1::]:
w.observe(self._save_options, names='value', type='change')
[docs] def remove_callbacks(self):
r"""
Function that removes all the internal handler callback functions.
"""
self.render_image.unobserve(self._save_options, names='value',
type='change')
self.mode.unobserve(self._save_options, names='value', type='change')
for w in self.shape_selection.children[1::]:
w.unobserve(self._save_options, names='value', type='change')
[docs] def set_visibility(self):
r"""
Function that sets the visibility of the various components of the
widget, depending on the properties of the current image object, i.e.
``self.n_channels`` and ``self.image_is_masked``.
"""
self.shape_selection.children[1].visible = self.has_initial_shape
self.shape_selection.children[3].visible = self.has_gt_shape
self.render_image.visible = self.has_image
[docs] def style(self, box_style=None, border_visible=False, border_colour='black',
border_style='solid', border_width=1, border_radius=0, padding=0,
margin=0, font_family='', font_size=None, font_style='',
font_weight='', buttons_style=''):
r"""
Function that defines the styling of the widget.
Parameters
----------
box_style : `str` or ``None`` (see below), optional
Possible widget style options::
'success', 'info', 'warning', 'danger', '', None
border_visible : `bool`, optional
Defines whether to draw the border line around the widget.
border_colour : `str`, optional
The colour of the border around the widget.
border_style : `str`, optional
The line style of the border around the widget.
border_width : `float`, optional
The line width of the border around the widget.
border_radius : `float`, optional
The radius of the border around the widget.
padding : `float`, optional
The padding around the widget.
margin : `float`, optional
The margin around the widget.
font_family : `str` (see below), optional
The font family to be used. Example options::
'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace',
'helvetica'
font_size : `int`, optional
The font size.
font_style : `str` (see below), optional
The font style. Example options::
'normal', 'italic', 'oblique'
font_weight : See Below, optional
The font weight. Example options::
'ultralight', 'light', 'normal', 'regular', 'book', 'medium',
'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy',
'extra bold', 'black'
buttons_style : `str` or ``None`` (see below), optional
Style options:
'success', 'info', 'warning', 'danger', 'primary', '', None
"""
format_box(self, box_style, border_visible, border_colour, border_style,
border_width, border_radius, padding, margin)
format_font(self, font_family, font_size, font_style, font_weight)
format_font(self.render_image, font_family, font_size, font_style,
font_weight)
format_font(self.mode, font_family, font_size, font_style, font_weight)
format_font(self.shape_selection.children[0], font_family, font_size,
font_style, font_weight)
for w in self.shape_selection.children[1::]:
format_font(w, font_family, font_size, font_style, font_weight)
w.button_style = buttons_style
[docs] def predefined_style(self, style):
r"""
Function that sets a predefined style on the widget.
Parameters
----------
style : `str` (see below)
Style options:
============= ============================
Style Description
============= ============================
``'minimal'`` Simple black and white style
``'success'`` Green-based style
``'info'`` Blue-based style
``'warning'`` Yellow-based style
``'danger'`` Red-based style
``''`` No style
============= ============================
"""
if style == 'minimal':
self.style(box_style=None, border_visible=True,
border_colour='black', border_style='solid',
border_width=1, border_radius=0, padding='0.2cm',
margin='0.3cm', font_family='', font_size=None,
font_style='', font_weight='', buttons_style='')
elif (style == 'info' or style == 'success' or style == 'danger' or
style == 'warning'):
self.style(box_style=style, border_visible=True,
border_colour=map_styles_to_hex_colours(style),
border_style='solid', border_width=1, border_radius=10,
padding='0.2cm', margin='0.3cm', font_family='',
font_size=None, font_style='', font_weight='',
buttons_style='primary')
else:
raise ValueError('style must be minimal or info or success or '
'danger or warning')
[docs] def set_widget_state(self, has_gt_shape, has_initial_shape, has_image,
allow_callback=True):
r"""
Method that updates the state of the widget.
Parameters
----------
has_gt_shape : `bool`
Whether the fitting result object has the ground truth shape.
has_initial_shape : `bool`
Whether the fitting result object has the initial shape.
has_image : `bool`
Whether the fitting result object has the image.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
# keep old value
old_value = self.selected_values
# check if updates are required
if (self.has_gt_shape != has_gt_shape or
self.has_initial_shape != has_initial_shape or
self.has_image != has_image):
# Assign properties
self.has_gt_shape = has_gt_shape
self.has_initial_shape = has_initial_shape
self.has_image = has_image
# Set widget's visibility
self.set_visibility()
# Get values
self._save_options({})
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class IterativeResultOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting options when visualizing an iterative
fitting result. The widget consists of the following parts from
`ipywidgets` and :ref:`api-tools-index`:
== ============================= =========================== ===============
No Object Property (`self.`) Description
== ============================= =========================== ===============
1 `RadioButtons` `mode` Subplot mode
2 `Checkbox` `render_image` Image rendering
3 `VBox` `mode_render_image_box` Contains 1, 2
4 `Latex` `shape_buttons[0]` 'Shape:' str
5 `ToggleButton` `shape_buttons[1]` Initial shape
6 `ToggleButton` `shape_buttons[2]` Final shape
7 `ToggleButton` `shape_buttons[3]` Ground truth
8 `HBox` `result_box` Contains 4-7
9 `RadioButtons` `iterations_mode` 'Animation' or
'Static'
10 :map:`AnimationOptionsWidget` `index_animation` Animation wid
11 :map:`SlicingCommandWidget` `index_slicing` Slicing wid
12 `Button` `plot_errors_button` Errors plot
13 `Button` `plot_displacements_button` Displacements
14 `Button` `plot_costs_button` Costs plot
15 `HBox` `buttons_box` Contains 12-14
16 `VBox` `index_buttons_box` 10,11,15
17 `HBox` `mode_index_buttons_box` Contains 9, 16
18 `Latex` `no_iterations_text` No iterations
19 `VBox` `iterations_box` Contains 17, 18
20 `Tab` `result_iterations_tab` Contains 8, 19
== ============================= =========================== ===============
Note that:
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* The selected values are stored in the ``self.selected_values`` `trait`
which is a `list`.
* To set the styling of this widget please refer to the :meth:`style` and
:meth:`predefined_style` methods.
* To update the handler callback function of the widget, please refer to
the :meth:`replace_render_function` method.
* To update the handler callback plot functions of the widget, please
refer to :meth:`replace_plots_function`, :meth:`replace_errors_function`
and :meth:`replace_displacements_function` methods.
Parameters
----------
has_gt_shape : `bool`
Whether the fitting result object has the ground truth shape.
has_initial_shape : `bool`
Whether the fitting result object has the initial shape.
has_image : `bool`
Whether the fitting result object has the image.
n_shapes : `int` or ``None``
The total number of shapes. If ``None``, then it is assumed that no
iteration shapes are available.
has_costs : `bool`
Whether the fitting result object has costs attached.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
It must have signature ``render_function(change)`` where ``change`` is
a `dict` with the following keys:
* ``type`` : The type of notification (normally ``'change'``).
* ``owner`` : the `HasTraits` instance
* ``old`` : the old value of the modified trait attribute
* ``new`` : the new value of the modified trait attribute
* ``name`` : the name of the modified trait attribute.
If ``None``, then nothing is assigned.
tab_update_function : `callable` or ``None``, optional
A function that gets called when switching between the 'Result' and
'Iterations' tabs. If ``None``, then nothing is assigned.
displacements_function : `callable` or ``None``, optional
The function that is executed when the 'Displacements' button is
pressed. It must have signature ``displacements_function(name)``. If
``None``, then nothing is assigned and the button is invisible.
errors_function : `callable` or ``None``, optional
The function that is executed when the 'Errors' button is pressed. It
must have signature ``errors_function(name)``. If ``None``, then
nothing is assigned and the button is invisible.
costs_function : `callable` or ``None``, optional
The function that is executed when the 'Errors' button is pressed. It
must have signature ``displacements_function(name)``. If ``None``,
then nothing is assigned and the button is invisible.
style : `str` (see below), optional
Sets a predefined style at the widget. Possible options are:
============= ============================
Style Description
============= ============================
``'minimal'`` Simple black and white style
``'success'`` Green-based style
``'info'`` Blue-based style
``'warning'`` Yellow-based style
``'danger'`` Red-based style
``''`` No style
============= ============================
tabs_style : `str` (see below), optional
Sets a predefined style at the tab widgets. Possible options are:
============= ============================
Style Description
============= ============================
``'minimal'`` Simple black and white style
``'success'`` Green-based style
``'info'`` Blue-based style
``'warning'`` Yellow-based style
``'danger'`` Red-based style
``''`` No style
============= ============================
Example
-------
Let's create an iterative result options widget and then update its state.
Firstly, we need to import it:
>>> from menpowidgets.menpofit.options import IterativeResultOptionsWidget
Now let's define a render function that will get called on every widget
change and will print the selected options:
>>> def render_function(change):
>>> print(wid.selected_values)
Let's also define a plot function that will get called when one of the
'Errors', 'Costs' or 'Displacements' buttons is pressed:
>>> def plot_function(name):
>>> print(name)
Create the widget with some initial options and display it:
>>> wid = IterativeResultOptionsWidget(
>>> has_gt_shape=True, has_initial_shape=True, has_image=True,
>>> n_shapes=20, has_costs=True, render_function=render_function,
>>> displacements_function=plot_function,
>>> errors_function=plot_function, costs_function=plot_function,
>>> style='info', tabs_style='danger')
>>> wid
By changing the various widgets, the printed message gets updated. Finally,
let's change the widget status with a new set of options:
>>> wid.set_widget_state(has_gt_shape=False, has_initial_shape=True,
>>> has_image=True, n_shapes=None, has_costs=False,
>>> allow_callback=True)
"""
def __init__(self, has_gt_shape, has_initial_shape, has_image, n_shapes,
has_costs, render_function=None, tab_update_function=None,
displacements_function=None, errors_function=None,
costs_function=None, style='minimal', tabs_style='minimal'):
# Initialise default options dictionary
render_image = True if has_image else False
default_options = {'render_final_shape': True,
'render_initial_shape': False,
'render_gt_shape': False,
'render_image': render_image,
'subplots_enabled': True}
# Assign properties
self.has_gt_shape = None
self.has_initial_shape = None
self.has_image = None
self.n_shapes = -1
self.tab_update_function = tab_update_function
# Create result tab
self.mode = ipywidgets.RadioButtons(
description='Figure mode:',
options={'Single': False, 'Multiple': True},
value=default_options['subplots_enabled'])
self.render_image = ipywidgets.Checkbox(
description='Render image',
value=default_options['render_image'])
self.mode_render_image_box = ipywidgets.VBox(
children=[self.mode, self.render_image], margin='0.2cm')
self.shape_buttons = [
ipywidgets.Latex(value='Shape:', margin='0.2cm'),
ipywidgets.ToggleButton(description='Initial', value=False),
ipywidgets.ToggleButton(description='Final', value=True),
ipywidgets.ToggleButton(description='Groundtruth', value=False)]
self.result_box = ipywidgets.HBox(children=self.shape_buttons,
align='center', margin='0.2cm',
padding='0.2cm')
# Create iterations tab
self.iterations_mode = ipywidgets.RadioButtons(
options={'Animation': 'animation', 'Static': 'static'},
value='animation', description='Iterations:', margin='0.15cm')
self.iterations_mode.observe(self._stop_animation, names='value',
type='change')
self.iterations_mode.observe(self._index_visibility, names='value',
type='change')
index = {'min': 0, 'max': 1, 'step': 1, 'index': 0}
self.index_animation = AnimationOptionsWidget(
index, description='', index_style='slider',
loop_enabled=False, interval=0.)
slice_options = {'command': 'range({})'.format(1),
'length': 1}
self.index_slicing = SlicingCommandWidget(
slice_options, description='', example_visible=True,
continuous_update=False, orientation='vertical')
self.plot_errors_button = ipywidgets.Button(
description='Errors', margin='0.1cm',
visible=has_gt_shape and errors_function is not None)
self.plot_displacements_button = ipywidgets.Button(
description='Displacements', margin='0.1cm',
visible=displacements_function is not None)
self.plot_costs_button = ipywidgets.Button(
description='Costs', margin='0.1cm', visible=has_costs)
self.buttons_box = ipywidgets.HBox(
children=[self.plot_errors_button, self.plot_costs_button,
self.plot_displacements_button])
self.index_buttons_box = ipywidgets.VBox(
children=[self.index_animation, self.index_slicing,
self.buttons_box])
self.mode_index_buttons_box = ipywidgets.HBox(
children=[self.iterations_mode, self.index_buttons_box],
margin='0.2cm', padding='0.2cm')
self.no_iterations_text = ipywidgets.Latex(
value='No iterations available')
self.iterations_box = ipywidgets.VBox(
children=[self.mode_index_buttons_box, self.no_iterations_text])
# Create final tab widget
self.result_iterations_tab = ipywidgets.Tab(
children=[self.result_box, self.iterations_box], margin='0.2cm')
self.result_iterations_tab.set_title(0, 'Final')
self.result_iterations_tab.set_title(1, 'Iterations')
self.result_iterations_tab.observe(
self._stop_animation, names='selected_index', type='change')
# Function for updating rendering options
if tab_update_function is not None:
self.result_iterations_tab.observe(tab_update_function,
names='selected_index',
type='change')
self.iterations_mode.observe(tab_update_function, names='value',
type='change')
# Create final widget
children = [self.mode_render_image_box, self.result_iterations_tab]
super(IterativeResultOptionsWidget, self).__init__(
children, Dict, default_options, render_function=render_function,
orientation='horizontal', align='start')
# Visibility
self._index_visibility({'new': 'animation'})
# Set callbacks
self._displacements_function = None
self.add_displacements_function(displacements_function)
self._errors_function = None
self.add_errors_function(errors_function)
self._costs_function = None
self.add_costs_function(costs_function)
# Set values
self.add_callbacks()
self.set_widget_state(has_gt_shape, has_initial_shape, has_image,
n_shapes, has_costs, allow_callback=False)
# Set style
self.predefined_style(style, tabs_style)
def _index_visibility(self, change):
self.index_animation.visible = change['new'] == 'animation'
self.index_slicing.visible = change['new'] == 'static'
def _stop_animation(self, change):
# Make sure that the animation gets stopped when the 'Static'
# radiobutton or 'Final' tab is selected.
if change['new'] in ['static', 0]:
self.index_animation.stop_animation()
[docs] def add_displacements_function(self, displacements_function):
r"""
Method that adds the provided `displacements_function` as a callback
handler to the `click` event of ``self.plot_displacements_button``. The
given function is also stored in ``self._displacements_function``.
Parameters
----------
displacements_function : `callable` or ``None``, optional
The function that behaves as a callback handler of the `click`
event of ``self.plot_displacements_button``. Its signature is
``displacements_function(name)``. If ``None``, then nothing is
added.
"""
self._displacements_function = displacements_function
if self._displacements_function is not None:
self.plot_displacements_button.on_click(displacements_function)
[docs] def remove_displacements_function(self):
r"""
Method that removes the current ``self._displacements_function`` as a
callback handler to the `click` event of
``self.plot_displacements_button`` and sets
``self._displacements_function = None``.
"""
if self._displacements_function is not None:
self.plot_displacements_button.on_click(
self._displacements_function, remove=True)
self._displacements_function = None
[docs] def replace_displacements_function(self, displacements_function):
r"""
Method that replaces the current ``self._displacements_function`` with
the given `displacements_function` as a callback handler to the `click`
event of ``self.plot_displacements_button``.
Parameters
----------
displacements_function : `callable` or ``None``, optional
The function that behaves as a callback handler of the `click`
event of ``self.plot_displacements_button``. Its signature is
``displacements_function(name)``. If ``None``, then nothing is
added.
"""
# remove old function
self.remove_displacements_function()
# add new function
self.add_displacements_function(displacements_function)
[docs] def add_errors_function(self, errors_function):
r"""
Method that adds the provided `errors_function` as a callback handler
to the `click` event of ``self.plot_errors_button``. The given
function is also stored in ``self._errors_function``.
Parameters
----------
errors_function : `callable` or ``None``, optional
The function that behaves as a callback handler of the `click`
event of ``self.plot_errors_button``. Its signature is
``errors_function(name)``. If ``None``, then nothing is added.
"""
self._errors_function = errors_function
if self._errors_function is not None:
self.plot_errors_button.on_click(errors_function)
[docs] def remove_errors_function(self):
r"""
Method that removes the current ``self._errors_function`` as a
callback handler to the `click` event of ``self.plot_errors_button``
and sets ``self._errors_function = None``.
"""
if self._errors_function is not None:
self.plot_errors_button.on_click(self._errors_function, remove=True)
self._errors_function = None
[docs] def replace_errors_function(self, errors_function):
r"""
Method that replaces the current ``self._errors_function`` with
the given `errors_function` as a callback handler to the `click`
event of ``self.plot_errors_button``.
Parameters
----------
errors_function : `callable` or ``None``, optional
The function that behaves as a callback handler of the `click`
event of ``self.plot_errors_button``. Its signature is
``errors_function(name)``. If ``None``, then nothing is added.
"""
# remove old function
self.remove_errors_function()
# add new function
self.add_errors_function(errors_function)
[docs] def add_costs_function(self, costs_function):
r"""
Method that adds the provided `costs_function` as a callback handler
to the `click` event of ``self.plot_costs_button``. The given
function is also stored in ``self._costs_function``.
Parameters
----------
costs_function : `callable` or ``None``, optional
The function that behaves as a callback handler of the `click`
event of ``self.plot_costs_button``. Its signature is
``costs_function(name)``. If ``None``, then nothing is added.
"""
self._costs_function = costs_function
if self._costs_function is not None:
self.plot_costs_button.on_click(costs_function)
[docs] def remove_costs_function(self):
r"""
Method that removes the current ``self._costs_function`` as a callback
handler to the `click` event of ``self.plot_costs_button`` and sets
``self._costs_function = None``.
"""
if self._costs_function is not None:
self.plot_costs_button.on_click(self._costs_function, remove=True)
self._costs_function = None
[docs] def replace_costs_function(self, costs_function):
r"""
Method that replaces the current ``self._costs_function`` with the
given `costs_function` as a callback handler to the `click` event of
``self.plot_costs_button``.
Parameters
----------
costs_function : `callable` or ``None``, optional
The function that behaves as a callback handler of the `click`
event of ``self.plot_costs_button``. Its signature is
``costs_function(name)``. If ``None``, then nothing is added.
"""
# remove old function
self.remove_costs_function()
# add new function
self.add_costs_function(costs_function)
def _save_options(self, change):
if (self.result_iterations_tab.selected_index == 0 or
self.n_shapes is None):
# Result tab
self.selected_values = {
'render_final_shape': self.shape_buttons[2].value,
'render_initial_shape': (self.shape_buttons[1].value and
self.has_initial_shape),
'render_gt_shape': (self.shape_buttons[3].value and
self.has_gt_shape),
'render_image': self.render_image.value and self.has_image,
'subplots_enabled': self.mode.value}
else:
# Iterations tab
if self.iterations_mode.value == 'animation':
# The mode is 'Animation'
iters = self.index_animation.selected_values
else:
# The mode is 'Static'
iters = self.index_slicing.selected_values
# Get selected values
self.selected_values = {
'iters': iters,
'render_image': self.render_image.value and self.has_image,
'subplots_enabled': self.mode.value}
[docs] def add_callbacks(self):
r"""
Function that adds the handler callback functions in all the widget
components, which are necessary for the internal functionality.
"""
self.render_image.observe(self._save_options, names='value',
type='change')
self.mode.observe(self._save_options, names='value', type='change')
for w in self.result_box.children[1::]:
w.observe(self._save_options, names='value', type='change')
self.index_animation.observe(self._save_options,
names='selected_values', type='change')
self.index_slicing.observe(self._save_options,
names='selected_values', type='change')
self.iterations_mode.observe(self._save_options, names='value',
type='change')
self.result_iterations_tab.observe(
self._save_options, names='selected_index', type='change')
[docs] def remove_callbacks(self):
r"""
Function that removes all the internal handler callback functions.
"""
self.render_image.unobserve(self._save_options, names='value',
type='change')
self.mode.unobserve(self._save_options, names='value', type='change')
for w in self.result_box.children[1::]:
w.unobserve(self._save_options, names='value', type='change')
self.index_animation.unobserve(self._save_options,
names='selected_values', type='change')
self.index_slicing.unobserve(self._save_options,
names='selected_values', type='change')
self.iterations_mode.unobserve(self._save_options, names='value',
type='change')
self.result_iterations_tab.unobserve(
self._save_options, names='selected_index', type='change')
[docs] def set_visibility(self):
r"""
Function that sets the visibility of the various components of the
widget, depending on the properties of the current image object, i.e.
``self.n_channels`` and ``self.image_is_masked``.
"""
self.result_box.children[1].visible = self.has_initial_shape
self.result_box.children[3].visible = self.has_gt_shape
self.render_image.visible = self.has_image
self.plot_errors_button.visible = (self.has_gt_shape and
self._errors_function is not None)
self.mode_index_buttons_box.visible = self.n_shapes is not None
self.no_iterations_text.visible = self.n_shapes is None
[docs] def style(self, box_style=None, border_visible=False, border_colour='black',
border_style='solid', border_width=1, border_radius=0, padding=0,
margin=0, font_family='', font_size=None, font_style='',
font_weight='', buttons_style='', tabs_box_style=None,
tabs_border_visible=False, tabs_border_colour='black',
tabs_border_style='solid', tabs_border_width=1,
tabs_border_radius=0):
r"""
Function that defines the styling of the widget.
Parameters
----------
box_style : `str` or ``None`` (see below), optional
Possible widget style options::
'success', 'info', 'warning', 'danger', '', None
border_visible : `bool`, optional
Defines whether to draw the border line around the widget.
border_colour : `str`, optional
The colour of the border around the widget.
border_style : `str`, optional
The line style of the border around the widget.
border_width : `float`, optional
The line width of the border around the widget.
border_radius : `float`, optional
The radius of the border around the widget.
padding : `float`, optional
The padding around the widget.
margin : `float`, optional
The margin around the widget.
font_family : `str` (see below), optional
The font family to be used. Example options::
'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace',
'helvetica'
font_size : `int`, optional
The font size.
font_style : `str` (see below), optional
The font style. Example options::
'normal', 'italic', 'oblique'
font_weight : See Below, optional
The font weight. Example options::
'ultralight', 'light', 'normal', 'regular', 'book', 'medium',
'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy',
'extra bold', 'black'
buttons_style : `str` or ``None`` (see below), optional
Style options:
'success', 'info', 'warning', 'danger', 'primary', '', None
tabs_box_style : `str` or ``None`` (see below), optional
Possible tab widgets style options::
'success', 'info', 'warning', 'danger', '', None
tabs_border_visible : `bool`, optional
Defines whether to draw the border line around the tab widgets.
tabs_border_colour : `str`, optional
The colour of the border around the tab widgets.
tabs_border_style : `str`, optional
The line style of the border around the tab widgets.
tabs_border_width : `float`, optional
The line width of the border around the tab widgets.
tabs_border_radius : `float`, optional
The radius of the border around the tab widgets.
"""
format_box(self, box_style, border_visible, border_colour, border_style,
border_width, border_radius, padding, margin)
format_font(self, font_family, font_size, font_style, font_weight)
format_font(self.render_image, font_family, font_size, font_style,
font_weight)
format_font(self.mode, font_family, font_size, font_style, font_weight)
format_font(self.result_box.children[0], font_family, font_size,
font_style, font_weight)
for w in self.result_box.children[1::]:
format_font(w, font_family, font_size, font_style, font_weight)
w.button_style = buttons_style
format_font(self.iterations_mode, font_family, font_size, font_style,
font_weight)
self.index_animation.predefined_style(tabs_box_style)
tmp_box_style = tabs_box_style
if tabs_box_style == 'minimal':
tmp_box_style = ''
self.index_animation.style(
box_style=tmp_box_style, border_visible=False, padding=0,
margin=0, font_family=font_family, font_size=font_size,
font_style=font_style, font_weight=font_weight)
self.index_slicing.style(
box_style=tmp_box_style, border_visible=False, padding=0,
margin=0, font_family=font_family, font_size=font_size,
font_style=font_style, font_weight=font_weight)
self.plot_errors_button.button_style = buttons_style
self.plot_displacements_button.button_style = buttons_style
self.plot_costs_button.button_style = buttons_style
format_box(self.result_box, box_style=tmp_box_style,
border_visible=tabs_border_visible,
border_colour=tabs_border_colour,
border_style=tabs_border_style,
border_width=tabs_border_width,
border_radius=tabs_border_radius, padding='0.2cm',
margin='0.2cm')
format_box(self.iterations_box, box_style=tmp_box_style,
border_visible=tabs_border_visible,
border_colour=tabs_border_colour,
border_style=tabs_border_style,
border_width=tabs_border_width,
border_radius=tabs_border_radius, padding='0.2cm',
margin='0.2cm')
[docs] def predefined_style(self, style, tabs_style):
r"""
Function that sets a predefined style on the widget.
Parameters
----------
style : `str` (see below)
Style options:
============= ============================
Style Description
============= ============================
``'minimal'`` Simple black and white style
``'success'`` Green-based style
``'info'`` Blue-based style
``'warning'`` Yellow-based style
``'danger'`` Red-based style
``''`` No style
============= ============================
tabs_style : `str` (see below)
Tabs style options:
============= ============================
Style Description
============= ============================
``'minimal'`` Simple black and white style
``'success'`` Green-based style
``'info'`` Blue-based style
``'warning'`` Yellow-based style
``'danger'`` Red-based style
``''`` No style
============= ============================
"""
if style == 'minimal':
self.style(box_style=None, border_visible=True,
border_colour='black', border_style='solid',
border_width=1, border_radius=0, padding='0.2cm',
margin='0.3cm', font_family='', font_size=None,
font_style='', font_weight='', buttons_style='',
tabs_box_style=None, tabs_border_visible=True)
elif (style == 'info' or style == 'success' or style == 'danger' or
style == 'warning'):
self.style(box_style=style, border_visible=True,
border_colour=map_styles_to_hex_colours(style),
border_style='solid', border_width=1, border_radius=10,
padding='0.2cm', margin='0.3cm', font_family='',
font_size=None, font_style='', font_weight='',
buttons_style='primary', tabs_box_style=tabs_style,
tabs_border_visible=True,
tabs_border_colour=map_styles_to_hex_colours(tabs_style),
tabs_border_style='solid', tabs_border_width=1,
tabs_border_radius=10)
else:
raise ValueError('style must be minimal or info or success or '
'danger or warning')
[docs] def set_widget_state(self, has_gt_shape, has_initial_shape, has_image,
n_shapes, has_costs, allow_callback=True):
r"""
Method that updates the state of the widget with a new set of values.
Parameters
----------
has_gt_shape : `bool`
Whether the fitting result object has the ground truth shape.
has_initial_shape : `bool`
Whether the fitting result object has the initial shape.
has_image : `bool`
Whether the fitting result object has the image.
n_shapes : `int` or ``None``
The total number of shapes. If ``None``, then it is assumed
that no iteration shapes are available.
has_costs : `bool`
Whether the fitting result object has the costs attached.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
# keep old value
old_value = self.selected_values
# check if updates are required
if (self.has_gt_shape != has_gt_shape or
self.has_initial_shape != has_initial_shape or
self.has_image != has_image or
self.n_shapes != n_shapes):
# temporarily remove callbacks
render_function = self._render_function
self.remove_render_function()
self.remove_callbacks()
# Update widgets
if self.n_shapes != n_shapes and n_shapes is not None:
index = {'min': 0, 'max': n_shapes - 1, 'step': 1, 'index': 0}
self.index_animation.set_widget_state(index,
allow_callback=False)
slice_options = {'command': 'range({})'.format(n_shapes),
'length': n_shapes}
self.index_slicing.set_widget_state(slice_options,
allow_callback=False)
# Assign properties
self.has_gt_shape = has_gt_shape
self.has_initial_shape = has_initial_shape
self.has_image = has_image
self.n_shapes = n_shapes
# Set widget's visibility
self.set_visibility()
# Get values
self._save_options({})
# Re-assign callbacks
self.add_callbacks()
self.add_render_function(render_function)
# set costs button visibility
self.plot_costs_button.visible = has_costs
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)