Source code for menpowidgets.tools
from collections import OrderedDict
import ipywidgets
from traitlets.traitlets import List, Int, Float, Dict, Bool, Unicode
from traitlets import link
from PIL import Image as PILImage
from io import BytesIO
import numpy as np
from base64 import b64decode
from menpo.compatibility import unicode
from menpo.image import Image
from .abstract import MenpoWidget
from .style import (map_styles_to_hex_colours, convert_image_to_bytes,
format_box, format_font, format_slider, format_text_box,
parse_font_awesome_icon)
from .utils import (lists_are_the_same, decode_colour, parse_slicing_command,
list_has_constant_step, parse_int_range_command,
parse_float_range_command)
# Global variables to try and reduce overhead of loading the logo
MENPO_MINIMAL_LOGO = None
MENPO_DANGER_LOGO = None
MENPO_WARNING_LOGO = None
MENPO_SUCCESS_LOGO = None
MENPO_INFO_LOGO = None
[docs]class LogoWidget(ipywidgets.FlexBox):
r"""
Creates a widget with Menpo's logo image. The widget stores the image in
``self.image`` using `ipywidgets.Image`. To set the styling of this widget
please refer to the :meth:`style` method.
Parameters
----------
style : ``{'minimal', 'danger', 'info', 'warning', 'success'}``, optional
Defines the styling of the logo widget, i.e. the colour around the
logo image.
"""
def __init__(self, style='minimal'):
from menpowidgets.base import menpowidgets_src_dir_path
import menpo.io as mio
# Try to only load the logo once
global MENPO_LOGO_SCALE
logos_path = menpowidgets_src_dir_path() / 'logos'
if style == 'minimal':
global MENPO_MINIMAL_LOGO
if MENPO_MINIMAL_LOGO is None:
MENPO_MINIMAL_LOGO = mio.import_image(
logos_path / "menpoproject_{}.png".format(style))
self.image = ipywidgets.Image(
value=convert_image_to_bytes(MENPO_MINIMAL_LOGO), width='50px')
elif style == 'danger':
global MENPO_DANGER_LOGO
if MENPO_DANGER_LOGO is None:
MENPO_DANGER_LOGO = mio.import_image(
logos_path / "menpoproject_{}.png".format(style))
self.image = ipywidgets.Image(
value=convert_image_to_bytes(MENPO_DANGER_LOGO), width='50px')
elif style == 'info':
global MENPO_INFO_LOGO
if MENPO_INFO_LOGO is None:
MENPO_INFO_LOGO = mio.import_image(
logos_path / "menpoproject_{}.png".format(style))
self.image = ipywidgets.Image(
value=convert_image_to_bytes(MENPO_INFO_LOGO), width='50px')
elif style == 'warning':
global MENPO_WARNING_LOGO
if MENPO_WARNING_LOGO is None:
MENPO_WARNING_LOGO = mio.import_image(
logos_path / "menpoproject_{}.png".format(style))
self.image = ipywidgets.Image(
value=convert_image_to_bytes(MENPO_WARNING_LOGO), width='50px')
elif style == 'success':
global MENPO_SUCCESS_LOGO
if MENPO_SUCCESS_LOGO is None:
MENPO_SUCCESS_LOGO = mio.import_image(
logos_path / "menpoproject_{}.png".format(style))
self.image = ipywidgets.Image(
value=convert_image_to_bytes(MENPO_SUCCESS_LOGO), width='50px')
else:
raise ValueError("style must be 'minimal', 'info', 'danger', "
"'warning' or 'success'; {} was "
"given.".format(style))
super(LogoWidget, self).__init__(children=[self.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, image_width='50px'):
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.
image_width : `str`, optional
The width of the image object
"""
format_box(self, box_style, border_visible, border_colour, border_style,
border_width, border_radius, padding, margin)
self.image.width = image_width
[docs]class ListWidget(MenpoWidget):
r"""
Creates a widget for selecting a `list` of numbers. It supports both
`int` and `float`.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
selected_list : `list`
The initial list of numbers.
mode : ``{'int', 'float'}``, optional
Defines the data type of the list members.
description : `str`, optional
The description of the command text box.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
example_visible : `bool`, optional
If `True`, then a line with command examples is printed below the
main text box.
"""
def __init__(self, selected_list, mode='float', description='Command:',
render_function=None, example_visible=True):
# Create children
selected_cmd = ''
if mode == 'int':
for i in selected_list:
selected_cmd += '{}, '.format(i)
self.example = ipywidgets.Latex(
value="e.g. '[1, 2]', '10', '10, 20', 'range(10)', "
"'range(1, 8, 2)' etc.",
font_size=11, font_style='italic', visible=example_visible)
elif mode == 'float':
for i in selected_list:
selected_cmd += '{:.1f}, '.format(i)
self.example = ipywidgets.Latex(
value="e.g. '10.', '10., 20.', 'range(10.)', "
"'range(2.5, 5., 2.)' etc.",
font_size=11, font_style='italic', visible=example_visible)
else:
raise ValueError("mode must be either int or float.")
self.cmd_text = ipywidgets.Text(
value=selected_cmd[:-2], description=description)
self.valid = ipywidgets.Valid(value=True)
self.error_msg = ipywidgets.Latex(value='', font_style='italic',
color='#FF0000')
self.cmd_text_example_error = ipywidgets.FlexBox(
children=[self.cmd_text, self.example, self.error_msg],
orientation='vertical', align='end')
# Create final widget
children = [self.cmd_text_example_error, self.valid]
super(ListWidget, self).__init__(
children, List, selected_list, render_function=render_function,
orientation='horizontal', align='start')
# Assign properties
self.mode = mode
# Set functionality
def save_cmd(name):
self.error_msg.value = ''
try:
if self.mode == 'int':
self.selected_values = parse_int_range_command(
str(self.cmd_text.value))
else:
self.selected_values = parse_float_range_command(
str(self.cmd_text.value))
self.valid.value = True
except ValueError as e:
self.valid.value = False
self.error_msg.value = str(e)
self.cmd_text.on_submit(save_cmd)
[docs] def set_widget_state(self, selected_list, allow_callback=True):
r"""
Method that updates the state of the widget if the provided
`selected_list` value is different than `self.selected_values`.
Parameters
----------
selected_list : `list`
The selected list of numbers.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
if not lists_are_the_same(selected_list, self.selected_values):
# Keep old value
old_value = self.selected_values
# Assign new options dict to selected_values
selected_cmd = ''
if self.mode == 'int':
for i in selected_list:
selected_cmd += '{}, '.format(i)
elif self.mode == 'float':
for i in selected_list:
selected_cmd += '{}, '.format(i)
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update command text and selected values
self.cmd_text.value = selected_cmd[:-2]
self.selected_values = selected_list
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[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, text_box_style=None, text_box_background_colour=None,
text_box_width=None, font_family='', font_size=None,
font_style='', font_weight=''):
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.
text_box_style : `str` or ``None`` (see below), optional
Command text box style options::
'success', 'info', 'warning', 'danger', '', None
text_box_background_colour : `str`, optional
The background colour of the command text box.
text_box_width : `str`, optional
The width of the command text box.
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'
"""
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.cmd_text, font_family, font_size, font_style,
font_weight)
self.cmd_text.color = map_styles_to_hex_colours(text_box_style)
self.cmd_text.background_color = map_styles_to_hex_colours(
text_box_background_colour, background=True)
self.cmd_text.border_color = map_styles_to_hex_colours(text_box_style)
self.cmd_text.font_family = 'monospace'
self.cmd_text.border_width = 1
self.cmd_text.width = text_box_width
[docs]class SlicingCommandWidget(MenpoWidget):
r"""
Creates a widget for selecting a slicing command.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
slice_options : `dict`
The initial slicing options. It must be a `dict` with:
* ``command`` : (`str`) The slicing command (e.g. ``':3'``).
* ``length`` : (`int`) The maximum length (e.g. ``68``).
description : `str`, optional
The description of the command text box.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
example_visible : `bool`, optional
If ``True``, then a line with command examples is printed below the
main text box.
continuous_update : `bool`, optional
If ``True``, then the render and update functions are called while
moving the slider's handle. If ``False``, then the the functions are
called only when the handle (mouse click) is released.
orientation : ``{'horizontal', 'vertical'}``, optional
The orientation between the command text box and the sliders.
"""
def __init__(self, slice_options, description='Command:',
render_function=None, example_visible=True,
continuous_update=False, orientation='horizontal'):
# Create children
indices = parse_slicing_command(slice_options['command'],
slice_options['length'])
self.cmd_text = ipywidgets.Text(value=slice_options['command'],
description=description)
self.example = ipywidgets.Latex(
value=self._example_str(slice_options['length']),
font_size=11, font_style='italic', visible=example_visible)
self.error_msg = ipywidgets.Latex(value='', font_style='italic',
color='#FF0000')
self.single_slider = ipywidgets.IntSlider(
min=0, max=slice_options['length'] - 1, value=0, width='6.8cm',
visible=self._single_slider_visible(indices),
continuous_update=continuous_update)
self.multiple_slider = ipywidgets.IntRangeSlider(
min=0, max=slice_options['length'] - 1,
value=(indices[0], indices[-1]),
width='6.8cm',
visible=self._multiple_slider_visible(indices)[0],
continuous_update=continuous_update)
self.valid = ipywidgets.Valid(value=True)
self.cmd_text_example_error = ipywidgets.FlexBox(
children=[self.cmd_text, self.example, self.error_msg],
orientation='vertical', align='end')
self.command_error_box = ipywidgets.HBox(
children=[self.cmd_text_example_error, self.valid], margin='0.1cm')
self.sliders_box = ipywidgets.VBox(
children=[self.single_slider, self.multiple_slider], align='start',
margin='0.1cm')
# Create final widget
children = [self.command_error_box, self.sliders_box]
align = 'end'
if orientation == 'horizontal':
align = 'start'
super(SlicingCommandWidget, self).__init__(
children, List, indices, render_function=render_function,
orientation=orientation, align=align)
# Assign properties
self.length = slice_options['length']
# Set functionality
def save_cmd(name):
self.error_msg.value = ''
try:
self.selected_values = parse_slicing_command(
str(self.cmd_text.value), self.length)
self.valid.value = True
except ValueError as e:
self.valid.value = False
self.error_msg.value = str(e)
# set single slider visibility and value
vis = self._single_slider_visible(self.selected_values)
self.single_slider.visible = vis
if vis:
self.single_slider.value = self.selected_values[0]
# set multiple slider visibility and value
vis, step = self._multiple_slider_visible(self.selected_values)
self.multiple_slider.visible = vis
if vis:
self.multiple_slider.step = step
self.multiple_slider.value = (self.selected_values[0],
self.selected_values[-1])
self.cmd_text.on_submit(save_cmd)
def single_slider_value(change):
value = change['new']
self.selected_values = [value]
self.cmd_text.value = str(value)
self.single_slider.observe(single_slider_value, names='value',
type='change')
def multiple_slider_value(change):
value = change['new']
self.selected_values = list(range(value[0], value[1]+1,
self.multiple_slider.step))
self.cmd_text.value = "{}:{}:{}".format(value[0], value[1]+1,
self.multiple_slider.step)
self.multiple_slider.observe(multiple_slider_value, names='value',
type='change')
def _example_str(self, length):
return "e.g. ':3', '-3:', '1:{}:2', '3::', '0, {}', '7', 'range({})' " \
"etc.".format(length, length, length)
def _single_slider_visible(self, selected_values):
return len(selected_values) == 1
def _multiple_slider_visible(self, selected_values):
return list_has_constant_step(selected_values)
[docs] def set_widget_state(self, slice_options, allow_callback=True):
r"""
Method that updates the state of the widget if the provided
`slice_options` value is different than `self.selected_values`.
Parameters
----------
slice_options : `dict`
The new slicing options. It must be a `dict` with:
* ``command`` : (`str`) The slicing command (e.g. ``':3'``).
* ``length`` : (`int`) The maximum length (e.g. ``68``).
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
# Assign new options dict to selected_values
self.length = slice_options['length']
# decode command
indices = parse_slicing_command(slice_options['command'],
slice_options['length'])
if not lists_are_the_same(indices, self.selected_values):
# Keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update selected values
self.selected_values = indices
# update single slider
vis = self._single_slider_visible(self.selected_values)
self.single_slider.visible = vis
self.single_slider.max = self.length - 1
if vis:
self.single_slider.value = self.selected_values[0]
# update multiple slider
vis, step = self._multiple_slider_visible(self.selected_values)
self.multiple_slider.visible = vis
self.multiple_slider.max = self.length - 1
if vis:
self.multiple_slider.step = step
self.multiple_slider.value = (self.selected_values[0],
self.selected_values[-1])
# update command text
self.cmd_text.value = slice_options['command']
# Update example str
self.example.value = self._example_str(slice_options['length'])
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[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, text_box_style=None, text_box_background_colour=None,
text_box_width=None, font_family='', font_size=None,
font_style='', font_weight=''):
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.
text_box_style : `str` or ``None`` (see below), optional
Command text box style options::
'success', 'info', 'warning', 'danger', '', None
text_box_background_colour : `str`, optional
The background colour of the command text box.
text_box_width : `str`, optional
The width of the command text box.
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'
"""
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.cmd_text, font_family, font_size, font_style,
font_weight)
self.cmd_text.color = map_styles_to_hex_colours(text_box_style)
self.cmd_text.background_color = map_styles_to_hex_colours(
text_box_background_colour, background=True)
self.cmd_text.border_color = map_styles_to_hex_colours(text_box_style)
self.cmd_text.font_family = 'monospace'
self.cmd_text.border_width = 1
self.cmd_text.width = text_box_width
self.single_slider.slider_color = map_styles_to_hex_colours(
box_style, background=False)
self.single_slider.background_color = map_styles_to_hex_colours(
box_style, background=False)
self.multiple_slider.slider_color = map_styles_to_hex_colours(
box_style, background=False)
self.multiple_slider.background_color = map_styles_to_hex_colours(
box_style, background=False)
[docs]class IndexSliderWidget(MenpoWidget):
r"""
Creates a widget for selecting an index using a slider.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
index : `dict`
The `dict` with the default options:
* ``min`` : (`int`) The minimum value (e.g. ``0``).
* ``max`` : (`int`) The maximum value (e.g. ``100``).
* ``step`` : (`int`) The index step (e.g. ``1``).
* ``index`` : (`int`) The index value (e.g. ``10``).
description : `str`, optional
The title of the widget.
continuous_update : `bool`, optional
If ``True``, then the render and update functions are called while moving
the slider's handle. If ``False``, then the the functions are called only
when the handle (mouse click) is released.
render_function : `callable` or ``None``, optional
The render function that is executed when the index value changes.
If ``None``, then nothing is assigned.
"""
def __init__(self, index, description='Index: ', continuous_update=False,
render_function=None):
# Create children
self.slider = ipywidgets.IntSlider(
min=index['min'], max=index['max'], value=index['index'],
step=index['step'], description=description, width='5cm',
continuous_update=continuous_update)
# Create final widget
children = [self.slider]
super(IndexSliderWidget, self).__init__(
children, Int, index['index'], render_function=render_function,
orientation='vertical', align='start')
# Set functionality
def save_index(change):
self.selected_values = change['new']
self.slider.observe(save_index, names='value', type='change')
[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='', slider_width='6cm', slider_bar_colour=None,
slider_handle_colour=None, slider_text_visible=True):
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'
slider_width : `float`, optional
The width of the slider
slider_bar_colour : `str`, optional
The colour of the slider's bar.
slider_handle_colour : `str`, optional
The colour of the slider's handle.
slider_text_visible : `bool`, optional
Whether the selected value of the slider is visible.
"""
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_slider(self.slider, slider_width=slider_width,
slider_handle_colour=slider_handle_colour,
slider_bar_colour=slider_bar_colour,
slider_text_visible=slider_text_visible)
[docs] def set_widget_state(self, index, allow_callback=True):
r"""
Method that updates the state of the widget, if the provided `index`
values are different than `self.selected_values`.
Parameters
----------
index : `dict`
The `dict` with the selected options:
* ``min`` : (`int`) The minimum value (e.g. ``0``).
* ``max`` : (`int`) The maximum value (e.g. ``100``).
* ``step`` : (`int`) The index step (e.g. ``1``).
* ``index`` : (`int`) The index value (e.g. ``10``).
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
# Check if update is required
if (index['index'] != self.selected_values or
index['min'] != self.slider.min or
index['max'] != self.slider.max or
index['step'] != self.slider.step):
# Keep old value
old_value = self.selected_values
# temporarily remove render function
render_function = self._render_function
self.remove_render_function()
# set values to slider
self.slider.min = index['min']
self.slider.max = index['max']
self.slider.step = index['step']
self.slider.value = index['index']
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, index['index'])
[docs]class IndexButtonsWidget(MenpoWidget):
r"""
Creates a widget for selecting an index using plus/minus buttons.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
index : `dict`
The `dict` with the default options:
* ``min`` : (`int`) The minimum value (e.g. ``0``).
* ``max`` : (`int`) The maximum value (e.g. ``100``).
* ``step`` : (`int`) The index step (e.g. ``1``).
* ``index`` : (`int`) The index value (e.g. ``10``).
render_function : `callable` or ``None``, optional
The render function that is executed when the index value changes.
If ``None``, then nothing is assigned.
description : `str`, optional
The title of the widget.
minus_description : `str`, optional
The text/icon of the button that decreases the index. If the `str`
starts with `'fa-'`, then a font-awesome icon is defined.
plus_description : `str`, optional
The title of the button that increases the index. If the `str` starts
with `'fa-'`, then a font-awesome icon is defined.
loop_enabled : `bool`, optional
If ``True``, then if by pressing the buttons we reach the minimum
(maximum) index values, then the counting will continue from the end
(beginning). If ``False``, the counting will stop at the minimum
(maximum) value.
text_editable : `bool`, optional
Flag that determines whether the index text will be editable.
"""
def __init__(self, index, render_function=None, description='Index: ',
minus_description='fa-minus', plus_description='fa-plus',
loop_enabled=True, text_editable=True):
# Create children
self.title = ipywidgets.Latex(value=description, padding=6, margin=6)
m_icon, m_description = parse_font_awesome_icon(minus_description)
self.button_minus = ipywidgets.Button(
description=m_description, icon=m_icon, width='1cm',
tooltip='Previous item')
p_icon, p_description = parse_font_awesome_icon(plus_description)
self.button_plus = ipywidgets.Button(
description=p_description, icon=p_icon, width='1cm',
tooltip='Next item')
self.index_text = ipywidgets.BoundedIntText(
value=index['index'], min=index['min'], max=index['max'],
disabled=not text_editable)
# Create final widget
children = [self.title, self.button_minus, self.index_text,
self.button_plus]
super(IndexButtonsWidget, self).__init__(
children, Int, index['index'], render_function=render_function,
orientation='horizontal', align='start')
# Assign properties
self.min = index['min']
self.max = index['max']
self.step = index['step']
self.loop_enabled = loop_enabled
self.text_editable = text_editable
# Set functionality
def value_plus(name):
tmp_val = int(self.index_text.value) + self.step
if tmp_val > self.max:
if self.loop_enabled:
self.index_text.value = str(self.min)
else:
self.index_text.value = str(self.max)
else:
self.index_text.value = str(tmp_val)
self.button_plus.on_click(value_plus)
def value_minus(name):
tmp_val = int(self.index_text.value) - self.step
if tmp_val < self.min:
if self.loop_enabled:
self.index_text.value = str(self.max)
else:
self.index_text.value = str(self.min)
else:
self.index_text.value = str(tmp_val)
self.button_minus.on_click(value_minus)
def save_index(change):
self.selected_values = int(change['new'])
self.index_text.observe(save_index, names='value', type='change')
[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='', minus_style='', plus_style='',
text_colour=None, text_background_colour=None):
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'
minus_style : `str` or ``None`` (see below), optional
Style options ::
'success', 'info', 'warning', 'danger', 'primary', '', None
plus_style : `str` or ``None`` (see below), optional
Style options ::
'success', 'info', 'warning', 'danger', 'primary', '', None
text_colour : `str`, optional
The text colour of the index text.
text_background_colour : `str`, optional
The background colour of the index text.
"""
format_box(self, box_style, border_visible, border_colour, border_style,
border_width, border_radius, padding, margin)
format_font(self.title, font_family, font_size, font_style,
font_weight)
format_font(self.button_minus, font_family, font_size, font_style,
font_weight)
format_font(self.button_plus, font_family, font_size, font_style,
font_weight)
format_font(self.index_text, font_family, font_size, font_style,
font_weight)
self.button_minus.button_style = minus_style
self.button_plus.button_style = plus_style
format_text_box(self.index_text, text_colour, text_background_colour)
[docs] def set_widget_state(self, index, loop_enabled, text_editable,
allow_callback=True):
r"""
Method that updates the state of the widget, if the provided `index`
value is different than `self.selected_values`.
Parameters
----------
index : `dict`
The `dict` with the selected options:
* ``min`` : (`int`) The minimum value (e.g. ``0``).
* ``max`` : (`int`) The maximum value (e.g. ``100``).
* ``step`` : (`int`) The index step (e.g. ``1``).
* ``index`` : (`int`) The index value (e.g. ``10``).
loop_enabled : `bool`, optional
If ``True``, then if by pressing the buttons we reach the minimum
(maximum) index values, then the counting will continue from the end
(beginning). If ``False``, the counting will stop at the minimum
(maximum) value.
text_editable : `bool`, optional
Flag that determines whether the index text will be editable.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
# Update loop_enabled and text_editable
self.loop_enabled = loop_enabled
self.text_editable = text_editable
self.index_text.disabled = not text_editable
# Check if update is required
if (index['index'] != self.selected_values or
index['min'] != self.min or index['max'] != self.max or
index['step'] != self.step):
# Keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# set value to index text
self.min = index['min']
self.max = index['max']
self.step = index['step']
self.index_text.min = index['min']
self.index_text.max = index['max']
self.index_text.value = str(index['index'])
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, index['index'])
[docs]class ColourSelectionWidget(MenpoWidget):
r"""
Creates a widget for colour selection of a single or multiple objects.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
colours_list : `list` of `str` or [`float`, `float`, `float`]
A `list` of colours. If a colour is defined as an `str`, then it must
either be a hex code or a colour name, such as ::
'blue', 'green', 'red', 'cyan', 'magenta', 'yellow', 'black',
'white', 'pink', 'orange'
If a colour has the form [`float`, `float`, `float`], then it defines an
RGB value and must have length 3.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
description : `str`, optional
The description of the widget.
labels : `list` of `str` or ``None``, optional
A `list` with the labels' names. If ``None``, then a `list` of the form
``label {}`` is automatically defined.
"""
def __init__(self, colours_list, render_function=None, description='Colour',
labels=None):
# Check if multiple mode should be enabled
if isinstance(colours_list, str) or isinstance(colours_list, unicode):
colours_list = [colours_list]
n_labels = len(colours_list)
multiple = n_labels > 1
# Decode the colour of the first label
default_colour = decode_colour(colours_list[0])
# Create children
labels_dict = OrderedDict()
if labels is None:
labels = []
for k in range(n_labels):
labels_dict["label {}".format(k)] = k
labels.append("label {}".format(k))
else:
for k, l in enumerate(labels):
labels_dict[l] = k
self.label_dropdown = ipywidgets.Dropdown(description=description,
options=labels_dict, value=0)
self.apply_to_all_button = ipywidgets.Button(
description=' Apply to all', icon='fa-paint-brush')
self.labels_box = ipywidgets.VBox(
children=[self.label_dropdown, self.apply_to_all_button],
visible=multiple, align='end')
colour_description = ''
if not multiple:
colour_description = description
self.colour_widget = ipywidgets.ColorPicker(
value=default_colour, description=colour_description, width='3cm',
tooltip='Select colour')
# Create final widget
children = [self.labels_box, self.colour_widget]
super(ColourSelectionWidget, self).__init__(
children, List, colours_list, render_function=render_function,
orientation='horizontal', align='start')
# Assign properties
self.labels = labels
self.n_colours = n_labels
self.description = description
# Set functionality
def apply_to_all_function(name):
tmp = str(self.colour_widget.value)
self.selected_values = [tmp] * len(self.selected_values)
self.label_dropdown.value = 0
self.apply_to_all_button.on_click(apply_to_all_function)
def update_colour_wrt_label(change):
value = change['new']
self.colour_widget.value = decode_colour(
self.selected_values[value])
self.label_dropdown.observe(update_colour_wrt_label, names='value',
type='change')
def save_colour(change):
idx = self.label_dropdown.value
tmp = [v for v in self.selected_values]
tmp[idx] = str(self.colour_widget.value)
self.selected_values = tmp
self.colour_widget.observe(save_colour, names='value', type='change')
[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='', label_colour=None, label_background_colour=None,
picker_colour=None, picker_background_colour=None,
apply_to_all_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'
label_colour : `str`, optional
The text colour of the labels dropdown selection.
label_background_colour : `str`, optional
The background colour of the labels dropdown selection.
picker_colour : `str`, optional
The text colour of the colour picker.
picker_background_colour : `str`, optional
The background colour of the colour picker.
apply_to_all_style : `str`,
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.label_dropdown, font_family, font_size, font_style,
font_weight)
format_font(self.apply_to_all_button, font_family, font_size,
font_style, font_weight)
format_font(self.colour_widget, font_family, font_size, font_style,
font_weight)
format_text_box(self.label_dropdown, label_colour,
label_background_colour)
format_text_box(self.colour_widget, picker_colour,
picker_background_colour)
self.apply_to_all_button.button_style = apply_to_all_style
[docs] def set_widget_state(self, colours_list, labels=None, allow_callback=True):
r"""
Method that updates the state of the widget, if the provided
`colours_list` and `labels` values are different than
`self.selected_values` and `self.labels` respectively.
Parameters
----------
colours_list : `list` of `str` or [`float`, `float`, `float`]
A `list` of colours. If a colour is defined as an `str`, then it must
either be a hex code or a colour name, such as ::
'blue', 'green', 'red', 'cyan', 'magenta', 'yellow', 'black',
'white', 'pink', 'orange'
If a colour has the form [`float`, `float`, `float`], then it defines
an RGB value and must have length 3.
labels : `list` of `str` or ``None``, optional
A `list` with the labels' names. If ``None``, then a `list` of the
form ``label {}`` is automatically defined.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
if isinstance(colours_list, str) or isinstance(colours_list, unicode):
colours_list = [colours_list]
if labels is None:
labels = ["label {}".format(k) for k in range(len(colours_list))]
self.n_colours = len(colours_list)
sel_colours = self.selected_values
sel_labels = self.labels
if (lists_are_the_same(sel_colours, colours_list) and
not lists_are_the_same(sel_labels, labels)):
# the provided colours are the same, but the labels changed, so
# update the labels
self.labels = labels
labels_dict = OrderedDict()
for k, l in enumerate(labels):
labels_dict[l] = k
self.label_dropdown.options = labels_dict
if len(labels) > 1:
if self.label_dropdown.value > 0:
self.label_dropdown.value = 0
else:
self.label_dropdown.value = 1
self.label_dropdown.value = 0
elif (not lists_are_the_same(sel_colours, colours_list) and
lists_are_the_same(sel_labels, labels)):
# the provided labels are the same, but the colours are different
# keep old value
old_value = self.selected_values
# temporarily remove render_function from r, g, b traits
render_function = self._render_function
self.remove_render_function()
# assign colour
self.selected_values = colours_list
k = self.label_dropdown.value
self.colour_widget.value = decode_colour(colours_list[k])
# re-assign render_function
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
elif (not lists_are_the_same(sel_colours, colours_list) and
not lists_are_the_same(sel_labels, labels)):
# keep old value
old_value = self.selected_values
# temporarily remove render_function from r, g, b traits
render_function = self._render_function
self.remove_render_function()
# both the colours and the labels are different
self.labels_box.visible = len(labels) > 1
if len(labels) > 1:
self.colour_widget.description = ''
else:
self.colour_widget.description = self.description
self.selected_values = colours_list
self.labels = labels
labels_dict = OrderedDict()
for k, l in enumerate(labels):
labels_dict[l] = k
self.label_dropdown.options = labels_dict
if len(labels) > 1:
if self.label_dropdown.value > 0:
self.label_dropdown.value = 0
else:
self.label_dropdown.value = 1
self.label_dropdown.value = 0
else:
self.label_dropdown.value = 0
# update colour widgets
self.colour_widget.value = decode_colour(colours_list[0])
# re-assign render_function
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs] def set_colours(self, colours_list, allow_callback=True):
r"""
Method that updates the colour values of the widget.
Parameters
----------
colours_list : `list` of `str` or [`float`, `float`, `float`]
A `list` of colours. If a colour is defined as an `str`, then it must
either be a hex code or a colour name, such as ::
'blue', 'green', 'red', 'cyan', 'magenta', 'yellow', 'black',
'white', 'pink', 'orange'
If a colour has the form [`float`, `float`, `float`], then it defines
an RGB value and must have length 3.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
Raises
------
ValueError
You must provide a colour per label.
"""
# Check provided colours
if isinstance(colours_list, str) or isinstance(colours_list, unicode):
colours_list = [colours_list]
if len(colours_list) != self.n_colours:
raise ValueError("You must provide a colour per label.")
# Keep old value
old_value = self.selected_values
# Remove render function
render_fun = self._render_function
self.remove_render_function()
# Keep previously selected label
previous_value = self.label_dropdown.value
for k, c in enumerate(colours_list):
self.label_dropdown.value = k
self.colour_widget.value = c
# Select previous label
self.label_dropdown.value = previous_value
# Add render function
self.add_render_function(render_fun)
# Callback
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class ZoomOneScaleWidget(MenpoWidget):
r"""
Creates a widget for selecting zoom options with a single scale.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
zoom_options : `dict`
The `dict` with the default options. It must have the following keys:
* ``min`` : (`float`) The minimum value (e.g. ``0.1``).
* ``max`` : (`float`) The maximum value (e.g. ``4.``).
* ``step`` : (`float`) The zoom step (e.g. ``0.05``).
* ``zoom`` : (`float`) The zoom value (e.g. ``1.``).
render_function : `callable` or ``None``, optional
The render function that is executed when the index value changes.
If ``None``, then nothing is assigned.
description : `str`, optional
The title of the widget.
minus_description : `str`, optional
The text/icon of the button that zooms_out. If the `str` starts with
`'fa-'`, then a font-awesome icon is defined.
plus_description : `str`, optional
The title of the button that zooms in. If the `str` starts with
`'fa-'`, then a font-awesome icon is defined.
continuous_update : `bool`, optional
If ``True``, then the render and update functions are called while
moving the zoom slider's handle. If ``False``, then the the functions
are called only when the handle (mouse click) is released.
"""
def __init__(self, zoom_options, render_function=None,
description='Figure scale: ',
minus_description='fa-search-minus',
plus_description='fa-search-plus', continuous_update=False):
# Create children
self.title = ipywidgets.Latex(value=description, padding=6, margin=6)
m_icon, m_description = parse_font_awesome_icon(minus_description)
self.button_minus = ipywidgets.Button(
description=m_description, icon=m_icon, width='1cm',
tooltip='Zoom Out')
p_icon, p_description = parse_font_awesome_icon(plus_description)
self.button_plus = ipywidgets.Button(
description=p_description, icon=p_icon, width='1cm',
tooltip='Zoom In')
self.zoom_slider = ipywidgets.FloatSlider(
value=zoom_options['zoom'], min=zoom_options['min'],
max=zoom_options['max'], step=zoom_options['step'], readout=False,
width='6cm', continuous_update=continuous_update)
self.zoom_text = ipywidgets.BoundedFloatText(
value=zoom_options['zoom'], min=zoom_options['min'],
max=zoom_options['max'], width='1.5cm')
# Create final widget
children = [self.title, self.button_minus, self.zoom_slider,
self.button_plus, self.zoom_text]
super(ZoomOneScaleWidget, self).__init__(
children, Float, zoom_options['zoom'],
render_function=render_function, orientation='horizontal',
align='start')
# Link the zoom text and slider
link((self.zoom_slider, 'value'), (self.zoom_text, 'value'))
# Set functionality
def value_plus(name):
tmp_val = float(self.zoom_text.value) + self.zoom_slider.step
if tmp_val > self.zoom_slider.max:
self.zoom_text.value = "{:.2f}".format(self.zoom_slider.max)
else:
self.zoom_text.value = "{:.2f}".format(tmp_val)
self.button_plus.on_click(value_plus)
def value_minus(name):
tmp_val = float(self.zoom_text.value) - self.zoom_slider.step
if tmp_val < self.zoom_slider.min:
self.zoom_text.value = "{:.2f}".format(self.zoom_slider.min)
else:
self.zoom_text.value = "{:.2f}".format(tmp_val)
self.button_minus.on_click(value_minus)
def save_zoom_slider(change):
self.selected_values = change['new']
self.zoom_slider.observe(save_zoom_slider, names='value', type='change')
[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='', slider_width='6cm'):
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'
slider_width : `float`, optional
The width of the slider
"""
format_box(self, box_style, border_visible, border_colour, border_style,
border_width, border_radius, padding, margin)
format_font(self.title, font_family, font_size, font_style,
font_weight)
format_font(self.button_minus, font_family, font_size, font_style,
font_weight)
format_font(self.button_plus, font_family, font_size, font_style,
font_weight)
format_font(self.zoom_text, font_family, font_size, font_style,
font_weight)
if box_style not in ['', None]:
self.button_minus.button_style = 'primary'
self.button_plus.button_style = 'primary'
else:
self.button_minus.button_style = None
self.button_plus.button_style = None
format_slider(self.zoom_slider, slider_width=slider_width,
slider_handle_colour=map_styles_to_hex_colours(box_style),
slider_bar_colour=map_styles_to_hex_colours(box_style),
slider_text_visible=False)
[docs] def set_widget_state(self, zoom_options, allow_callback=True):
r"""
Method that updates the state of the widget, if the provided
`zoom_options` value is different than `self.selected_values`.
Parameters
----------
zoom_options : `dict`
The `dict` with the selected options. It must have the following
keys:
* ``min`` : (`float`) The minimum value (e.g. ``0.1``).
* ``max`` : (`float`) The maximum value (e.g. ``4.``).
* ``step`` : (`float`) The zoom step (e.g. ``0.05``).
* ``zoom`` : (`float`) The zoom value (e.g. ``1.``).
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
# Check if update is required
if (zoom_options['zoom'] != self.selected_values or
zoom_options['min'] != self.zoom_slider.min or
zoom_options['max'] != self.zoom_slider.max or
zoom_options['step'] != self.zoom_slider.step):
# keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update widgets
self.zoom_text.min = zoom_options['min']
self.zoom_slider.min = zoom_options['min']
self.zoom_text.max = zoom_options['max']
self.zoom_slider.max = zoom_options['max']
self.zoom_slider.step = zoom_options['step']
self.zoom_text.value = "{:.2f}".format(zoom_options['zoom'])
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class ZoomTwoScalesWidget(MenpoWidget):
r"""
Creates a widget for selecting zoom options with a single scale.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
zoom_options : `dict`
The `dict` with the default options. It must have the following keys:
* ``min`` : (`float`) The minimum value (e.g. ``0.1``).
* ``max`` : (`float`) The maximum value (e.g. ``4.``).
* ``step`` : (`float`) The zoom step (e.g. ``0.05``).
* ``zoom`` : (`float`) The zoom value (e.g. ``1.``).
* ``lock_aspect_ratio`` : (`bool`) Flag that locks the aspect ratio.
render_function : `callable` or ``None``, optional
The render function that is executed when the index value changes.
If ``None``, then nothing is assigned.
description : `str`, optional
The title of the widget.
minus_description : `str`, optional
The text/icon of the button that zooms_out. If the `str` starts with
`'fa-'`, then a font-awesome icon is defined.
plus_description : `str`, optional
The title of the button that zooms in. If the `str` starts with
`'fa-'`, then a font-awesome icon is defined.
continuous_update : `bool`, optional
If ``True``, then the render and update functions are called while
moving the zoom slider's handle. If ``False``, then the the functions
are called only when the handle (mouse click) is released.
"""
def __init__(self, zoom_options, render_function=None,
description='Figure scale: ',
minus_description='fa-search-minus',
plus_description='fa-search-plus', continuous_update=False):
# Create children
self.title = ipywidgets.Latex(value=description, padding=6, margin=6)
self.x_title = ipywidgets.Latex(value='X', padding=6, margin=6)
self.y_title = ipywidgets.Latex(value='Y', padding=6, margin=6)
m_icon, m_description = parse_font_awesome_icon(minus_description)
self.x_button_minus = ipywidgets.Button(
description=m_description, icon=m_icon, width='1cm',
tooltip='Zoom Out')
self.y_button_minus = ipywidgets.Button(
description=m_description, icon=m_icon, width='1cm',
tooltip='Zoom Out')
p_icon, p_description = parse_font_awesome_icon(plus_description)
self.x_button_plus = ipywidgets.Button(
description=p_description, icon=p_icon, width='1cm',
tooltip='Zoom In')
self.y_button_plus = ipywidgets.Button(
description=p_description, icon=p_icon, width='1cm',
tooltip='Zoom In')
self.x_zoom_slider = ipywidgets.FloatSlider(
value=zoom_options['zoom'][0], min=zoom_options['min'],
max=zoom_options['max'], readout=False, width='6cm',
continuous_update=continuous_update)
self.y_zoom_slider = ipywidgets.FloatSlider(
value=zoom_options['zoom'][1], min=zoom_options['min'],
max=zoom_options['max'], readout=False, width='6cm',
continuous_update=continuous_update)
self.x_zoom_text = ipywidgets.BoundedFloatText(
value=zoom_options['zoom'][0], min=zoom_options['min'],
max=zoom_options['max'], width='1.5cm')
self.y_zoom_text = ipywidgets.BoundedFloatText(
value=zoom_options['zoom'][1], min=zoom_options['min'],
max=zoom_options['max'], width='1.5cm')
self.x_box = ipywidgets.HBox(
children=[self.x_title, self.x_button_minus, self.x_zoom_slider,
self.x_button_plus, self.x_zoom_text], margin='0.05cm')
self.y_box = ipywidgets.HBox(
children=[self.y_title, self.y_button_minus, self.y_zoom_slider,
self.y_button_plus, self.y_zoom_text], margin='0.05cm')
self.x_y_box = ipywidgets.VBox(children=[self.x_box, self.y_box])
self.lock_link = ipywidgets.jslink((self.x_zoom_slider, 'value'),
(self.y_zoom_slider, 'value'))
lock_icon = 'fa-link'
if not zoom_options['lock_aspect_ratio']:
lock_icon = 'fa-unlink'
self.lock_link.unlink()
self.lock_aspect_button = ipywidgets.ToggleButton(
value=zoom_options['lock_aspect_ratio'], description='',
icon=lock_icon, tooltip='Keep aspect ratio')
self.options_box = ipywidgets.HBox(
children=[self.lock_aspect_button, self.x_y_box], align='center')
# Create final widget
children = [self.title, self.options_box]
super(ZoomTwoScalesWidget, self).__init__(
children, List, zoom_options['zoom'],
render_function=render_function, orientation='horizontal',
align='center')
# Link the zoom texts and sliders
link((self.x_zoom_slider, 'value'), (self.x_zoom_text, 'value'))
link((self.y_zoom_slider, 'value'), (self.y_zoom_text, 'value'))
# Assign properties
self.lock_aspect_ratio = zoom_options['lock_aspect_ratio']
# Set functionality
def x_value_plus(name):
tmp_val = float(self.x_zoom_text.value) + self.x_zoom_slider.step
if tmp_val > self.x_zoom_slider.max:
self.x_zoom_text.value = "{:.2f}".format(
self.x_zoom_slider.max)
else:
self.x_zoom_text.value = "{:.2f}".format(tmp_val)
self.x_button_plus.on_click(x_value_plus)
def x_value_minus(name):
tmp_val = float(self.x_zoom_text.value) - self.x_zoom_slider.step
if tmp_val < self.x_zoom_slider.min:
self.x_zoom_text.value = "{:.2f}".format(
self.x_zoom_slider.min)
else:
self.x_zoom_text.value = "{:.2f}".format(tmp_val)
self.x_button_minus.on_click(x_value_minus)
def y_value_plus(name):
tmp_val = float(self.y_zoom_text.value) + self.y_zoom_slider.step
if tmp_val > self.y_zoom_slider.max:
self.y_zoom_text.value = "{:.2f}".format(
self.y_zoom_slider.max)
else:
self.y_zoom_text.value = "{:.2f}".format(tmp_val)
self.y_button_plus.on_click(y_value_plus)
def y_value_minus(name):
tmp_val = float(self.y_zoom_text.value) - self.y_zoom_slider.step
if tmp_val < self.y_zoom_slider.min:
self.y_zoom_text.value = "{:.2f}".format(
self.y_zoom_slider.min)
else:
self.y_zoom_text.value = "{:.2f}".format(tmp_val)
self.y_button_minus.on_click(y_value_minus)
def save_zoom(change):
value = change['new']
if self.lock_aspect_ratio:
self.selected_values = [value, value]
else:
self.selected_values = [self.x_zoom_slider.value,
self.y_zoom_slider.value]
self.x_zoom_slider.observe(save_zoom, names='value', type='change')
self.y_zoom_slider.observe(save_zoom, names='value', type='change')
def link_button(change):
self.lock_aspect_ratio = change['new']
if change['new']:
self.lock_aspect_button.icon = 'fa-link'
self.lock_link = link((self.x_zoom_slider, 'value'),
(self.y_zoom_slider, 'value'))
self.selected_values = [self.x_zoom_slider.value,
self.x_zoom_slider.value]
else:
self.lock_aspect_button.icon = 'fa-unlink'
self.lock_link.unlink()
self.lock_aspect_button.observe(link_button, names='value',
type='change')
[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='', slider_width='6cm'):
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'
slider_width : `float`, optional
The width of the slider
"""
format_box(self, box_style, border_visible, border_colour, border_style,
border_width, border_radius, padding, margin)
format_font(self.title, font_family, font_size, font_style,
font_weight)
format_font(self.x_title, font_family, font_size, font_style,
font_weight)
format_font(self.y_title, font_family, font_size, font_style,
font_weight)
format_font(self.x_button_minus, font_family, font_size, font_style,
font_weight)
format_font(self.x_button_plus, font_family, font_size, font_style,
font_weight)
format_font(self.x_zoom_text, font_family, font_size, font_style,
font_weight)
format_font(self.y_button_minus, font_family, font_size, font_style,
font_weight)
format_font(self.y_button_plus, font_family, font_size, font_style,
font_weight)
format_font(self.y_zoom_text, font_family, font_size, font_style,
font_weight)
if box_style not in ['', None]:
self.x_button_minus.button_style = 'primary'
self.x_button_plus.button_style = 'primary'
self.y_button_minus.button_style = 'primary'
self.y_button_plus.button_style = 'primary'
self.lock_aspect_button.button_style = 'warning'
else:
self.x_button_minus.button_style = None
self.x_button_plus.button_style = None
self.y_button_minus.button_style = None
self.y_button_plus.button_style = None
self.lock_aspect_button.button_style = None
format_slider(self.x_zoom_slider, slider_width=slider_width,
slider_handle_colour=map_styles_to_hex_colours(box_style),
slider_bar_colour=map_styles_to_hex_colours(box_style),
slider_text_visible=False)
format_slider(self.y_zoom_slider, slider_width=slider_width,
slider_handle_colour=map_styles_to_hex_colours(box_style),
slider_bar_colour=map_styles_to_hex_colours(box_style),
slider_text_visible=False)
[docs] def set_widget_state(self, zoom_options, allow_callback=True):
r"""
Method that updates the state of the widget, if the provided
`zoom_options` value is different than `self.selected_values`.
Parameters
----------
zoom_options : `dict`
The `dict` with the selected options. It must have the following
keys:
* ``min`` : (`float`) The minimum value (e.g. ``0.1``).
* ``max`` : (`float`) The maximum value (e.g. ``4.``).
* ``step`` : (`float`) The zoom step (e.g. ``0.05``).
* ``zoom`` : (`float`) The zoom value (e.g. ``1.``).
* ``lock_aspect_ratio`` : (`bool`) Flag that locks the aspect ratio.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
# Check if update is required
if (not lists_are_the_same(zoom_options['zoom'],
self.selected_values) or
zoom_options['min'] != self.x_zoom_slider.min or
zoom_options['max'] != self.x_zoom_slider.max or
zoom_options['step'] != self.x_zoom_slider.step):
# keep old value
old_value = self.selected_values
# temporarily remove render and update functions
render_function = self._render_function
self.remove_render_function()
# update widgets
self.x_zoom_text.min = zoom_options['min']
self.x_zoom_slider.min = zoom_options['min']
self.y_zoom_text.min = zoom_options['min']
self.y_zoom_slider.min = zoom_options['min']
self.x_zoom_text.max = zoom_options['max']
self.x_zoom_slider.max = zoom_options['max']
self.y_zoom_text.max = zoom_options['max']
self.y_zoom_slider.max = zoom_options['max']
self.x_zoom_slider.step = zoom_options['step']
self.y_zoom_slider.step = zoom_options['step']
self.x_zoom_text.value = "{:.2f}".format(zoom_options['zoom'][0])
self.y_zoom_text.value = "{:.2f}".format(zoom_options['zoom'][1])
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class ImageOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting image rendering options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
image_options : `dict`
The initial image options. It must be a `dict` with the following keys:
* ``alpha`` : (`float`) The alpha value (e.g. ``1.``).
* ``interpolation`` : (`str`) The interpolation (e.g. ``'bilinear'``).
* ``cmap_name`` : (`str`) The colourmap (e.g. ``'gray'``).
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
"""
def __init__(self, image_options, render_function=None):
# Create children
self.interpolation_checkbox = ipywidgets.Checkbox(
description='Pixelated',
value=image_options['interpolation'] == 'none')
self.alpha_slider = ipywidgets.FloatSlider(
description='Alpha', value=image_options['alpha'],
min=0.0, max=1.0, step=0.05, width='4cm', continuous_update=False)
cmap_dict = OrderedDict()
cmap_dict['None'] = None
cmap_dict['afmhot'] = 'afmhot'
cmap_dict['autumn'] = 'autumn'
cmap_dict['binary'] = 'binary'
cmap_dict['bone'] = 'bone'
cmap_dict['brg'] = 'brg'
cmap_dict['bwr'] = 'bwr'
cmap_dict['cool'] = 'cool'
cmap_dict['coolwarm'] = 'coolwarm'
cmap_dict['copper'] = 'copper'
cmap_dict['cubehelix']= 'cubehelix'
cmap_dict['flag'] = 'flag'
cmap_dict['gist_earth'] = 'gist_earth'
cmap_dict['gist_heat'] = 'gist_heat'
cmap_dict['gist_gray'] = 'gist_gray'
cmap_dict['gist_ncar'] = 'gist_ncar'
cmap_dict['gist_rainbow'] = 'gist_rainbow'
cmap_dict['gist_stern'] = 'gist_stern'
cmap_dict['gist_yarg'] = 'gist_yarg'
cmap_dict['gnuplot'] = 'gnuplot'
cmap_dict['gnuplot2'] = 'gnuplot2'
cmap_dict['gray'] = 'gray'
cmap_dict['hot'] = 'hot'
cmap_dict['hsv'] = 'hsv'
cmap_dict['inferno'] = 'inferno'
cmap_dict['jet'] = 'jet'
cmap_dict['magma'] = 'magma'
cmap_dict['nipy_spectral'] = 'nipy_spectral'
cmap_dict['ocean'] = 'ocean'
cmap_dict['pink'] = 'pink'
cmap_dict['plasma'] = 'plasma'
cmap_dict['prism'] = 'prism'
cmap_dict['rainbow'] = 'rainbow'
cmap_dict['seismic'] = 'seismic'
cmap_dict['spectral'] = 'spectral'
cmap_dict['spring'] = 'spring'
cmap_dict['summer'] = 'summer'
cmap_dict['terrain'] = 'terrain'
cmap_dict['viridis'] = 'viridis'
cmap_dict['winter'] = 'winter'
cmap_dict['Blues'] = 'Blues'
cmap_dict['BuGn'] = 'BuGn'
cmap_dict['BuPu'] = 'BuPu'
cmap_dict['GnBu'] = 'GnBu'
cmap_dict['Greens'] = 'Greens'
cmap_dict['Greys'] = 'Greys'
cmap_dict['Oranges'] = 'Oranges'
cmap_dict['OrRd'] = 'OrRd'
cmap_dict['PuBu'] = 'PuBu'
cmap_dict['PuBuGn'] = 'PuBuGn'
cmap_dict['PuRd'] = 'PuRd'
cmap_dict['Purples'] = 'Purples'
cmap_dict['RdPu'] = 'RdPu'
cmap_dict['Reds'] = 'Reds'
cmap_dict['YlGn'] = 'YlGn'
cmap_dict['YlGnBu'] = 'YlGnBu'
cmap_dict['YlOrBr'] = 'YlOrBr'
cmap_dict['YlOrRd'] = 'YlOrRd'
self.cmap_select = ipywidgets.Select(
options=cmap_dict, value='gray', description='Colourmap',
width='3cm', height='2cm')
self.alpha_interpolation_box = ipywidgets.VBox(children=[
self.alpha_slider, self.interpolation_checkbox])
# Create final widget
children = [self.cmap_select, self.alpha_interpolation_box]
super(ImageOptionsWidget, self).__init__(
children, Dict, image_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def save_interpolation(change):
if change['new']:
interpolation = 'none'
else:
interpolation = 'bilinear'
tmp = self.selected_values
self.selected_values = {'interpolation': interpolation,
'alpha': tmp['alpha'],
'cmap_name': tmp['cmap_name']}
self.interpolation_checkbox.observe(save_interpolation, names='value',
type='change')
def save_alpha(change):
tmp = self.selected_values
self.selected_values = {'interpolation': tmp['interpolation'],
'alpha': change['new'],
'cmap_name': tmp['cmap_name']}
self.alpha_slider.observe(save_alpha, names='value', type='change')
def save_cmap(change):
tmp = self.selected_values
self.selected_values = {'interpolation': tmp['interpolation'],
'alpha': tmp['alpha'],
'cmap_name': change['new']}
self.cmap_select.observe(save_cmap, names='value', type='change')
[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=''):
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'
"""
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.alpha_slider, font_family, font_size, font_style,
font_weight)
format_font(self.interpolation_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.cmap_select, font_family, font_size, font_style,
font_weight)
format_slider(self.alpha_slider, slider_width='4cm',
slider_handle_colour=map_styles_to_hex_colours(box_style),
slider_bar_colour=map_styles_to_hex_colours(box_style),
slider_text_visible=True)
[docs] def set_widget_state(self, image_options, allow_callback=True):
r"""
Method that updates the state of the widget if the provided
`image_options` are different than `self.selected_values`.
Parameters
----------
image_options : `dict`
The selected image options. It must be a `dict` with the following
keys:
* ``alpha`` : (`float`) The alpha value (e.g. ``1.``).
* ``interpolation`` : (`str`) The interpolation (e.g. ``'bilinear'``)
* ``cmap_name`` : (`str`) The colourmap (e.g. ``'gray'``).
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
if image_options != self.selected_values:
# keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update
self.alpha_slider.value = image_options['alpha']
self.interpolation_checkbox.value = \
image_options['interpolation'] == 'none'
self.cmap_select.value = image_options['cmap_name']
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class LineOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting line rendering options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
line_options : `dict`
The initial line options. It must be a `dict` with the following keys:
* ``render_lines`` : (`bool`) Flag for rendering the lines.
* ``line_width`` : ('float`) The width of the lines (e.g. ``1.``)
* ``line_colour`` : (`str`) The colour of the lines (e.g. ``'blue'``).
* ``line_style`` : (`str`) The style of the lines (e.g. ``'-'``).
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
render_checkbox_title : `str`, optional
The description of the show line checkbox.
labels : `list` of `str` or ``None``, optional
A `list` with the labels' names that get passed in to the
`ColourSelectionWidget`. If ``None``, then a `list` of the form
``label {}`` is automatically defined. Note that the labels are defined
only for the colour option and not the rest of the options.
"""
def __init__(self, line_options, render_function=None,
render_checkbox_title='Render lines', labels=None):
# Create children
self.render_lines_checkbox = ipywidgets.Checkbox(
description=render_checkbox_title,
value=line_options['render_lines'])
self.line_width_text = ipywidgets.BoundedFloatText(
description='Width', value=line_options['line_width'], min=0.,
max=10**6)
line_style_dict = OrderedDict()
line_style_dict['solid'] = '-'
line_style_dict['dashed'] = '--'
line_style_dict['dash-dot'] = '-.'
line_style_dict['dotted'] = ':'
self.line_style_dropdown = ipywidgets.Dropdown(
options=line_style_dict, value=line_options['line_style'],
description='Style')
self.line_colour_widget = ColourSelectionWidget(
line_options['line_colour'], description='Colour', labels=labels,
render_function=None)
self.line_options_box = ipywidgets.Box(
children=[self.line_style_dropdown, self.line_width_text,
self.line_colour_widget])
# Create final widget
children = [self.render_lines_checkbox, self.line_options_box]
super(LineOptionsWidget, self).__init__(
children, Dict, line_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def line_options_visible(change):
self.line_options_box.visible = change['new']
line_options_visible({'new': line_options['render_lines']})
self.render_lines_checkbox.observe(line_options_visible, names='value',
type='change')
def save_options(change):
self.selected_values = {
'render_lines': self.render_lines_checkbox.value,
'line_width': float(self.line_width_text.value),
'line_colour': self.line_colour_widget.selected_values,
'line_style': self.line_style_dropdown.value}
self.render_lines_checkbox.observe(save_options, names='value',
type='change')
self.line_width_text.observe(save_options, names='value', type='change')
self.line_colour_widget.observe(save_options, names='selected_values',
type='change')
self.line_style_dropdown.observe(save_options, names='value',
type='change')
[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=''):
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'
"""
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_lines_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.line_style_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.line_width_text, font_family, font_size, font_style,
font_weight)
self.line_colour_widget.style(
box_style=None, border_visible=False, font_family=font_family,
font_size=font_size, font_weight=font_weight, font_style=font_style,
label_colour=None, label_background_colour=None,
picker_colour=None, picker_background_colour=None,
apply_to_all_style='')
[docs] def set_widget_state(self, line_options, labels=None, allow_callback=True):
r"""
Method that updates the state of the widget if the provided
`line_options` are different than `self.selected_values`.
Parameters
----------
line_options : `dict`
The selected line options. It must be a `dict` with the following
keys:
* ``render_lines`` : (`bool`) Flag for rendering the lines.
* ``line_width`` : ('float`) The width of the lines (e.g. ``1.``)
* ``line_colour`` : (`str`) The colour of the lines (e.g. ``'blue'``).
* ``line_style`` : (`str`) The style of the lines (e.g. ``'-'``).
labels : `list` of `str` or ``None``, optional
A `list` with the labels' names that get passed in to the
`ColourSelectionWidget`. If ``None``, then a `list` of the form
``label {}`` is automatically defined.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
if self.selected_values != line_options:
# keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update
self.render_lines_checkbox.value = line_options['render_lines']
self.line_style_dropdown.value = line_options['line_style']
self.line_width_text.value = float(line_options['line_width'])
self.line_colour_widget.set_widget_state(
line_options['line_colour'], labels=labels,
allow_callback=False)
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class MarkerOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting marker rendering options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
marker_options : `dict`
The initial marker options. It must be a `dict` with the following keys:
* ``render_markers`` : (`bool`) Flag for rendering the markers.
* ``marker_size`` : (`int`) The size of the markers (e.g. ``20``).
* ``marker_face_colour`` : (`list`) The colours list.
(e.g. ``['red', 'blue']``).
* ``marker_edge_colour`` : (`list`) The edge colours list.
(e.g. ``['black', 'white']``).
* ``marker_style`` : (`str`) The size of the markers. (e.g. ``'o'``).
* ``marker_edge_width`` : (`int`) The esdge width of the markers.
(e.g. ``1``).
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
render_checkbox_title : `str`, optional
The description of the render marker checkbox.
labels : `list` of `str` or ``None``, optional
A `list` with the labels' names that get passed in to the
`ColourSelectionWidget`. If ``None``, then a `list` of the form
``label {}`` is automatically defined. Note that the labels are defined
only for the colour option and not the rest of the options.
"""
def __init__(self, marker_options, render_function=None,
render_checkbox_title='Render markers', labels=None):
# Create children
self.render_markers_checkbox = ipywidgets.Checkbox(
description=render_checkbox_title,
value=marker_options['render_markers'])
self.marker_size_text = ipywidgets.BoundedIntText(
description='Size', value=marker_options['marker_size'], min=0,
max=10**6)
self.marker_edge_width_text = ipywidgets.BoundedFloatText(
description='Edge width', min=0., max=10**6,
value=marker_options['marker_edge_width'])
marker_style_dict = OrderedDict()
marker_style_dict['point'] = '.'
marker_style_dict['pixel'] = ','
marker_style_dict['circle'] = 'o'
marker_style_dict['triangle down'] = 'v'
marker_style_dict['triangle up'] = '^'
marker_style_dict['triangle left'] = '<'
marker_style_dict['triangle right'] = '>'
marker_style_dict['tri down'] = '1'
marker_style_dict['tri up'] = '2'
marker_style_dict['tri left'] = '3'
marker_style_dict['tri right'] = '4'
marker_style_dict['octagon'] = '8'
marker_style_dict['square'] = 's'
marker_style_dict['pentagon'] = 'p'
marker_style_dict['star'] = '*'
marker_style_dict['hexagon 1'] = 'h'
marker_style_dict['hexagon 2'] = 'H'
marker_style_dict['plus'] = '+'
marker_style_dict['x'] = 'x'
marker_style_dict['diamond'] = 'D'
marker_style_dict['thin diamond'] = 'd'
self.marker_style_dropdown = ipywidgets.Dropdown(
options=marker_style_dict, value=marker_options['marker_style'],
description='Style')
self.marker_box_1 = ipywidgets.VBox(
children=[self.marker_style_dropdown, self.marker_size_text,
self.marker_edge_width_text], margin='0.1cm')
self.marker_face_colour_widget = ColourSelectionWidget(
marker_options['marker_face_colour'], description='Face colour',
labels=labels, render_function=None)
self.marker_edge_colour_widget = ColourSelectionWidget(
marker_options['marker_edge_colour'], description='Edge colour',
labels=labels, render_function=None)
self.marker_box_2 = ipywidgets.VBox(
children=[self.marker_face_colour_widget,
self.marker_edge_colour_widget], margin='0.1cm',
align='end')
self.marker_options_box = ipywidgets.HBox(
children=[self.marker_box_1, self.marker_box_2])
# Create final widget
children = [self.render_markers_checkbox, self.marker_options_box]
super(MarkerOptionsWidget, self).__init__(
children, Dict, marker_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def marker_options_visible(change):
self.marker_options_box.visible = change['new']
marker_options_visible({'new': marker_options['render_markers']})
self.render_markers_checkbox.observe(marker_options_visible,
names='value', type='change')
def save_options(change):
self.selected_values = {
'render_markers': self.render_markers_checkbox.value,
'marker_size': int(self.marker_size_text.value),
'marker_face_colour':
self.marker_face_colour_widget.selected_values,
'marker_edge_colour':
self.marker_edge_colour_widget.selected_values,
'marker_style': self.marker_style_dropdown.value,
'marker_edge_width': float(self.marker_edge_width_text.value)}
self.render_markers_checkbox.observe(save_options, names='value',
type='change')
self.marker_size_text.observe(save_options, names='value', type='change')
self.marker_face_colour_widget.observe(
save_options, names='selected_values', type='change')
self.marker_edge_colour_widget.observe(
save_options, names='selected_values', type='change')
self.marker_style_dropdown.observe(save_options, names='value',
type='change')
self.marker_edge_width_text.observe(save_options, names='value',
type='change')
[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=''):
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'
"""
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_markers_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.marker_style_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.marker_size_text, font_family, font_size, font_style,
font_weight)
format_font(self.marker_edge_width_text, font_family, font_size,
font_style, font_weight)
self.marker_edge_colour_widget.style(
box_style=None, border_visible=False, font_family=font_family,
font_size=font_size, font_weight=font_weight, font_style=font_style,
label_colour=None, label_background_colour=None,
picker_colour=None, picker_background_colour=None,
apply_to_all_style='')
self.marker_face_colour_widget.style(
box_style=None, border_visible=False, font_family=font_family,
font_size=font_size, font_weight=font_weight, font_style=font_style,
label_colour=None, label_background_colour=None,
picker_colour=None, picker_background_colour=None,
apply_to_all_style='')
[docs] def set_widget_state(self, marker_options, labels=None,
allow_callback=True):
r"""
Method that updates the state of the widget if the provided
`marker_options` are different than `self.selected_values`.
Parameters
----------
marker_options : `dict`
The seected marker options. It must be a `dict` with the following
keys:
* ``render_markers`` : (`bool`) Flag for rendering the markers.
* ``marker_size`` : (`int`) The size of the markers (e.g. ``20``).
* ``marker_face_colour`` : (`list`) The colours list.
(e.g. ``['red', 'blue']``).
* ``marker_edge_colour`` : (`list`) The edge colours list.
(e.g. ``['black', 'white']``).
* ``marker_style`` : (`str`) The size of the markers. (e.g. ``'o'``).
* ``marker_edge_width`` : (`int`) The esdge width of the markers.
(e.g. ``1``).
labels : `list` of `str` or ``None``, optional
A `list` with the labels' names that get passed in to the
`ColourSelectionWidget`. If ``None``, then a `list` of the form
``label {}`` is automatically defined.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
if self.selected_values != marker_options:
# keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update
self.render_markers_checkbox.value = marker_options['render_markers']
self.marker_style_dropdown.value = marker_options['marker_style']
self.marker_size_text.value = int(marker_options['marker_size'])
self.marker_edge_width_text.value = \
float(marker_options['marker_edge_width'])
self.marker_face_colour_widget.set_widget_state(
marker_options['marker_face_colour'], labels=labels,
allow_callback=False)
self.marker_edge_colour_widget.set_widget_state(
marker_options['marker_edge_colour'], labels=labels,
allow_callback=False)
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class NumberingOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting numbering rendering options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
numbers_options : `dict`
The initial numbering options. It must be a `dict` with the following
keys:
* ``render_numbering`` : (`bool`) Flag for rendering the numbers.
* ``numbers_font_name`` : (`str`) The font name (e.g. ``'serif'``).
* ``numbers_font_size`` : (`int`) The font size (e.g. ``10``).
* ``numbers_font_style`` : (`str`) The font style (e.g. ``'normal'``).
* ``numbers_font_weight`` : (`str`) The font weight (e.g. ``'normal'``).
* ``numbers_font_colour`` : (`list`) The font colour (e.g. ``['black']``)
* ``numbers_horizontal_align`` : (`str`) The horizontal alignment
(e.g. ``'center'``).
* ``numbers_vertical_align`` : (`str`) The vertical alignment
(e.g. ``'bottom'``).
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
render_checkbox_title : `str`, optional
The description of the render numbering checkbox.
"""
def __init__(self, numbers_options, render_function=None,
render_checkbox_title='Render numbering'):
# Create children
self.render_numbering_checkbox = ipywidgets.Checkbox(
description=render_checkbox_title,
value=numbers_options['render_numbering'])
numbers_font_name_dict = OrderedDict()
numbers_font_name_dict['serif'] = 'serif'
numbers_font_name_dict['sans-serif'] = 'sans-serif'
numbers_font_name_dict['cursive'] = 'cursive'
numbers_font_name_dict['fantasy'] = 'fantasy'
numbers_font_name_dict['monospace'] = 'monospace'
self.numbers_font_name_dropdown = ipywidgets.Dropdown(
options=numbers_font_name_dict,
value=numbers_options['numbers_font_name'], description='Font')
self.numbers_font_size_text = ipywidgets.BoundedIntText(
description='Size', min=0, max=10**6,
value=numbers_options['numbers_font_size'])
numbers_font_style_dict = OrderedDict()
numbers_font_style_dict['normal'] = 'normal'
numbers_font_style_dict['italic'] = 'italic'
numbers_font_style_dict['oblique'] = 'oblique'
self.numbers_font_style_dropdown = ipywidgets.Dropdown(
options=numbers_font_style_dict,
value=numbers_options['numbers_font_style'], description='Style')
numbers_font_weight_dict = OrderedDict()
numbers_font_weight_dict['normal'] = 'normal'
numbers_font_weight_dict['ultralight'] = 'ultralight'
numbers_font_weight_dict['light'] = 'light'
numbers_font_weight_dict['regular'] = 'regular'
numbers_font_weight_dict['book'] = 'book'
numbers_font_weight_dict['medium'] = 'medium'
numbers_font_weight_dict['roman'] = 'roman'
numbers_font_weight_dict['semibold'] = 'semibold'
numbers_font_weight_dict['demibold'] = 'demibold'
numbers_font_weight_dict['demi'] = 'demi'
numbers_font_weight_dict['bold'] = 'bold'
numbers_font_weight_dict['heavy'] = 'heavy'
numbers_font_weight_dict['extra bold'] = 'extra bold'
numbers_font_weight_dict['black'] = 'black'
self.numbers_font_weight_dropdown = ipywidgets.Dropdown(
options=numbers_font_weight_dict,
value=numbers_options['numbers_font_weight'], description='Weight')
self.numbers_font_colour_widget = ColourSelectionWidget(
numbers_options['numbers_font_colour'], description='Colour',
render_function=None)
numbers_horizontal_align_dict = OrderedDict()
numbers_horizontal_align_dict['center'] = 'center'
numbers_horizontal_align_dict['right'] = 'right'
numbers_horizontal_align_dict['left'] = 'left'
self.numbers_horizontal_align_dropdown = ipywidgets.Dropdown(
options=numbers_horizontal_align_dict,
value=numbers_options['numbers_horizontal_align'],
description='Align hor.')
numbers_vertical_align_dict = OrderedDict()
numbers_vertical_align_dict['center'] = 'center'
numbers_vertical_align_dict['top'] = 'top'
numbers_vertical_align_dict['bottom'] = 'bottom'
numbers_vertical_align_dict['baseline'] = 'baseline'
self.numbers_vertical_align_dropdown = ipywidgets.Dropdown(
options=numbers_vertical_align_dict,
value=numbers_options['numbers_vertical_align'],
description='Align ver.')
self.name_size_style_weight = ipywidgets.VBox(
children=[self.numbers_font_name_dropdown,
self.numbers_font_size_text,
self.numbers_font_style_dropdown,
self.numbers_font_weight_dropdown])
self.colour_horizontal_vertical_align = ipywidgets.VBox(
children=[self.numbers_font_colour_widget,
self.numbers_horizontal_align_dropdown,
self.numbers_vertical_align_dropdown])
self.numbering_options_box = ipywidgets.HBox(
children=[self.name_size_style_weight,
self.colour_horizontal_vertical_align])
# Create final widget
children = [self.render_numbering_checkbox, self.numbering_options_box]
super(NumberingOptionsWidget, self).__init__(
children, Dict, numbers_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def numbering_options_visible(change):
self.numbering_options_box.visible = change['new']
numbering_options_visible({'new': numbers_options['render_numbering']})
self.render_numbering_checkbox.observe(numbering_options_visible,
names='value', type='change')
def save_options(change):
self.selected_values = {
'render_numbering': self.render_numbering_checkbox.value,
'numbers_font_name': self.numbers_font_name_dropdown.value,
'numbers_font_size': int(self.numbers_font_size_text.value),
'numbers_font_style': self.numbers_font_style_dropdown.value,
'numbers_font_weight': self.numbers_font_weight_dropdown.value,
'numbers_font_colour':
self.numbers_font_colour_widget.selected_values[0],
'numbers_horizontal_align':
self.numbers_horizontal_align_dropdown.value,
'numbers_vertical_align':
self.numbers_vertical_align_dropdown.value}
self.render_numbering_checkbox.observe(save_options, names='value',
type='change')
self.numbers_font_name_dropdown.observe(save_options, names='value',
type='change')
self.numbers_font_size_text.observe(save_options, names='value',
type='change')
self.numbers_font_style_dropdown.observe(save_options, names='value',
type='change')
self.numbers_font_weight_dropdown.observe(save_options, names='value',
type='change')
self.numbers_font_colour_widget.observe(
save_options, names='selected_values', type='change')
self.numbers_horizontal_align_dropdown.observe(
save_options, names='value', type='change')
self.numbers_vertical_align_dropdown.observe(
save_options, names='value', type='change')
[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=''):
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'
"""
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_numbering_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.numbers_font_name_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.numbers_font_size_text, font_family, font_size,
font_style, font_weight)
format_font(self.numbers_font_style_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.numbers_font_weight_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.numbers_horizontal_align_dropdown, font_family,
font_size, font_style, font_weight)
format_font(self.numbers_vertical_align_dropdown, font_family,
font_size, font_style, font_weight)
self.numbers_font_colour_widget.style(
box_style=None, border_visible=False, font_family=font_family,
font_size=font_size, font_weight=font_weight, font_style=font_style,
label_colour=None, label_background_colour=None,
picker_colour=None, picker_background_colour=None,
apply_to_all_style='')
[docs] def set_widget_state(self, numbers_options, allow_callback=True):
r"""
Method that updates the state of the widget if the given
`numbers_options` are different than `self.selected_values`.
Parameters
----------
numbers_options : `dict`
The selected numbering options. It must be a `dict` with the
following keys:
* ``render_numbering`` : (`bool`) Flag for rendering the numbers.
* ``numbers_font_name`` : (`str`) The font name (e.g. ``'serif'``).
* ``numbers_font_size`` : (`int`) The font size (e.g. ``10``).
* ``numbers_font_style`` : (`str`) The font style (e.g. ``'normal'``).
* ``numbers_font_weight`` : (`str`) The font weight (e.g. ``'normal'``).
* ``numbers_font_colour`` : (`colour`) The font colour
(e.g. ``'black'``)
* ``numbers_horizontal_align`` : (`str`) The horizontal alignment
(e.g. ``'center'``).
* ``numbers_vertical_align`` : (`str`) The vertical alignment
(e.g. ``'bottom'``).
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
if self.selected_values != numbers_options:
# keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update
self.render_numbering_checkbox.value = \
numbers_options['render_numbering']
self.numbers_font_name_dropdown.value = \
numbers_options['numbers_font_name']
self.numbers_font_size_text.value = \
int(numbers_options['numbers_font_size'])
self.numbers_font_style_dropdown.value = \
numbers_options['numbers_font_style']
self.numbers_font_weight_dropdown.value = \
numbers_options['numbers_font_weight']
self.numbers_horizontal_align_dropdown.value = \
numbers_options['numbers_horizontal_align']
self.numbers_vertical_align_dropdown.value = \
numbers_options['numbers_vertical_align']
self.numbers_font_colour_widget.set_widget_state(
numbers_options['numbers_font_colour'],
allow_callback=False)
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class AxesLimitsWidget(MenpoWidget):
r"""
Creates a widget for selecting the axes limits.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
axes_x_limits : `float` or [`float`, `float`] or ``None``
The limits of the x axis.
axes_y_limits : `float` or [`float`, `float`] or ``None``
The limits of the y axis.
render_function : `callable` or ``None``, optional
The render function that is executed when the index value changes.
If ``None``, then nothing is assigned.
"""
def __init__(self, axes_x_limits, axes_y_limits, render_function=None):
# Create children
# x limits
if axes_x_limits is None:
toggles_initial_value = 'auto'
percentage_initial_value = [0.]
percentage_visible = False
range_initial_value = [0., 100.]
range_visible = False
elif isinstance(axes_x_limits, float):
toggles_initial_value = 'percentage'
percentage_initial_value = [axes_x_limits]
percentage_visible = True
range_initial_value = [0., 100.]
range_visible = False
else:
toggles_initial_value = 'range'
percentage_initial_value = [0.]
percentage_visible = False
range_initial_value = axes_x_limits
range_visible = True
self.axes_x_limits_toggles = ipywidgets.ToggleButtons(
description='X limits:', value=toggles_initial_value,
options=['auto', 'percentage', 'range'], margin='0.1cm')
self.axes_x_limits_percentage = ListWidget(
percentage_initial_value, mode='float', description='',
render_function=None, example_visible=False)
self.axes_x_limits_percentage.margin = '0.1cm'
self.axes_x_limits_percentage.visible = percentage_visible
self.axes_x_limits_range = ListWidget(
range_initial_value, mode='float', description='',
render_function=None, example_visible=False)
self.axes_x_limits_range.margin = '0.1cm'
self.axes_x_limits_range.visible = range_visible
self.axes_x_limits_options_box = ipywidgets.HBox(
children=[self.axes_x_limits_percentage, self.axes_x_limits_range])
self.axes_x_limits_box = ipywidgets.HBox(
children=[self.axes_x_limits_toggles,
self.axes_x_limits_options_box], align='start')
# y limits
if axes_y_limits is None:
toggles_initial_value = 'auto'
percentage_initial_value = [0.]
percentage_visible = False
range_initial_value = [0., 100.]
range_visible = False
elif isinstance(axes_y_limits, float):
toggles_initial_value = 'percentage'
percentage_initial_value = [axes_y_limits]
percentage_visible = True
range_initial_value = [0., 100.]
range_visible = False
else:
toggles_initial_value = 'range'
percentage_initial_value = [0.]
percentage_visible = False
range_initial_value = axes_y_limits
range_visible = True
self.axes_y_limits_toggles = ipywidgets.ToggleButtons(
description='Y limits:', value=toggles_initial_value,
options=['auto', 'percentage', 'range'], margin='0.1cm')
self.axes_y_limits_percentage = ListWidget(
percentage_initial_value, mode='float', description='',
render_function=None, example_visible=False)
self.axes_y_limits_percentage.margin = '0.1cm'
self.axes_y_limits_percentage.visible = percentage_visible
self.axes_y_limits_range = ListWidget(
range_initial_value, mode='float', description='',
render_function=None, example_visible=False)
self.axes_y_limits_range.margin = '0.1cm'
self.axes_y_limits_range.visible = range_visible
self.axes_y_limits_options_box = ipywidgets.HBox(
children=[self.axes_y_limits_percentage, self.axes_y_limits_range])
self.axes_y_limits_box = ipywidgets.HBox(
children=[self.axes_y_limits_toggles,
self.axes_y_limits_options_box], align='start')
# Create final widget
children = [self.axes_x_limits_box, self.axes_y_limits_box]
super(AxesLimitsWidget, self).__init__(
children, Dict, {'x': axes_x_limits, 'y': axes_y_limits},
render_function=render_function, orientation='vertical',
align='start')
# Set functionality
def x_visibility(change):
if change['new'] == 'auto':
self.axes_x_limits_percentage.visible = False
self.axes_x_limits_range.visible = False
elif change['new'] == 'percentage':
self.axes_x_limits_percentage.visible = True
self.axes_x_limits_range.visible = False
else:
self.axes_x_limits_percentage.visible = False
self.axes_x_limits_range.visible = True
self.axes_x_limits_toggles.observe(x_visibility, names='value',
type='change')
def y_visibility(change):
if change['new'] == 'auto':
self.axes_y_limits_percentage.visible = False
self.axes_y_limits_range.visible = False
elif change['new'] == 'percentage':
self.axes_y_limits_percentage.visible = True
self.axes_y_limits_range.visible = False
else:
self.axes_y_limits_percentage.visible = False
self.axes_y_limits_range.visible = True
self.axes_y_limits_toggles.observe(y_visibility, names='value',
type='change')
def save_options(change):
if self.axes_x_limits_toggles.value == 'auto':
x_val = None
elif self.axes_x_limits_toggles.value == 'percentage':
x_val = self.axes_x_limits_percentage.selected_values[0]
else:
x_val = [self.axes_x_limits_range.selected_values[0],
self.axes_x_limits_range.selected_values[1]]
if self.axes_y_limits_toggles.value == 'auto':
y_val = None
elif self.axes_y_limits_toggles.value == 'percentage':
y_val = self.axes_y_limits_percentage.selected_values[0]
else:
y_val = [self.axes_y_limits_range.selected_values[0],
self.axes_y_limits_range.selected_values[1]]
self.selected_values = {'x': x_val, 'y': y_val}
self.axes_x_limits_toggles.observe(save_options, names='value',
type='change')
self.axes_x_limits_percentage.observe(
save_options, names='selected_values', type='change')
self.axes_x_limits_range.observe(save_options, names='selected_values',
type='change')
self.axes_y_limits_toggles.observe(save_options, names='value',
type='change')
self.axes_y_limits_percentage.observe(
save_options, names='selected_values', type='change')
self.axes_y_limits_range.observe(save_options, names='selected_values',
type='change')
[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='', toggles_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'
toggles_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.axes_x_limits_toggles, font_family, font_size,
font_style, font_weight)
format_font(self.axes_y_limits_toggles, font_family, font_size,
font_style, font_weight)
self.axes_x_limits_toggles.button_style = toggles_style
self.axes_y_limits_toggles.button_style = toggles_style
self.axes_x_limits_percentage.style(
box_style=box_style, border_visible=False, padding=0,
margin='0.1cm', text_box_style=box_style, text_box_width=None,
font_family=font_family, font_size=font_size,
font_style=font_style, font_weight=font_weight)
self.axes_x_limits_range.style(
box_style=box_style, border_visible=False, padding=0,
margin='0.1cm', text_box_style=box_style, text_box_width=None,
font_family=font_family, font_size=font_size,
font_style=font_style, font_weight=font_weight)
self.axes_y_limits_percentage.style(
box_style=box_style, border_visible=False, padding=0,
margin='0.1cm', text_box_style=box_style, text_box_width=None,
font_family=font_family, font_size=font_size,
font_style=font_style, font_weight=font_weight)
self.axes_y_limits_range.style(
box_style=box_style, border_visible=False, padding=0,
margin='0.1cm', text_box_style=box_style, text_box_width=None,
font_family=font_family, font_size=font_size,
font_style=font_style, font_weight=font_weight)
[docs] def set_widget_state(self, axes_x_limits, axes_y_limits,
allow_callback=True):
r"""
Method that updates the state of the widget, if the provided
`axes_y_limits` and `axes_x_limits` values are different than
`self.selected_values`.
Parameters
----------
axes_x_limits : `float` or [`float`, `float`] or ``None``
The limits of the x axis.
axes_y_limits : `float` or [`float`, `float`] or ``None``
The limits of the y axis.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
# Check if update is required
if self.selected_values != {'x': axes_x_limits, 'y': axes_y_limits}:
# keep old values
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update
if axes_x_limits is None:
self.axes_x_limits_toggles.value = 'auto'
elif isinstance(axes_x_limits, float):
self.axes_x_limits_toggles.value = 'percentage'
self.axes_x_limits_percentage.set_widget_state(
[axes_x_limits], allow_callback=False)
else:
self.axes_x_limits_toggles.value = 'range'
self.axes_x_limits_range.set_widget_state(
axes_x_limits, allow_callback=False)
if axes_y_limits is None:
self.axes_y_limits_toggles.value = 'auto'
elif isinstance(axes_y_limits, float):
self.axes_y_limits_toggles.value = 'percentage'
self.axes_y_limits_percentage.set_widget_state(
[axes_y_limits], allow_callback=False)
else:
self.axes_y_limits_toggles.value = 'range'
self.axes_y_limits_range.set_widget_state(
axes_y_limits, allow_callback=False)
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class AxesTicksWidget(MenpoWidget):
r"""
Creates a widget for selecting the axes ticks.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
axes_ticks : `dict`
The initial options. It must be a `dict` with the following keys:
* ``x`` : (`list` or ``None``) The x ticks (e.g. ``[10, 20]``).
* ``y`` : (`list` or ``None``) The y ticks (e.g. ``None``).
render_function : `callable` or ``None``, optional
The render function that is executed when the index value changes.
If ``None``, then nothing is assigned.
"""
def __init__(self, axes_ticks, render_function=None):
# Create children
# x ticks
if axes_ticks['x'] is None:
toggles_initial_value = 'auto'
list_visible = False
list_value = []
else:
toggles_initial_value = 'list'
list_visible = True
list_value = axes_ticks['x']
self.axes_x_ticks_toggles = ipywidgets.ToggleButtons(
description='X ticks:', value=toggles_initial_value,
options=['auto', 'list'], margin='0.1cm')
self.axes_x_ticks_list = ListWidget(
list_value, mode='float', description='', render_function=None,
example_visible=False)
self.axes_x_ticks_list.margin = '0.1cm'
self.axes_x_ticks_list.visible = list_visible
self.axes_x_ticks_box = ipywidgets.HBox(
children=[self.axes_x_ticks_toggles, self.axes_x_ticks_list],
align='start')
# y ticks
if axes_ticks['y'] is None:
toggles_initial_value = 'auto'
list_visible = False
list_value = []
else:
toggles_initial_value = 'list'
list_visible = True
list_value = axes_ticks['y']
self.axes_y_ticks_toggles = ipywidgets.ToggleButtons(
description='Y ticks:', value=toggles_initial_value,
options=['auto', 'list'], margin='0.1cm')
self.axes_y_ticks_list = ListWidget(
list_value, mode='float', description='', render_function=None,
example_visible=False)
self.axes_y_ticks_list.margin = '0.1cm'
self.axes_y_ticks_list.visible = list_visible
self.axes_y_ticks_box = ipywidgets.HBox(
children=[self.axes_y_ticks_toggles, self.axes_y_ticks_list],
align='start')
# Create final widget
children = [self.axes_x_ticks_box, self.axes_y_ticks_box]
super(AxesTicksWidget, self).__init__(
children, Dict, axes_ticks, render_function=render_function,
orientation='vertical', align='start')
# Set functionality
def x_visibility(change):
self.axes_x_ticks_list.visible = change['new'] == 'list'
self.axes_x_ticks_toggles.observe(x_visibility, names='value',
type='change')
def y_visibility(change):
self.axes_y_ticks_list.visible = change['new'] == 'list'
self.axes_y_ticks_toggles.observe(y_visibility, names='value',
type='change')
def save_options(change):
if self.axes_x_ticks_toggles.value == 'auto':
x_val = None
else:
x_val = self.axes_x_ticks_list.selected_values
if self.axes_y_ticks_toggles.value == 'auto':
y_val = None
else:
y_val = self.axes_y_ticks_list.selected_values
self.selected_values = {'x': x_val, 'y': y_val}
self.axes_x_ticks_toggles.observe(save_options, names='value',
type='change')
self.axes_x_ticks_list.observe(save_options, names='selected_values',
type='change')
self.axes_y_ticks_toggles.observe(save_options, names='value',
type='change')
self.axes_y_ticks_list.observe(save_options, names='selected_values',
type='change')
[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='', toggles_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'
toggles_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.axes_x_ticks_toggles, font_family, font_size,
font_style, font_weight)
format_font(self.axes_y_ticks_toggles, font_family, font_size,
font_style, font_weight)
self.axes_x_ticks_toggles.button_style = toggles_style
self.axes_y_ticks_toggles.button_style = toggles_style
self.axes_x_ticks_list.style(
box_style=None, border_visible=False, text_box_style=None,
text_box_background_colour=None, font_family=font_family,
margin='0.1cm', font_size=font_size, font_style=font_style,
font_weight=font_weight)
self.axes_y_ticks_list.style(
box_style=None, border_visible=False, text_box_style=None,
text_box_background_colour=None, font_family=font_family,
margin='0.1cm', font_size=font_size, font_style=font_style,
font_weight=font_weight)
[docs] def set_widget_state(self, axes_ticks, allow_callback=True):
r"""
Method that updates the state of the widget, if the provided `axes_ticks`
values are different than `self.selected_values`.
Parameters
----------
axes_ticks : `dict`
The selected options. It must be a `dict` with the following keys:
* ``x`` : (`list` or ``None``) The x ticks (e.g. ``[10, 20]``).
* ``y`` : (`list` or ``None``) The y ticks (e.g. ``None``).
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
# Check if update is required
if axes_ticks != self.selected_values:
# keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update
if axes_ticks['x'] is None:
self.axes_x_ticks_toggles.value = 'auto'
else:
self.axes_x_ticks_toggles.value = 'list'
self.axes_x_ticks_list.set_widget_state(axes_ticks['x'],
allow_callback=False)
if axes_ticks['y'] is None:
self.axes_y_ticks_toggles.value = 'auto'
else:
self.axes_y_ticks_toggles.value = 'list'
self.axes_y_ticks_list.set_widget_state(axes_ticks['y'],
allow_callback=False)
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class AxesOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting axes rendering options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
axes_options : `dict`
The initial axes options. It must be a `dict` with the following keys:
* ``render_axes`` : (`bool`) Flag for rendering the axes.
* ``axes_font_name`` : (`str`) The axes font name (e.g. ``'serif'``).
* ``axes_font_size`` : (`int`) The axes font size (e.g. ``10``).
* ``axes_font_style`` : (`str`) The axes font style (e.g. ``'normal'``)
* ``axes_font_weight`` : (`str`) The font weight (e.g. ``'normal'``).
* ``axes_x_ticks`` : (`list` or ``None``) The x ticks (e.g. ``[10, 20]``)
* ``axes_y_ticks`` : (`list` or ``None``) The y ticks (e.g. ``None``).
* ``axes_x_limits`` : (`float` or [`float`, `float`] or ``None``)
The x limits (e.g. ``None``).
* ``axes_y_limits`` : (`float` or [`float`, `float`] or ``None``)
The y limits (e.g. ``1.``).
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
render_checkbox_title : `str`, optional
The description of the show line checkbox.
"""
def __init__(self, axes_options, render_function=None,
render_checkbox_title='Render axes'):
# Create children
# render checkbox
self.render_axes_checkbox = ipywidgets.Checkbox(
description=render_checkbox_title,
value=axes_options['render_axes'])
# axes font options
axes_font_name_dict = OrderedDict()
axes_font_name_dict['serif'] = 'serif'
axes_font_name_dict['sans-serif'] = 'sans-serif'
axes_font_name_dict['cursive'] = 'cursive'
axes_font_name_dict['fantasy'] = 'fantasy'
axes_font_name_dict['monospace'] = 'monospace'
self.axes_font_name_dropdown = ipywidgets.Dropdown(
options=axes_font_name_dict, value=axes_options['axes_font_name'],
description='Font')
self.axes_font_size_text = ipywidgets.BoundedIntText(
description='Size', value=axes_options['axes_font_size'],
min=0, max=10**6)
axes_font_style_dict = OrderedDict()
axes_font_style_dict['normal'] = 'normal'
axes_font_style_dict['italic'] = 'italic'
axes_font_style_dict['oblique'] = 'oblique'
self.axes_font_style_dropdown = ipywidgets.Dropdown(
options=axes_font_style_dict, description='Style',
value=axes_options['axes_font_style'])
axes_font_weight_dict = OrderedDict()
axes_font_weight_dict['normal'] = 'normal'
axes_font_weight_dict['ultralight'] = 'ultralight'
axes_font_weight_dict['light'] = 'light'
axes_font_weight_dict['regular'] = 'regular'
axes_font_weight_dict['book'] = 'book'
axes_font_weight_dict['medium'] = 'medium'
axes_font_weight_dict['roman'] = 'roman'
axes_font_weight_dict['semibold'] = 'semibold'
axes_font_weight_dict['demibold'] = 'demibold'
axes_font_weight_dict['demi'] = 'demi'
axes_font_weight_dict['bold'] = 'bold'
axes_font_weight_dict['heavy'] = 'heavy'
axes_font_weight_dict['extra bold'] = 'extra bold'
axes_font_weight_dict['black'] = 'black'
self.axes_font_weight_dropdown = ipywidgets.Dropdown(
options=axes_font_weight_dict,
value=axes_options['axes_font_weight'], description='Weight')
self.axes_font_box_1 = ipywidgets.VBox(
children=[self.axes_font_name_dropdown, self.axes_font_size_text],
margin='0.2cm')
self.axes_font_box_2 = ipywidgets.VBox(
children=[self.axes_font_style_dropdown,
self.axes_font_weight_dropdown], margin='0.2cm')
self.axes_font_options_box = ipywidgets.HBox(
children=[self.axes_font_box_1, self.axes_font_box_2])
# axes ticks options
axes_ticks = {'x': axes_options['axes_x_ticks'],
'y': axes_options['axes_y_ticks']}
self.axes_ticks_widget = AxesTicksWidget(axes_ticks,
render_function=None)
# axes font and ticks options box
self.axes_font_ticks_options = ipywidgets.VBox(
children=[self.axes_font_options_box, self.axes_ticks_widget])
# axes font, ticks and render checkbox box
self.axes_options_box = ipywidgets.HBox(
children=[self.render_axes_checkbox, self.axes_font_ticks_options],
margin='0.2cm')
# axes limits options
self.axes_limits_widget = AxesLimitsWidget(
axes_options['axes_x_limits'], axes_options['axes_y_limits'],
render_function=None)
# options tab
self.axes_options_tab = ipywidgets.Tab(
children=[self.axes_options_box, self.axes_limits_widget])
self.axes_options_tab.set_title(0, 'Font & Ticks')
self.axes_options_tab.set_title(1, 'Limits')
# Create final widget
children = [self.axes_options_tab]
super(AxesOptionsWidget, self).__init__(
children, Dict, axes_options, render_function=render_function,
orientation='vertical', align='start')
# Set functionality
def axes_options_visible(change):
self.axes_font_ticks_options.visible = change['new']
axes_options_visible({'new': axes_options['render_axes']})
self.render_axes_checkbox.observe(axes_options_visible, names='value',
type='change')
def save_options(change):
self.selected_values = {
'render_axes': self.render_axes_checkbox.value,
'axes_font_name': self.axes_font_name_dropdown.value,
'axes_font_size': int(self.axes_font_size_text.value),
'axes_font_style': self.axes_font_style_dropdown.value,
'axes_font_weight': self.axes_font_weight_dropdown.value,
'axes_x_ticks': self.axes_ticks_widget.selected_values['x'],
'axes_y_ticks': self.axes_ticks_widget.selected_values['y'],
'axes_x_limits': self.axes_limits_widget.selected_values['x'],
'axes_y_limits': self.axes_limits_widget.selected_values['y']}
self.render_axes_checkbox.observe(save_options, names='value',
type='change')
self.axes_font_name_dropdown.observe(save_options, names='value',
type='change')
self.axes_font_size_text.observe(save_options, names='value',
type='change')
self.axes_font_style_dropdown.observe(save_options, names='value',
type='change')
self.axes_font_weight_dropdown.observe(save_options, names='value',
type='change')
self.axes_ticks_widget.observe(save_options, names='selected_values',
type='change')
self.axes_limits_widget.observe(save_options, names='selected_values',
type='change')
[docs] def set_widget_state(self, axes_options, allow_callback=True):
r"""
Method that updates the state of the widget if the provided
`axes_options` are different than `self.selected_values`.
Parameters
----------
axes_options : `dict`
The selected axes options. It must be a `dict` with the following
keys:
* ``render_axes`` : (`bool`) Flag for rendering the axes.
* ``axes_font_name`` : (`str`) The axes font name (e.g. ``'serif'``).
* ``axes_font_size`` : (`int`) The axes font size (e.g. ``10``).
* ``axes_font_style`` : (`str`) The axes font style
(e.g. ``'normal'``)
* ``axes_font_weight`` : (`str`) The font weight (e.g. ``'normal'``).
* ``axes_x_ticks`` : (`list` or ``None``) The x ticks
(e.g. ``[10, 20]``).
* ``axes_y_ticks`` : (`list` or ``None``) The y ticks (e.g. ``None``)
* ``axes_x_limits`` : (`float` or [`float`, `float`] or ``None``)
The x limits (e.g. ``None``).
* ``axes_y_limits`` : (`float` or [`float`, `float`] or ``None``)
The y limits (e.g. ``1.``).
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
if self.selected_values != axes_options:
# keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update
self.render_axes_checkbox.value = axes_options['render_axes']
self.axes_font_name_dropdown.value = axes_options['axes_font_name']
self.axes_font_size_text.value = axes_options['axes_font_size']
self.axes_font_style_dropdown.value = \
axes_options['axes_font_style']
self.axes_font_weight_dropdown.value = \
axes_options['axes_font_weight']
axes_ticks = {'x': axes_options['axes_x_ticks'],
'y': axes_options['axes_y_ticks']}
self.axes_ticks_widget.set_widget_state(axes_ticks,
allow_callback=False)
self.axes_limits_widget.set_widget_state(
axes_options['axes_x_limits'], axes_options['axes_y_limits'],
allow_callback=False)
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[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=''):
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'
"""
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_axes_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.axes_font_name_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.axes_font_style_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.axes_font_size_text, font_family, font_size,
font_style, font_weight)
format_font(self.axes_font_weight_dropdown, font_family, font_size,
font_style, font_weight)
self.axes_ticks_widget.style(
box_style=None, border_visible=False, font_family=font_family,
font_size=font_size, font_style=font_style,
font_weight=font_weight, toggles_style='')
self.axes_limits_widget.style(
box_style=None, border_visible=False, font_family=font_family,
font_size=font_size, font_style=font_style,
font_weight=font_weight, toggles_style='')
[docs]class LegendOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting legend rendering options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
legend_options : `dict`
The initial legend options. It must be a `dict` with the following keys:
* ``render_legend`` : (`bool`) Flag for rendering the legend.
* ``legend_title`` : (`str`) The legend title (e.g. ``''``).
* ``legend_font_name`` : (`str`) The font name (e.g. ``'serif'``).
* ``legend_font_style`` : (`str`) The font style (e.g. ``'normal'``).
* ``legend_font_size`` : (`str`) The font size (e.g. ``10``).
* ``legend_font_weight`` : (`str`) The font weight (e.g. ``'normal'``).
* ``legend_marker_scale`` : (`float`) The marker scale (e.g. ``1.``).
* ``legend_location`` : (`int`) The legend location (e.g. ``2``).
* ``legend_bbox_to_anchor`` : (`tuple`) Bbox to anchor
(e.g. ``(1.05, 1.)``).
* ``legend_border_axes_pad`` : (`float`) Border axes pad (e.g. ``1.``).
* ``legend_n_columns`` : (`int`) The number of columns (e.g. ``1``).
* ``legend_horizontal_spacing`` : (`float`) Horizontal spacing
(e.g. ``1.``).
* ``legend_vertical_spacing`` : (`float`) Vetical spacing (e.g. ``1.``).
* ``legend_border`` : (`bool`) Flag for adding border to the legend.
* ``legend_border_padding`` : (`float`) The border padding (e.g. ``0.5``)
* ``legend_shadow`` : (`bool`) Flag for adding shadow to the legend.
* ``legend_rounded_corners`` : (`bool`) Flag for adding rounded
corners to the legend.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
render_checkbox_title : `str`, optional
The description of the render legend checkbox.
"""
def __init__(self, legend_options, render_function=None,
render_checkbox_title='Render legend'):
# Create children
# render checkbox
self.render_legend_checkbox = ipywidgets.Checkbox(
description=render_checkbox_title,
value=legend_options['render_legend'], margin='0.2cm')
# font-related options and title
legend_font_name_dict = OrderedDict()
legend_font_name_dict['serif'] = 'serif'
legend_font_name_dict['sans-serif'] = 'sans-serif'
legend_font_name_dict['cursive'] = 'cursive'
legend_font_name_dict['fantasy'] = 'fantasy'
legend_font_name_dict['monospace'] = 'monospace'
self.legend_font_name_dropdown = ipywidgets.Dropdown(
options=legend_font_name_dict,
value=legend_options['legend_font_name'], description='Font')
self.legend_font_size_text = ipywidgets.BoundedIntText(
description='Size', min=0, max=10**6,
value=legend_options['legend_font_size'])
legend_font_style_dict = OrderedDict()
legend_font_style_dict['normal'] = 'normal'
legend_font_style_dict['italic'] = 'italic'
legend_font_style_dict['oblique'] = 'oblique'
self.legend_font_style_dropdown = ipywidgets.Dropdown(
options=legend_font_style_dict,
value=legend_options['legend_font_style'], description='Style')
legend_font_weight_dict = OrderedDict()
legend_font_weight_dict['normal'] = 'normal'
legend_font_weight_dict['ultralight'] = 'ultralight'
legend_font_weight_dict['light'] = 'light'
legend_font_weight_dict['regular'] = 'regular'
legend_font_weight_dict['book'] = 'book'
legend_font_weight_dict['medium'] = 'medium'
legend_font_weight_dict['roman'] = 'roman'
legend_font_weight_dict['semibold'] = 'semibold'
legend_font_weight_dict['demibold'] = 'demibold'
legend_font_weight_dict['demi'] = 'demi'
legend_font_weight_dict['bold'] = 'bold'
legend_font_weight_dict['heavy'] = 'heavy'
legend_font_weight_dict['extra bold'] = 'extra bold'
legend_font_weight_dict['black'] = 'black'
self.legend_font_weight_dropdown = ipywidgets.Dropdown(
options=legend_font_weight_dict,
value=legend_options['legend_font_weight'], description='Weight')
self.legend_title_text = ipywidgets.Text(
description='Title', value=legend_options['legend_title'],
margin='0.1cm')
self.legend_font_name_and_size_box = ipywidgets.HBox(
children=[self.legend_font_name_dropdown,
self.legend_font_size_text])
self.legend_font_style_and_weight_box = ipywidgets.HBox(
children=[self.legend_font_style_dropdown,
self.legend_font_weight_dropdown])
self.legend_font_box = ipywidgets.Box(
children=[self.legend_font_name_and_size_box,
self.legend_font_style_and_weight_box], margin='0.1cm')
self.font_related_box = ipywidgets.Box(
children=[self.legend_title_text, self.legend_font_box])
# location-related options
legend_location_dict = OrderedDict()
legend_location_dict['best'] = 0
legend_location_dict['upper right'] = 1
legend_location_dict['upper left'] = 2
legend_location_dict['lower left'] = 3
legend_location_dict['lower right'] = 4
legend_location_dict['right'] = 5
legend_location_dict['center left'] = 6
legend_location_dict['center right'] = 7
legend_location_dict['lower center'] = 8
legend_location_dict['upper center'] = 9
legend_location_dict['center'] = 10
self.legend_location_dropdown = ipywidgets.Dropdown(
options=legend_location_dict,
value=legend_options['legend_location'],
description='Anchor')
if legend_options['legend_bbox_to_anchor'] is None:
tmp1 = False
tmp2 = 0.
tmp3 = 0.
else:
tmp1 = True
tmp2 = legend_options['legend_bbox_to_anchor'][0]
tmp3 = legend_options['legend_bbox_to_anchor'][1]
self.bbox_to_anchor_enable_checkbox = ipywidgets.Checkbox(
value=tmp1, description='Offset', margin='0.1cm')
self.bbox_to_anchor_x_text = ipywidgets.FloatText(
value=tmp2, description='', width='3cm')
self.bbox_to_anchor_y_text = ipywidgets.FloatText(
value=tmp3, description='', width='3cm')
self.legend_bbox_to_anchor_x_y_box = ipywidgets.VBox(
children=[self.bbox_to_anchor_x_text, self.bbox_to_anchor_y_text],
margin='0.1cm')
self.legend_bbox_to_anchor_box = ipywidgets.HBox(
children=[self.bbox_to_anchor_enable_checkbox,
self.legend_bbox_to_anchor_x_y_box], align='start')
self.legend_border_axes_pad_text = ipywidgets.BoundedFloatText(
value=legend_options['legend_border_axes_pad'],
description='Padding', min=0.)
self.legend_location_border_axes_pad_box = ipywidgets.VBox(
children=[self.legend_location_dropdown,
self.legend_border_axes_pad_text], margin='0.1cm')
self.location_related_box = ipywidgets.HBox(
children=[self.legend_location_border_axes_pad_box,
self.legend_bbox_to_anchor_box])
# formatting related
self.legend_n_columns_text = ipywidgets.BoundedIntText(
value=legend_options['legend_n_columns'], description='Columns',
min=0, width='1.6cm')
self.legend_marker_scale_text = ipywidgets.BoundedFloatText(
description='Marker scale', width='1.6cm',
value=legend_options['legend_marker_scale'], min=0.)
self.legend_horizontal_spacing_text = ipywidgets.BoundedFloatText(
value=legend_options['legend_horizontal_spacing'],
description='Horizontal space', min=0., width='1.6cm')
self.legend_vertical_spacing_text = ipywidgets.BoundedFloatText(
value=legend_options['legend_vertical_spacing'],
description='Vertical space', min=0., width='1.6cm')
self.legend_n_columns_and_marker_scale_box = ipywidgets.VBox(
children=[self.legend_n_columns_text,
self.legend_horizontal_spacing_text], align='end')
self.legend_horizontal_and_vertical_spacing_box = ipywidgets.VBox(
children=[self.legend_marker_scale_text,
self.legend_vertical_spacing_text], align='end')
self.location_box = ipywidgets.HBox(
children=[self.legend_n_columns_and_marker_scale_box,
self.legend_horizontal_and_vertical_spacing_box],
margin='0.1cm')
self.legend_border_checkbox = ipywidgets.Checkbox(
description='Border', value=legend_options['legend_border'])
self.legend_border_padding_text = ipywidgets.BoundedFloatText(
value=legend_options['legend_border_padding'],
description='Padding', min=0., width='1.5cm')
self.border_box = ipywidgets.HBox(
children=[self.legend_border_checkbox,
self.legend_border_padding_text])
self.legend_shadow_checkbox = ipywidgets.Checkbox(
description='Shadow', value=legend_options['legend_shadow'])
self.legend_rounded_corners_checkbox = ipywidgets.Checkbox(
description='Fancy',
value=legend_options['legend_rounded_corners'])
self.shadow_fancy_border_box = ipywidgets.VBox(
children=[self.border_box, self.legend_shadow_checkbox,
self.legend_rounded_corners_checkbox], margin='0.1cm')
self.formatting_related_box = ipywidgets.HBox(
children=[self.location_box, self.shadow_fancy_border_box])
# Options widget
self.tab_box = ipywidgets.Tab(
children=[self.location_related_box, self.font_related_box,
self.formatting_related_box])
self.tab_box.set_title(0, 'Location')
self.tab_box.set_title(1, 'Font')
self.tab_box.set_title(2, 'Formatting')
# Create final widget
children = [self.render_legend_checkbox, self.tab_box]
super(LegendOptionsWidget, self).__init__(
children, Dict, legend_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def legend_options_visible(change):
self.tab_box.visible = change['new']
legend_options_visible({'new': legend_options['render_legend']})
self.render_legend_checkbox.observe(legend_options_visible,
names='value', type='change')
def border_pad_visible(change):
self.legend_border_padding_text.visible = change['new']
self.legend_border_checkbox.observe(border_pad_visible, names='value',
type='change')
def bbox_to_anchor_visible(change):
self.bbox_to_anchor_x_text.visible = change['new']
self.bbox_to_anchor_y_text.visible = change['new']
bbox_to_anchor_visible({
'new': not legend_options['legend_bbox_to_anchor'] is None})
self.bbox_to_anchor_enable_checkbox.observe(
bbox_to_anchor_visible, names='value', type='change')
def save_options(change):
legend_bbox_to_anchor = None
if self.bbox_to_anchor_enable_checkbox.value:
legend_bbox_to_anchor = (self.bbox_to_anchor_x_text.value,
self.bbox_to_anchor_y_text.value)
self.selected_values = {
'render_legend': self.render_legend_checkbox.value,
'legend_title': str(self.legend_title_text.value),
'legend_font_name': self.legend_font_name_dropdown.value,
'legend_font_style': self.legend_font_style_dropdown.value,
'legend_font_size': int(self.legend_font_size_text.value),
'legend_font_weight': self.legend_font_weight_dropdown.value,
'legend_marker_scale':
float(self.legend_marker_scale_text.value),
'legend_location': self.legend_location_dropdown.value,
'legend_bbox_to_anchor': legend_bbox_to_anchor,
'legend_border_axes_pad':
float(self.legend_border_axes_pad_text.value),
'legend_n_columns': int(self.legend_n_columns_text.value),
'legend_horizontal_spacing':
float(self.legend_horizontal_spacing_text.value),
'legend_vertical_spacing':
float(self.legend_vertical_spacing_text.value),
'legend_border': self.legend_border_checkbox.value,
'legend_border_padding':
float(self.legend_border_padding_text.value),
'legend_shadow': self.legend_shadow_checkbox.value,
'legend_rounded_corners':
self.legend_rounded_corners_checkbox.value}
self.render_legend_checkbox.observe(save_options, names='value',
type='change')
self.legend_title_text.observe(save_options, names='value',
type='change')
self.legend_font_name_dropdown.observe(save_options, names='value',
type='change')
self.legend_font_size_text.observe(save_options, names='value',
type='change')
self.legend_font_style_dropdown.observe(save_options, names='value',
type='change')
self.legend_font_weight_dropdown.observe(save_options, names='value',
type='change')
self.legend_location_dropdown.observe(save_options, names='value',
type='change')
self.bbox_to_anchor_enable_checkbox.observe(
save_options, names='value', type='change')
self.bbox_to_anchor_x_text.observe(save_options, names='value',
type='change')
self.bbox_to_anchor_y_text.observe(save_options, names='value',
type='change')
self.legend_border_axes_pad_text.observe(save_options, names='value',
type='change')
self.legend_n_columns_text.observe(save_options, names='value',
type='change')
self.legend_marker_scale_text.observe(save_options, names='value',
type='change')
self.legend_horizontal_spacing_text.observe(
save_options, names='value', type='change')
self.legend_vertical_spacing_text.observe(save_options, names='value',
type='change')
self.legend_border_checkbox.observe(save_options, names='value',
type='change')
self.legend_border_padding_text.observe(save_options, names='value',
type='change')
self.legend_shadow_checkbox.observe(save_options, names='value',
type='change')
self.legend_rounded_corners_checkbox.observe(
save_options, names='value', type='change')
[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=''):
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'
"""
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_legend_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.legend_font_name_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.legend_font_size_text, font_family, font_size,
font_style, font_weight)
format_font(self.legend_font_style_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.legend_font_weight_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.legend_title_text, font_family, font_size, font_style,
font_weight)
format_font(self.legend_location_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.bbox_to_anchor_enable_checkbox, font_family,
font_size, font_style, font_weight)
format_font(self.bbox_to_anchor_x_text, font_family, font_size,
font_style, font_weight)
format_font(self.bbox_to_anchor_y_text, font_family, font_size,
font_style, font_weight)
format_font(self.legend_border_axes_pad_text, font_family, font_size,
font_style, font_weight)
format_font(self.legend_n_columns_text, font_family, font_size,
font_style, font_weight)
format_font(self.legend_marker_scale_text, font_family, font_size,
font_style, font_weight)
format_font(self.legend_horizontal_spacing_text, font_family,
font_size, font_style, font_weight)
format_font(self.legend_vertical_spacing_text, font_family, font_size,
font_style, font_weight)
format_font(self.legend_border_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.legend_border_padding_text, font_family, font_size,
font_style, font_weight)
format_font(self.legend_shadow_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.legend_rounded_corners_checkbox, font_family,
font_size, font_style, font_weight)
[docs] def set_widget_state(self, legend_options, allow_callback=True):
r"""
Method that updates the state of the widget if the provided
`legend_options` are different than `self.selected_values`.
Parameters
----------
legend_options : `dict`
The selected legend options. It must be a `dict` with the following
keys:
* ``render_legend`` : (`bool`) Flag for rendering the legend.
* ``legend_title`` : (`str`) The legend title (e.g. ``''``).
* ``legend_font_name`` : (`str`) The font name (e.g. ``'serif'``).
* ``legend_font_style`` : (`str`) The font style (e.g. ``'normal'``).
* ``legend_font_size`` : (`str`) The font size (e.g. ``10``).
* ``legend_font_weight`` : (`str`) The font weight
(e.g. ``'normal'``).
* ``legend_marker_scale`` : (`float`) The marker scale (e.g. ``1.``).
* ``legend_location`` : (`int`) The legend location (e.g. ``2``).
* ``legend_bbox_to_anchor`` : (`tuple`) Bbox to anchor
(e.g. ``(1.05, 1.)``).
* ``legend_border_axes_pad`` : (`float`) Border axes pad
(e.g. ``1.``).
* ``legend_n_columns`` : (`int`) The number of columns (e.g. ``1``).
* ``legend_horizontal_spacing`` : (`float`) Horizontal spacing
(e.g. ``1.``).
* ``legend_vertical_spacing`` : (`float`) Vetical spacing (e.g. ``1.``)
* ``legend_border`` : (`bool`) Flag for adding border to the legend.
* ``legend_border_padding`` : (`float`) The border padding
(e.g. ``0.5``)
* ``legend_shadow`` : (`bool`) Flag for adding shadow to the legend.
* ``legend_rounded_corners`` : (`bool`) Flag for adding rounded
corners to the legend.
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
if self.selected_values != legend_options:
# keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update render legend checkbox
self.render_legend_checkbox.value = legend_options['render_legend']
# update legend_title
self.legend_title_text.value = legend_options['legend_title']
# update legend_font_name dropdown menu
self.legend_font_name_dropdown.value = \
legend_options['legend_font_name']
# update legend_font_size text box
self.legend_font_size_text.value = \
int(legend_options['legend_font_size'])
# update legend_font_style dropdown menu
self.legend_font_style_dropdown.value = \
legend_options['legend_font_style']
# update legend_font_weight dropdown menu
self.legend_font_weight_dropdown.value = \
legend_options['legend_font_weight']
# update legend_location dropdown menu
self.legend_location_dropdown.value = \
legend_options['legend_location']
# update legend_bbox_to_anchor
if legend_options['legend_bbox_to_anchor'] is None:
tmp1 = False
tmp2 = 0.
tmp3 = 0.
else:
tmp1 = True
tmp2 = legend_options['legend_bbox_to_anchor'][0]
tmp3 = legend_options['legend_bbox_to_anchor'][1]
self.bbox_to_anchor_enable_checkbox.value = tmp1
self.bbox_to_anchor_x_text.value = tmp2
self.bbox_to_anchor_y_text.value = tmp3
# update legend_border_axes_pad
self.legend_border_axes_pad_text.value = \
legend_options['legend_border_axes_pad']
# update legend_n_columns text box
self.legend_n_columns_text.value = \
int(legend_options['legend_n_columns'])
# update legend_marker_scale text box
self.legend_marker_scale_text.value = \
float(legend_options['legend_marker_scale'])
# update legend_horizontal_spacing text box
self.legend_horizontal_spacing_text.value = \
float(legend_options['legend_horizontal_spacing'])
# update legend_vertical_spacing text box
self.legend_vertical_spacing_text.value = \
float(legend_options['legend_vertical_spacing'])
# update legend_border
self.legend_border_checkbox.value = legend_options['legend_border']
# update legend_border_padding text box
self.legend_border_padding_text.value = \
float(legend_options['legend_border_padding'])
# update legend_shadow
self.legend_shadow_checkbox.value = legend_options['legend_shadow']
# update legend_rounded_corners
self.legend_rounded_corners_checkbox.value = \
legend_options['legend_rounded_corners']
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class GridOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting grid rendering options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the state of the widget, please refer to the
:meth:`set_widget_state` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
grid_options : `dict`
The initial grid options. It must be a `dict` with the following keys:
* ``render_grid`` : (`bool`) Flag for rendering the grid.
* ``grid_line_width`` : (`int`) The line width (e.g. ``1``).
* ``grid_line_style`` : (`str`) The line style (e.g. ``'-'``).
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
render_checkbox_title : `str`, optional
The description of the show line checkbox.
"""
def __init__(self, grid_options, render_function=None,
render_checkbox_title='Render grid'):
# Create children
self.render_grid_checkbox = ipywidgets.Checkbox(
description=render_checkbox_title,
value=grid_options['render_grid'])
self.grid_line_width_text = ipywidgets.BoundedFloatText(
description='Width', value=grid_options['grid_line_width'],
min=0., max=10**6)
grid_line_style_dict = OrderedDict()
grid_line_style_dict['solid'] = '-'
grid_line_style_dict['dashed'] = '--'
grid_line_style_dict['dash-dot'] = '-.'
grid_line_style_dict['dotted'] = ':'
self.grid_line_style_dropdown = ipywidgets.Dropdown(
value=grid_options['grid_line_style'], description='Style',
options=grid_line_style_dict,)
self.grid_options_box = ipywidgets.VBox(
children=[self.grid_line_style_dropdown, self.grid_line_width_text])
# Create final widget
children = [self.render_grid_checkbox, self.grid_options_box]
super(GridOptionsWidget, self).__init__(
children, Dict, grid_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def grid_options_visible(change):
self.grid_options_box.visible = change['new']
grid_options_visible({'new': grid_options['render_grid']})
self.render_grid_checkbox.observe(grid_options_visible, names='value',
type='change')
def save_options(change):
self.selected_values = {
'render_grid': self.render_grid_checkbox.value,
'grid_line_width': float(self.grid_line_width_text.value),
'grid_line_style': self.grid_line_style_dropdown.value}
self.render_grid_checkbox.observe(save_options, names='value',
type='change')
self.grid_line_width_text.observe(save_options, names='value',
type='change')
self.grid_line_style_dropdown.observe(save_options, names='value',
type='change')
[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=''):
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'
"""
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_grid_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.grid_line_style_dropdown, font_family, font_size,
font_style, font_weight)
format_font(self.grid_line_width_text, font_family, font_size,
font_style, font_weight)
[docs] def set_widget_state(self, grid_options, allow_callback=True):
r"""
Method that updates the state of the widget with a new set of values.
Parameters
----------
grid_options : `dict`
The selected grid options. It must be a `dict` with the following
keys:
* ``render_grid`` : (`bool`) Flag for rendering the grid.
* ``grid_line_width`` : (`int`) The line width (e.g. ``1``).
* ``grid_line_style`` : (`str`) The line style (e.g. ``'-'``).
allow_callback : `bool`, optional
If ``True``, it allows triggering of any callback functions.
"""
if self.selected_values != grid_options:
# keep old value
old_value = self.selected_values
# temporarily remove render callback
render_function = self._render_function
self.remove_render_function()
# update
self.render_grid_checkbox.value = grid_options['render_grid']
self.grid_line_style_dropdown.value = \
grid_options['grid_line_style']
self.grid_line_width_text.value = \
float(grid_options['grid_line_width'])
# re-assign render callback
self.add_render_function(render_function)
# trigger render function if allowed
if allow_callback:
self.call_render_function(old_value, self.selected_values)
[docs]class HOGOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting HOG options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
hog_options : `dict`
The initial options. It must be a `dict` with the following keys:
* ``mode`` : (`str`) ``'dense'`` or ``'sparse'``.
* ``algorithm`` : (`str`) ``'dalaltriggs'`` or ``'zhuramanan'``.
* ``num_bins`` : (`int`) The number of orientation bins (e.g. ``9``).
* ``cell_size`` : (`int`) The cell size in pixels (e.g. ``8``).
* ``block_size`` : (`int`) The block size in cells (e.g. ``2``).
* ``signed_gradient`` : (`bool`) Whether to use signed gradients.
* ``l2_norm_clip`` : (`float`) L2 norm clipping threshold (e.g ``0.2``).
* ``window_height`` : (`int`) The sliding window height (e.g. ``1``).
* ``window_width`` : (`int`) The sliding window width (e.g. ``1``).
* ``window_unit`` : (`str`) The window size unit (e.g. ``'blocks'``).
* ``window_step_vertical`` : (`int`) The vertical window step
(e.g. ``1``).
* ``window_step_horizontal`` : (`int`) The horizontal window step
(e.g. ``1``).
* ``window_step_unit`` : (`str`) The window step unit (e.g. ``'pixels'``)
* ``padding`` : (`bool`) Whether to pad the final image.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
"""
def __init__(self, hog_options, render_function=None):
# Window related options
tmp = OrderedDict()
tmp['Dense'] = 'dense'
tmp['Sparse'] = 'sparse'
self.mode_radiobuttons = ipywidgets.RadioButtons(
options=tmp, description='Mode', value=hog_options['mode'])
self.padding_checkbox = ipywidgets.Checkbox(
description='Padding', value=hog_options['padding'])
self.mode_padding_box = ipywidgets.HBox(
children=[self.mode_radiobuttons, self.padding_checkbox])
self.window_height_text = ipywidgets.BoundedIntText(
value=hog_options['window_height'], description='Height',
min=1, width='2cm')
self.window_width_text = ipywidgets.BoundedIntText(
value=hog_options['window_width'], description='Width',
min=1, width='2cm')
tmp = OrderedDict()
tmp['Blocks'] = 'blocks'
tmp['Pixels'] = 'pixels'
self.window_size_unit_radiobuttons = ipywidgets.RadioButtons(
options=tmp, description=' Size unit',
value=hog_options['window_unit'])
self.window_size_box = ipywidgets.VBox(
children=[self.window_height_text, self.window_width_text,
self.window_size_unit_radiobuttons])
self.window_vertical_text = ipywidgets.BoundedIntText(
value=hog_options['window_step_vertical'],
description='Step Y', min=1, width='2cm')
self.window_horizontal_text = ipywidgets.BoundedIntText(
value=hog_options['window_step_horizontal'],
description='Step X', min=1, width='2cm')
tmp = OrderedDict()
tmp['Pixels'] = 'pixels'
tmp['Cells'] = 'cells'
self.window_step_unit_radiobuttons = ipywidgets.RadioButtons(
options=tmp, description='Step unit',
value=hog_options['window_step_unit'])
self.window_step_box = ipywidgets.VBox(
children=[self.window_vertical_text, self.window_horizontal_text,
self.window_step_unit_radiobuttons])
self.window_size_step_box = ipywidgets.HBox(
children=[self.window_size_box, self.window_step_box])
self.window_box = ipywidgets.Box(children=[self.mode_padding_box,
self.window_size_step_box])
# Algorithm related options
tmp = OrderedDict()
tmp['Dalal & Triggs'] = 'dalaltriggs'
tmp['Zhu & Ramanan'] = 'zhuramanan'
self.algorithm_radiobuttons = ipywidgets.RadioButtons(
options=tmp, value=hog_options['algorithm'],
description='Algorithm')
self.cell_size_text = ipywidgets.BoundedIntText(
value=hog_options['cell_size'],
description='Cell size (in pixels)', min=1, width='1.5cm')
self.block_size_text = ipywidgets.BoundedIntText(
value=hog_options['block_size'],
description='Block size (in cells)', min=1, width='1.5cm')
self.num_bins_text = ipywidgets.BoundedIntText(
value=hog_options['num_bins'],
description='Orientation bins', min=1, width='1.5cm')
self.algorithm_sizes_box = ipywidgets.VBox(
children=[self.cell_size_text, self.block_size_text,
self.num_bins_text])
self.signed_gradient_checkbox = ipywidgets.Checkbox(
value=hog_options['signed_gradient'],
description='Gradient sign')
self.l2_norm_clipping_text = ipywidgets.BoundedFloatText(
value=hog_options['l2_norm_clip'],
description='L2 norm clipping', min=0., width='1.5cm')
self.algorithm_other_box = ipywidgets.Box(
children=[self.signed_gradient_checkbox,
self.l2_norm_clipping_text], align='end')
self.algorithm_options_box = ipywidgets.HBox(
children=[self.algorithm_sizes_box, self.algorithm_other_box])
self.algorithm_box = ipywidgets.Box(
children=[self.algorithm_radiobuttons, self.algorithm_options_box])
# Final widget
self.options_box = ipywidgets.Tab(children=[self.window_box,
self.algorithm_box])
self.options_box.set_title(0, 'Window')
self.options_box.set_title(1, 'Algorithm')
# Create final widget
children = [self.options_box]
super(HOGOptionsWidget, self).__init__(
children, Dict, hog_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def window_mode(change):
value = change['new']
self.window_horizontal_text.disabled = value == 'sparse'
self.window_vertical_text.disabled = value == 'sparse'
self.window_step_unit_radiobuttons.disabled = value == 'sparse'
self.window_height_text.disabled = value == 'sparse'
self.window_width_text.disabled = value == 'sparse'
self.window_size_unit_radiobuttons.disabled = value == 'sparse'
self.mode_radiobuttons.observe(window_mode, names='value', type='change')
# algorithm function
def algorithm_mode(change):
value = change['new']
self.l2_norm_clipping_text.disabled = value == 'zhuramanan'
self.signed_gradient_checkbox.disabled = value == 'zhuramanan'
self.block_size_text.disabled = value == 'zhuramanan'
self.num_bins_text.disabled = value == 'zhuramanan'
self.algorithm_radiobuttons.observe(algorithm_mode, names='value',
type='change')
# get options
def save_options(change):
self.selected_values = {
'mode': self.mode_radiobuttons.value,
'algorithm': self.algorithm_radiobuttons.value,
'num_bins': self.num_bins_text.value,
'cell_size': self.cell_size_text.value,
'block_size': self.block_size_text.value,
'signed_gradient': self.signed_gradient_checkbox.value,
'l2_norm_clip': self.l2_norm_clipping_text.value,
'window_height': self.window_height_text.value,
'window_width': self.window_width_text.value,
'window_unit': self.window_size_unit_radiobuttons.value,
'window_step_vertical': self.window_vertical_text.value,
'window_step_horizontal': self.window_horizontal_text.value,
'window_step_unit': self.window_step_unit_radiobuttons.value,
'padding': self.padding_checkbox.value}
self.mode_radiobuttons.observe(save_options, names='value',
type='change')
self.padding_checkbox.observe(save_options, names='value', type='change')
self.window_height_text.observe(save_options, names='value',
type='change')
self.window_width_text.observe(save_options, names='value',
type='change')
self.window_size_unit_radiobuttons.observe(
save_options, names='value', type='change')
self.window_vertical_text.observe(save_options, names='value',
type='change')
self.window_horizontal_text.observe(save_options, names='value',
type='change')
self.window_step_unit_radiobuttons.observe(
save_options, names='value', type='change')
self.algorithm_radiobuttons.observe(save_options, names='value',
type='change')
self.num_bins_text.observe(save_options, names='value', type='change')
self.cell_size_text.observe(save_options, names='value', type='change')
self.block_size_text.observe(save_options, names='value', type='change')
self.signed_gradient_checkbox.observe(save_options, names='value',
type='change')
self.l2_norm_clipping_text.observe(save_options, names='value',
type='change')
[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=''):
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'
"""
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.options_box, font_family, font_size, font_style,
font_weight)
format_font(self.mode_radiobuttons, font_family, font_size, font_style,
font_weight)
format_font(self.padding_checkbox, font_family, font_size, font_style,
font_weight)
format_font(self.window_height_text, font_family, font_size, font_style,
font_weight)
format_font(self.window_width_text, font_family, font_size, font_style,
font_weight)
format_font(self.window_size_unit_radiobuttons, font_family, font_size,
font_style, font_weight)
format_font(self.window_vertical_text, font_family, font_size,
font_style, font_weight)
format_font(self.window_horizontal_text, font_family, font_size,
font_style, font_weight)
format_font(self.window_step_unit_radiobuttons, font_family, font_size,
font_style, font_weight)
format_font(self.algorithm_radiobuttons, font_family, font_size,
font_style, font_weight)
format_font(self.cell_size_text, font_family, font_size, font_style,
font_weight)
format_font(self.block_size_text, font_family, font_size, font_style,
font_weight)
format_font(self.num_bins_text, font_family, font_size, font_style,
font_weight)
format_font(self.signed_gradient_checkbox, font_family, font_size,
font_style, font_weight)
format_font(self.l2_norm_clipping_text, font_family, font_size,
font_style, font_weight)
[docs]class DSIFTOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting desnse SIFT options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
dsift_options : `dict`
The initial options. It must be a `dict` with the following keys:
* ``window_step_horizontal`` : (`int`) The horizontal window step
(e.g. ``1``).
* ``window_step_vertical`` : (`int`) The vertical window step
(e.g. ``1``).
* ``num_bins_horizontal`` : (`int`) The horizontal number of spatial bins
(e.g. ``2``).
* ``num_bins_vertical`` : (`int`) The vertical number of spatial bins
(e.g. ``2``).
* ``num_or_bins`` : (`int`) The number of orientation bins (e.g. ``9``).
* ``cell_size_horizontal`` : (`int`) The horizontal cell size in pixels
(e.g. ``6``).
* ``cell_size_vertical`` : (`int`) The vertical cell size in pixels
(e.g. ``6``).
* ``fast`` : (`bool`) Flag for fast approximation.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
"""
def __init__(self, dsift_options, render_function=None):
# Create widgets
self.window_vertical_text = ipywidgets.BoundedIntText(
value=dsift_options['window_step_vertical'],
description='Step Y', min=1, width='2cm')
self.window_horizontal_text = ipywidgets.BoundedIntText(
value=dsift_options['window_step_horizontal'],
description='Step X', min=1, width='2cm')
self.fast_checkbox = ipywidgets.Checkbox(
value=dsift_options['fast'],
description='Fast computation')
self.cell_size_vertical_text = ipywidgets.BoundedIntText(
value=dsift_options['cell_size_vertical'],
description='Cell size Y', min=1, width='2cm')
self.cell_size_horizontal_text = ipywidgets.BoundedIntText(
value=dsift_options['cell_size_horizontal'],
description='Cell size X', min=1, width='2cm')
self.num_bins_vertical_text = ipywidgets.BoundedIntText(
value=dsift_options['num_bins_vertical'],
description='Bins Y', min=1, width='2cm')
self.num_bins_horizontal_text = ipywidgets.BoundedIntText(
value=dsift_options['num_bins_horizontal'],
description='Bins X', min=1, width='2cm')
self.num_or_bins_text = ipywidgets.BoundedIntText(
value=dsift_options['num_or_bins'],
description='Orientation bins', min=1, width='2cm')
# Final widget
self.window_step_box = ipywidgets.VBox(
children=[self.window_vertical_text, self.window_horizontal_text,
self.fast_checkbox])
self.cell_size_box = ipywidgets.VBox(
children=[self.cell_size_vertical_text,
self.cell_size_horizontal_text])
self.num_bins_box = ipywidgets.VBox(
children=[self.num_bins_vertical_text,
self.num_bins_horizontal_text, self.num_or_bins_text])
self.options_box = ipywidgets.HBox(children=[self.window_step_box,
self.cell_size_box,
self.num_bins_box])
# Create final widget
children = [self.options_box]
super(DSIFTOptionsWidget, self).__init__(
children, Dict, dsift_options, render_function=render_function,
orientation='horizontal', align='start')
# Get options
def save_options(change):
self.selected_values = {
'window_step_horizontal': self.window_horizontal_text.value,
'window_step_vertical': self.window_vertical_text.value,
'num_bins_horizontal': self.num_bins_horizontal_text.value,
'num_bins_vertical': self.num_bins_vertical_text.value,
'num_or_bins': self.num_or_bins_text.value,
'cell_size_horizontal': self.cell_size_horizontal_text.value,
'cell_size_vertical': self.cell_size_vertical_text.value,
'fast': self.fast_checkbox.value}
self.window_vertical_text.observe(save_options, names='value',
type='change')
self.window_horizontal_text.observe(save_options, names='value',
type='change')
self.num_bins_vertical_text.observe(save_options, names='value',
type='change')
self.num_bins_horizontal_text.observe(save_options, names='value',
type='change')
self.num_or_bins_text.observe(save_options, names='value', type='change')
self.cell_size_vertical_text.observe(save_options, names='value',
type='change')
self.cell_size_horizontal_text.observe(save_options, names='value',
type='change')
self.fast_checkbox.observe(save_options, names='value', type='change')
[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=''):
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'
"""
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.options_box, font_family, font_size, font_style,
font_weight)
format_font(self.window_vertical_text, font_family, font_size,
font_style, font_weight)
format_font(self.window_horizontal_text, font_family, font_size,
font_style, font_weight)
format_font(self.num_bins_vertical_text, font_family, font_size,
font_style, font_weight)
format_font(self.num_bins_horizontal_text, font_family, font_size,
font_style, font_weight)
format_font(self.num_or_bins_text, font_family, font_size, font_style,
font_weight)
format_font(self.cell_size_vertical_text, font_family, font_size,
font_style, font_weight)
format_font(self.cell_size_horizontal_text, font_family, font_size,
font_style, font_weight)
format_font(self.fast_checkbox, font_family, font_size, font_style,
font_weight)
[docs]class DaisyOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting Daisy options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
daisy_options : `dict`
The initial options. It must be a `dict` with the following keys:
* ``step`` : (`int`) The sampling step (e.g. ``1``).
* ``radius`` : (`int`) The radius value (e.g. ``15``).
* ``rings`` : (`int`) The number of rings (e.g. ``2``).
* ``histograms`` : (`int`) The number of histograms (e.g. ``2``).
* ``orientations`` : (`int`) The number of orientation bins (e.g. ``8``).
* ``normalization`` : (`str`) The normalisation method (e.g. ``'l1'``).
* ``sigmas`` : (`list` or ``None``)
* ``ring_radii`` : (`list` or ``None``)
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
"""
def __init__(self, daisy_options, render_function=None):
self.step_text = ipywidgets.BoundedIntText(
value=daisy_options['step'], description='Step', min=1,
max=10**6, width='1.6cm')
self.radius_text = ipywidgets.BoundedIntText(
value=daisy_options['radius'], description='Radius', min=1,
max=10**6, width='1.6cm')
self.rings_text = ipywidgets.BoundedIntText(
value=daisy_options['rings'], description='Rings', min=1,
max=10**6, width='1.6cm')
self.histograms_text = ipywidgets.BoundedIntText(
value=daisy_options['histograms'], description='Histograms',
min=1, max=10**6, width='1.6cm')
self.orientations_text = ipywidgets.BoundedIntText(
value=daisy_options['orientations'], description='Orientations',
min=1, max=10**6, width='1.6cm')
tmp = OrderedDict()
tmp['L1'] = 'l1'
tmp['L2'] = 'l2'
tmp['Daisy'] = 'daisy'
tmp['None'] = None
self.normalization_dropdown = ipywidgets.Dropdown(
value=daisy_options['normalization'], options=tmp,
description='Normalisation')
init_sigmas = daisy_options['sigmas']
if init_sigmas is None:
init_sigmas = []
self.sigmas_wid = ListWidget(
init_sigmas, mode='float', description='Sigmas',
render_function=None, example_visible=False)
init_ring = daisy_options['ring_radii']
if init_ring is None:
init_ring = []
self.ring_radii_wid = ListWidget(
init_ring, mode='float', description='Ring radii',
render_function=None, example_visible=False)
self.step_radius_rings_histograms_box = ipywidgets.VBox(
children=[self.step_text, self.radius_text, self.rings_text,
self.histograms_text])
self.orientations_normalization_sigmas_radii_box = ipywidgets.VBox(
children=[self.orientations_text, self.normalization_dropdown,
self.sigmas_wid, self.ring_radii_wid])
# Create final widget
children = [self.step_radius_rings_histograms_box,
self.orientations_normalization_sigmas_radii_box]
super(DaisyOptionsWidget, self).__init__(
children, Dict, daisy_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def save_options(change):
sigmas_val = self.sigmas_wid.selected_values
if len(sigmas_val) == 0:
sigmas_val = None
ring_radii_val = self.ring_radii_wid.selected_values
if len(ring_radii_val) == 0:
ring_radii_val = None
self.selected_values = {
'step': self.step_text.value,
'radius': self.radius_text.value,
'rings': self.rings_text.value,
'histograms': self.histograms_text.value,
'orientations': self.orientations_text.value,
'normalization': self.normalization_dropdown.value,
'sigmas': sigmas_val,
'ring_radii': ring_radii_val}
self.step_text.observe(save_options, names='value', type='change')
self.radius_text.observe(save_options, names='value', type='change')
self.rings_text.observe(save_options, names='value', type='change')
self.histograms_text.observe(save_options, names='value', type='change')
self.orientations_text.observe(save_options, names='value',
type='change')
self.normalization_dropdown.observe(save_options, names='value',
type='change')
self.sigmas_wid.observe(save_options, names='selected_values',
type='change')
self.ring_radii_wid.observe(save_options, names='selected_values',
type='change')
[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=''):
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'
"""
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.step_text, font_family, font_size, font_style,
font_weight)
format_font(self.radius_text, font_family, font_size, font_style,
font_weight)
format_font(self.rings_text, font_family, font_size, font_style,
font_weight)
format_font(self.histograms_text, font_family, font_size, font_style,
font_weight)
format_font(self.orientations_text, font_family, font_size, font_style,
font_weight)
format_font(self.normalization_dropdown, font_family, font_size,
font_style, font_weight)
self.sigmas_wid.style(box_style=None, border_visible=False,
font_family=font_family, font_size=font_size,
font_style=font_style, font_weight=font_weight)
self.ring_radii_wid.style(box_style=None, border_visible=False,
font_family=font_family, font_size=font_size,
font_style=font_style,
font_weight=font_weight)
[docs]class LBPOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting LBP options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
lbp_options : `dict`
The initial options. It must be a `dict` with the following keys:
* ``radius`` : (`list`) The radius values list (e.g. ``[0, 1, 2, 3]``).
* ``samples`` : (`list`) The sampling poitns list (e.g. ``[8] * 4``).
* ``mapping_type`` : (`str`) The mapping type (e.g. ``'u2'``).
* ``window_step_vertical`` : (`int`) The vertical window step
(e.g. ``1``),
* ``window_step_horizontal`` : (`int`) The horizontal window step
(e.g. ``1``)
* ``window_step_unit`` : (`str`) The window step unit (e.g. ``'pixels'``)
* ``padding`` : (`bool`) Whether to pad the final image.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
"""
def __init__(self, lbp_options, render_function=None):
# Create children
tmp = OrderedDict()
tmp['Uniform-2'] = 'u2'
tmp['Rotation-Invariant'] = 'ri'
tmp['Both'] = 'riu2'
tmp['None'] = 'none'
self.mapping_type_dropdown = ipywidgets.Dropdown(
value=lbp_options['mapping_type'], options=tmp,
description='Mapping')
self.radius_wid = ListWidget(
lbp_options['radius'], mode='int', description='Radius',
render_function=None, example_visible=False)
self.samples_wid = ListWidget(
lbp_options['samples'], mode='int', description='Samples',
render_function=None, example_visible=False)
self.radius_samples_mapping_type_box = ipywidgets.VBox(
children=[self.radius_wid, self.samples_wid,
self.mapping_type_dropdown])
self.window_vertical_text = ipywidgets.BoundedIntText(
value=lbp_options['window_step_vertical'], description='Step Y',
min=1, max=10**6, width='1.5cm')
self.window_horizontal_text = ipywidgets.BoundedIntText(
value=lbp_options['window_step_horizontal'], description='Step X',
min=1, max=10**6, width='1.5cm')
tmp = OrderedDict()
tmp['Pixels'] = 'pixels'
tmp['Windows'] = 'cells'
self.window_step_unit_radiobuttons = ipywidgets.RadioButtons(
options=tmp, description='Step unit',
value=lbp_options['window_step_unit'])
self.padding_checkbox = ipywidgets.Checkbox(
value=lbp_options['padding'], description='Padding')
self.window_box = ipywidgets.Box(
children=[self.window_vertical_text, self.window_horizontal_text,
self.window_step_unit_radiobuttons,
self.padding_checkbox])
# Create final widget
children = [self.window_box, self.radius_samples_mapping_type_box]
super(LBPOptionsWidget, self).__init__(
children, Dict, lbp_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def save_options(change):
self.selected_values = {
'radius': self.radius_wid.selected_values,
'samples': self.samples_wid.selected_values,
'mapping_type': self.mapping_type_dropdown.value,
'window_step_vertical': self.window_vertical_text.value,
'window_step_horizontal': self.window_horizontal_text.value,
'window_step_unit': self.window_step_unit_radiobuttons.value,
'padding': self.padding_checkbox.value}
self.mapping_type_dropdown.observe(save_options, names='value',
type='change')
self.window_vertical_text.observe(save_options, names='value',
type='change')
self.window_horizontal_text.observe(save_options, names='value',
type='change')
self.window_step_unit_radiobuttons.observe(
save_options, names='value', type='change')
self.padding_checkbox.observe(save_options, names='value', type='change')
self.radius_wid.observe(save_options, names='selected_values',
type='change')
self.samples_wid.observe(save_options, names='selected_values',
type='change')
[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=''):
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'
"""
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.mapping_type_dropdown, font_family, font_size,
font_style, font_weight)
self.radius_wid.style(box_style=None, border_visible=False,
font_family=font_family, font_size=font_size,
font_style=font_style, font_weight=font_weight)
self.samples_wid.style(box_style=None, border_visible=False,
font_family=font_family, font_size=font_size,
font_style=font_style, font_weight=font_weight)
format_font(self.window_vertical_text, font_family, font_size,
font_style, font_weight)
format_font(self.window_horizontal_text, font_family, font_size,
font_style, font_weight)
format_font(self.window_step_unit_radiobuttons, font_family, font_size,
font_style, font_weight)
format_font(self.padding_checkbox, font_family, font_size, font_style,
font_weight)
[docs]class IGOOptionsWidget(MenpoWidget):
r"""
Creates a widget for selecting IGO options.
* The selected values are stored in the ``self.selected_values`` `trait`.
* To set the styling of this widget please refer to the :meth:`style` method.
* To update the handler callback function of the widget, please refer to the
:meth:`replace_render_function` method.
Parameters
----------
igo_options : `dict`
The initial options. It must be a `dict` with the following keys:
* ``double_angles`` : (`bool`) Whether to use the cos and sin of the
double angles as well.
render_function : `callable` or ``None``, optional
The render function that is executed when a widgets' value changes.
If ``None``, then nothing is assigned.
"""
def __init__(self, igo_options, render_function=None):
self.double_angles_checkbox = ipywidgets.Checkbox(
value=igo_options['double_angles'], description='Double angles')
# Create final widget
children = [self.double_angles_checkbox]
super(IGOOptionsWidget, self).__init__(
children, Dict, igo_options, render_function=render_function,
orientation='horizontal', align='start')
# Set functionality
def save_options(change):
self.selected_values = {'double_angles': change['new']}
self.double_angles_checkbox.observe(save_options, names='value',
type='change')
[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=''):
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'
"""
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.double_angles_checkbox, font_family, font_size,
font_style, font_weight)
[docs]class CameraWidget(ipywidgets.DOMWidget):
r"""
Creates a webcam widget.
Parameters
----------
canvas_width : `int`, optional
The initial width of the rendered canvas. Note that this doesn't actually
change the webcam resolution. It simply rescales the rendered image, as
well as the size of the returned screenshots.
hd : `bool`, optional
If ``True``, then the webcam will be set to high definition (HD), i.e.
720 x 1280. Otherwise the default resolution will be used.
"""
_view_name = Unicode('CameraView').tag(sync=True)
imageurl = Unicode('').tag(sync=True)
take_snapshot = Bool(False).tag(sync=True)
canvas_width = Int(640).tag(sync=True)
canvas_height = Int().tag(sync=True)
hd = Bool(True).tag(sync=True)
snapshots = List().tag(sync=True)
def __init__(self, canvas_width=640, hd=True, *args):
super(CameraWidget, self).__init__(*args)
# Set tait values
self.canvas_width = canvas_width
self.hd = hd
# Assign callback to imageurl trait
self.observe(self._from_data_url, names='imageurl', type='change')
@staticmethod
def _from_data_url(change):
r"""
Method that converts the image in `imageurl` to `menpo.image.Image`
and appends it to `self.snapshots`.
"""
self = change['owner']
data_uri = change['new']
data_uri = data_uri.encode('utf-8')
data_uri = data_uri[len('data:image/png;base64,'):]
im = PILImage.open(BytesIO(b64decode(data_uri)))
self.snapshots.append(
Image.init_from_channels_at_back(np.array(im)[..., :3]))