from collections import OrderedDict
from StringIO import StringIO


# Global variables to try and reduce overhead of loading the logo
MENPO_LOGO = None
MENPO_LOGO_SCALE = None


def logo(scale=0.3):
    r"""
    Creates a widget with Menpo Logo Image.

    The structure of the widgets is the following:
        logo.children = [logo_image_widget]

    To fix the alignment within this widget please refer to `format_logo()`
    function.

    Parameters
    ----------
    scale : `float`, optional
        Defines the scale that will be applied to the logo image
        (data/menpo_thumbnail.jpg).
    """
    import IPython.html.widgets as ipywidgets
    # Try only load the logo once
    global MENPO_LOGO, MENPO_LOGO_SCALE
    if MENPO_LOGO is None or scale != MENPO_LOGO_SCALE:
        import menpo.io as mio

        image = mio.import_builtin_asset.menpo_thumbnail_jpg()
        MENPO_LOGO = image.rescale(scale)
        MENPO_LOGO_SCALE = scale
    logo_wid = ipywidgets.ImageWidget(value=_convert_image_to_bytes(MENPO_LOGO))
    return ipywidgets.ContainerWidget(children=[logo_wid])


def format_logo(logo_wid, container_border='1px solid black',
                border_visible=True):
    r"""
    Function that adds an optional border line arounf the logo widget. Usage
    example:
        logo_wid = logo()
        display(logo_wid)
        format_logo(logo_wid)

    Parameters
    ----------
    logo_wid :
        The widget object generated by the `logo()` function.
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    """
    if border_visible:
        logo_wid.set_css('border', container_border)


def index_selection_slider(index_selection_default, plot_function=None,
                           update_function=None, description='Image Number:'):
    r"""
    Creates a widget for selecting an index. Specifically, it has:
        1) A slider.

    The structure of the widget is the following:
        index_wid = slider

    The returned widget saves the selected values in the following dictionary:
        index_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_index_selection()` function.

    Parameters
    ----------
    index_selection_default : `dict`
        The dictionary with the default options. For example:
            index_selection_default = {'min':0,
                                       'max':100,
                                       'step':1,
                                       'index':10}
    plot_function : `function` or None, optional
        The plot function that is executed when the index value changes.
        If None, then nothing is assigned.
    update_function : `function` or None, optional
        The update function that is executed when the index value changes.
        If None, then nothing is assigned.
    description : `str`, optional
        The title of the widget.
    """
    import IPython.html.widgets as ipywidgets
    # Create widget
    index_wid = ipywidgets.IntSliderWidget(min=index_selection_default['min'],
                                           max=index_selection_default['max'],
                                           value=index_selection_default[
                                               'index'],
                                           step=index_selection_default['step'],
                                           description=description)

    # Assign output
    index_wid.selected_values = index_selection_default

    # Save index
    def save_index(name, value):
        index_wid.selected_values['index'] = value
    index_wid.on_trait_change(save_index, 'value')

    # assign given update_function
    if update_function is not None:
        index_wid.on_trait_change(update_function, 'value')

    # assign given plot_function
    if plot_function is not None:
        index_wid.on_trait_change(plot_function, 'value')

    return index_wid


def index_selection_buttons(index_selection_default, plot_function=None,
                            update_function=None, description='Image Number:',
                            minus_description='-', plus_description='+',
                            loop=True, text_editable=True):
    r"""
    Creates a widget for selecting an index. Specifically, it has:
        1) Two buttons to increase and decrease the index.
        2) A text area with the selected widget. It can either be editable or
           not.

    The structure of the widget is the following:
        index_wid = [title, minus_button, text, plus_button]

    The returned widget saves the selected values in the following dictionary:
        index_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_index_selection()` function.

    Parameters
    ----------
    index_selection_default : `dict`
        The dictionary with the default options. For example:
            index_selection_default = {'min':0,
                                       'max':100,
                                       'step':1,
                                       'index':10}
    plot_function : `function` or None, optional
        The plot function that is executed when the index value changes.
        If None, then nothing is assigned.
    update_function : `function` or None, optional
        The update 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 title of the button that decreases the index.
    plus_description : `str`, optional
        The title of the button that increases the index.
    loop : `boolean`, optional
        If True, 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 : `boolean`, optional
        Flag that determines whether the index text will be editable.
    """
    import IPython.html.widgets as ipywidgets
    # Create widgets
    tlt = ipywidgets.LatexWidget(value=description)
    but_minus = ipywidgets.ButtonWidget(description=minus_description)
    but_plus = ipywidgets.ButtonWidget(description=plus_description)
    val = ipywidgets.IntTextWidget(value=index_selection_default['index'],
                                   disabled=not text_editable)
    index_wid = ipywidgets.ContainerWidget(children=[tlt, but_minus, val,
                                                     but_plus])

    # Assign output
    index_wid.selected_values = index_selection_default

    # plus button pressed
    def change_value_plus(name):
        tmp_val = int(val.value) + index_wid.selected_values['step']
        if tmp_val > index_wid.selected_values['max']:
            if loop:
                val.value = str(index_wid.selected_values['min'])
            else:
                val.value = str(index_wid.selected_values['max'])
        else:
            val.value = str(tmp_val)
    but_plus.on_click(change_value_plus)

    # minus button pressed
    def change_value_minus(name):
        tmp_val = int(val.value) - index_wid.selected_values['step']
        if tmp_val < index_wid.selected_values['min']:
            if loop:
                val.value = str(index_wid.selected_values['max'])
            else:
                val.value = str(index_wid.selected_values['min'])
        else:
            val.value = str(tmp_val)

    but_minus.on_click(change_value_minus)

    # Save index
    def save_index(name, old_value, value):
        tmp_val = int(value)
        if (tmp_val > index_wid.selected_values['max'] or
            tmp_val < index_wid.selected_values['min']):
            val.value = int(old_value)
        index_wid.selected_values['index'] = tmp_val

    val.on_trait_change(save_index, 'value')

    # assign given update_function
    if update_function is not None:
        val.on_trait_change(update_function, 'value')

    # assign given plot_function
    if plot_function is not None:
        val.on_trait_change(plot_function, 'value')

    return index_wid


def format_index_selection(index_wid, text_width='0.5cm'):
    r"""
    Function that corrects the align (style format) of a given index_selection
    widget. It can be used with both `index_selection_buttons()` and
    `index_selection_slider()` functions. Usage example:
        index_wid = index_selection_buttons()
        display(index_wid)
        format_index_selection(index_wid)

    Parameters
    ----------
    index_wid :
        The widget object generated by either the `index_selection_buttons()`
        or the `index_selection_slider()` function.
    text_width : `str`, optional
        The width of the index text area in the case of
        `index_selection_buttons()`.
    """
    import IPython.html.widgets as ipywidgets

    if not isinstance(index_wid, ipywidgets.IntSliderWidget):
        # align all widgets
        index_wid.remove_class('vbox')
        index_wid.add_class('hbox')
        index_wid.add_class('align-center')

        # set text width
        index_wid.children[2].set_css('width', text_width)
        index_wid.children[2].add_class('center')

        # set margins
        index_wid.children[0].set_css('margin-right', '6px')


def update_index_selection(index_wid, index_selection_default,
                           plot_function=None, update_function=None):
    r"""
    Function that updates the state of a given index_selection widget if the
    index bounds have changed. It can be used with both
    `index_selection_buttons()` and `index_selection_slider()` functions. Usage
    example:
        index_selection_default = {'min':0,
                                   'max':100,
                                   'step':1,
                                   'index':10}
        index_wid = index_selection_buttons(index_selection_default)
        display(index_wid)
        format_index_selection(index_wid)
        index_selection_default = {'min':0,
                                   'max':10,
                                   'step':5,
                                   'index':5}
        update_index_selection(index_wid, index_selection_default)

    Parameters
    ----------
    index_wid :
        The widget object generated by either the `index_selection_buttons()`
        or the `index_selection_slider()` function.
    index_selection_default : `dict`
        The dictionary with the default options. For example:
            index_selection_default = {'min':0,
                                       'max':100,
                                       'step':1,
                                       'index':10}
    plot_function : `function` or None, optional
        The plot function that is executed when the index value changes.
        If None, then nothing is assigned.
    update_function : `function` or None, optional
        The update function that is executed when the index value changes.
        If None, then nothing is assigned.
    """
    import IPython.html.widgets as ipywidgets
    # check if update is required
    index_wid_selected = index_wid.selected_values
    if not (index_selection_default['min'] == index_wid_selected['min'] and
            index_selection_default['max'] == index_wid_selected['max'] and
            index_selection_default['step'] == index_wid_selected['step'] and
            index_selection_default['index'] == index_wid_selected['index']):
        if isinstance(index_wid, ipywidgets.IntSliderWidget):
            # created by `index_selection_slider()` function
            index_wid.min = index_selection_default['min']
            index_wid.max = index_selection_default['max']
            index_wid.step = index_selection_default['step']
            index_wid.value = index_selection_default['index']
            # assign given update_function
            if update_function is not None:
                index_wid.on_trait_change(update_function, 'value')
            # assign given plot_function
            if plot_function is not None:
                index_wid.on_trait_change(plot_function, 'value')
        else:
            # created by `index_selection_buttons()` function
            index_wid.children[2].value = str(index_selection_default['index'])
            # assign given update_function
            if update_function is not None:
                index_wid.children[2].on_trait_change(update_function, 'value')
            # assign given plot_function
            if plot_function is not None:
                index_wid.children[2].on_trait_change(plot_function, 'value')

    # Assign new options dict to selected_values
    index_wid.selected_values = index_selection_default


def _decode_colour(colour):
    r_val = g_val = b_val = 0.
    if not isinstance(colour, str):
        r_val = colour[0]
        g_val = colour[1]
        b_val = colour[2]
        colour = 'custom'
    return colour, r_val, g_val, b_val


def colour_selection(default_colour_list, plot_function=None, title='Colour',
                     labels=None):
    r"""
    Creates a widget with Colour Selection Options. Specifically, it has:
        1) A label selection if more than one colours are provided.
        2) An 'apply to all labels' button.
        3) A drop down menu with predefined colours and a 'custom' entry.
        4) If 'custom is selected, then three float text boxes appear to enter
           the desired RGB values.

    The structure of the widgets is the following:
        colour_selection_wid.children = [labels, drop_down_menu, rgb]
        labels.children = [selection_dropdown, apply_to_all_button]
        rgb.children = [r_value, g_value, b_value]

    The returned widget saves the selected values in the following list:
        colour_selection_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_colour_selection()` function.

    To update the state of this widget, please refer to
    `update_colour_selection()` function.

    Parameters
    ----------
    default_colour_list : `list` of `str` or [`float`, `float`, `float`]
        If `str`, it must be one of {'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'}.
        If [`float`, `float`, `float`], it defines an RGB value and must have
        length 3.
    plot_function : `function` or None, optional
        The plot function that is executed when a widgets' value changes.
        If None, then nothing is assigned.
    title : `str`, optional
        The description of the drop down menu.
    labels : `list`, optional
        A list with the labels' names.
    """
    import IPython.html.widgets as ipywidgets
    # check if multiple mode should be enabled
    n_labels = len(default_colour_list)
    multiple = n_labels > 1

    # colours dictionary
    colour_dict = OrderedDict()
    colour_dict['blue'] = 'b'
    colour_dict['green'] = 'g'
    colour_dict['red'] = 'r'
    colour_dict['cyan'] = 'c'
    colour_dict['magenta'] = 'm'
    colour_dict['yellow'] = 'y'
    colour_dict['black'] = 'k'
    colour_dict['white'] = 'w'
    colour_dict['custom'] = 'custom'

    # Labels dropdown menu
    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
    selection = ipywidgets.DropdownWidget(values=labels_dict, value=0)
    apply_to_all = ipywidgets.ButtonWidget(description='apply to all labels')
    labels_wid = ipywidgets.ContainerWidget(children=[selection, apply_to_all],
                                            visible=multiple)

    # find default values
    default_colour, r_val, g_val, b_val = _decode_colour(default_colour_list[0])

    # create widgets
    r_wid = ipywidgets.BoundedFloatTextWidget(value=r_val, description='RGB',
                                              min=0.0,
                                              max=1.0)
    g_wid = ipywidgets.BoundedFloatTextWidget(value=g_val, min=0.0, max=1.0)
    b_wid = ipywidgets.BoundedFloatTextWidget(value=b_val, min=0.0, max=1.0)
    menu = ipywidgets.DropdownWidget(values=colour_dict, value=default_colour,
                                     description='')
    rgb = ipywidgets.ContainerWidget(children=[r_wid, g_wid, b_wid])

    if multiple:
        selection.description = title
    else:
        menu.description = title

    # Final widget
    colour_selection_wid = ipywidgets.ContainerWidget(
        children=[labels_wid, menu, rgb])

    # Assign output
    colour_selection_wid.selected_values = {'colour': default_colour_list,
                                            'labels': labels}

    # control visibility
    def show_rgb(name, value):
        if value == 'custom':
            rgb.visible = True
        else:
            rgb.visible = False
    show_rgb('', default_colour)
    menu.on_trait_change(show_rgb, 'value')

    # functions in case of multiple
    def apply_to_all_function(name):
        if menu.value == 'custom':
            tmp = [r_wid.value, g_wid.value, b_wid.value]
        else:
            tmp = menu.value
        for idx in range(len(colour_selection_wid.selected_values['colour'])):
            colour_selection_wid.selected_values['colour'][idx] = tmp
        if selection.value == 0:
            selection.value = 1
        else:
            selection.value = 0

    apply_to_all.on_click(apply_to_all_function)

    def selection_function(name, value):
        colour, r_val, g_val, b_val = _decode_colour(
            colour_selection_wid.selected_values['colour'][value])
        menu.value = colour
        r_wid.value = r_val
        g_wid.value = g_val
        b_wid.value = b_val

    selection.on_trait_change(selection_function, 'value')

    # save colour
    def get_colour(name, value):
        idx = selection.value
        if menu.value == 'custom':
            colour_selection_wid.selected_values['colour'][idx] = [r_wid.value,
                                                                   g_wid.value,
                                                                   b_wid.value]
        else:
            colour_selection_wid.selected_values['colour'][idx] = menu.value
    menu.on_trait_change(get_colour, 'value')
    r_wid.on_trait_change(get_colour, 'value')
    g_wid.on_trait_change(get_colour, 'value')
    b_wid.on_trait_change(get_colour, 'value')

    # assign plot function
    if plot_function is not None:
        menu.on_trait_change(plot_function, 'value')
        r_wid.on_trait_change(plot_function, 'value')
        g_wid.on_trait_change(plot_function, 'value')
        b_wid.on_trait_change(plot_function, 'value')

        def tmp_plot_function(name):
            plot_function('', True)
        apply_to_all.on_click(tmp_plot_function)

    return colour_selection_wid


def format_colour_selection(colour_selection_wid):
    r"""
    Function that corrects the align (style format) of a given colour_selection
    widget. Usage example:
        colour_selection_wid = colour_selection(['r'])
        display(colour_selection_wid)
        format_colour_selection(colour_selection_wid)

    Parameters
    ----------
    colour_selection_wid :
        The widget object generated by the `colour_selection()` function.
    """
    # align selection container and colour
    colour_selection_wid.add_class('align-end')

    # align r, g, b values
    colour_selection_wid.children[2].remove_class('vbox')
    colour_selection_wid.children[2].add_class('hbox')
    colour_selection_wid.children[2].add_class('align-start')

    # set width of r, g, b
    colour_selection_wid.children[2].children[0].set_css('width', '0.5cm')
    colour_selection_wid.children[2].children[1].set_css('width', '0.5cm')
    colour_selection_wid.children[2].children[2].set_css('width', '0.5cm')

    # align label selection and apply to all button
    colour_selection_wid.children[0].add_class('align-end')


def update_colour_selection(colour_selection_wid, default_colour_list,
                            labels=None):
    r"""
    Function that updates the state of a given colour_selection widget. Usage
    example:
        colour_selection_wid = colour_selection(default_colour_list=['r', 'b'],
                                                labels=['jaw', 'mouth'])
        display(colour_selection_wid)
        format_colour_selection(colour_selection_wid)
        update_colour_selection(colour_selection_wid,
                                default_colour_list=[[0.5, 0.7, 1.0]],
                                labels=['all'])

    Parameters
    ----------
    colour_selection_wid :
        The widget object generated by the `colour_selection()` function.
    default_colour_list : `list` of `str` or [`float`, `float`, `float`]
        If `str`, it must be one of {'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'}.
        If [`float`, `float`, `float`], it defines an RGB value and must have
        length 3.
    labels : `list`, optional
        A list with the labels' names.
    """
    if labels is None:
        labels = colour_selection_wid.selected_values['labels']

    sel_colours = colour_selection_wid.selected_values['colour']
    sel_labels = colour_selection_wid.selected_values['labels']
    if (_lists_are_the_same(sel_colours, default_colour_list) and not
        _lists_are_the_same(sel_labels, labels)):
        # the provided colours are the same, but the labels changed, so update
        # the labels
        colour_selection_wid.selected_values['labels'] = labels
        labels_dict = OrderedDict()
        for k, l in enumerate(labels):
            labels_dict[l] = k
        colour_selection_wid.children[0].children[0].values = labels_dict
        colour_selection_wid.children[0].children[0].value = 0
    elif (not _lists_are_the_same(sel_colours, default_colour_list) and
          _lists_are_the_same(sel_labels, labels)):
        # the provided labels are the same, but the colours are different
        # assign colour
        colour_selection_wid.selected_values['colour'] = default_colour_list
        k = colour_selection_wid.children[0].children[0].value
        default_colour = default_colour_list[k]
        if not isinstance(default_colour, str):
            r_val = default_colour[0]
            g_val = default_colour[1]
            b_val = default_colour[2]
            default_colour = 'custom'
            colour_selection_wid.children[2].children[0].value = r_val
            colour_selection_wid.children[2].children[1].value = g_val
            colour_selection_wid.children[2].children[2].value = b_val
        colour_selection_wid.children[1].value = default_colour
        colour_selection_wid.children[0].children[0].value = 0
    elif (not _lists_are_the_same(sel_colours, default_colour_list) and not
          _lists_are_the_same(sel_labels, labels)):
        # both the colours and the labels are different
        # assign colour
        if len(sel_labels) > 1 and len(labels) == 1:
            colour_selection_wid.children[1].description = \
                colour_selection_wid.children[0].children[0].description
            colour_selection_wid.children[0].children[0].description = ''
        elif len(sel_labels) == 1 and len(labels) > 1:
            colour_selection_wid.children[0].children[0].description = \
                colour_selection_wid.children[1].description
            colour_selection_wid.children[1].description = ''
        colour_selection_wid.children[0].visible = len(labels) > 1
        colour_selection_wid.selected_values['colour'] = default_colour_list
        colour_selection_wid.selected_values['labels'] = labels
        labels_dict = OrderedDict()
        for k, l in enumerate(labels):
            labels_dict[l] = k
        colour_selection_wid.children[0].children[0].values = labels_dict
        colour_selection_wid.children[0].children[0].value = 0
        k = 0
        default_colour = default_colour_list[k]
        if not isinstance(default_colour, str):
            r_val = default_colour[0]
            g_val = default_colour[1]
            b_val = default_colour[2]
            default_colour = 'custom'
            colour_selection_wid.children[2].children[0].value = r_val
            colour_selection_wid.children[2].children[1].value = g_val
            colour_selection_wid.children[2].children[2].value = b_val
        colour_selection_wid.children[1].value = default_colour
        colour_selection_wid.children[0].children[0].value = 0


def image_options(image_options_default, plot_function=None,
                  toggle_show_visible=True, toggle_show_default=True,
                  toggle_title='Image Object'):
    r"""
    Creates a widget with Image Options. Specifically, it has:
        1) A slider that controls the image's alpha (transparency).
        2) A checkbox for interpolation.
        3) A toggle button that controls the visibility of all the above, i.e.
           the image options.

    The structure of the widgets is the following:
        image_options_wid.children = [toggle_button, options]
        options.children = [alpha_slider, pixelated_checkbox]

    The returned widget saves the selected values in the following dictionary:
        image_options_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_image_options()` function.

    Parameters
    ----------
    image_options_default : `dict`
        The initial selected image options.
        Example:
            image_options={'alpha': 1.,
                           'interpolation': 'bilinear'}
    plot_function : `function` or None, optional
        The plot function that is executed when a widgets' value changes.
        If None, then nothing is assigned.
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    toggle_title : `str`, optional
        The title of the toggle button.
    """
    import IPython.html.widgets as ipywidgets
    # Create widgets
    # toggle button
    but = ipywidgets.ToggleButtonWidget(description=toggle_title,
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # alpha, interpolation
    interpolation = ipywidgets.CheckboxWidget(
        description='Pixelated',
        value=image_options_default['interpolation'] == 'none')
    alpha = ipywidgets.FloatSliderWidget(description='Alpha',
                                         value=image_options_default['alpha'],
                                         min=0.0, max=1.0, step=0.05)
    options_wid = ipywidgets.ContainerWidget(children=[interpolation, alpha])

    # Final widget
    image_options_wid = ipywidgets.ContainerWidget(children=[but, options_wid])

    # Assign output
    image_options_wid.selected_values = image_options_default

    # get options functions
    def save_interpolation(name, value):
        if value:
            image_options_wid.selected_values['interpolation'] = 'none'
        else:
            image_options_wid.selected_values['interpolation'] = 'bilinear'
    interpolation.on_trait_change(save_interpolation, 'value')

    def save_alpha(name, value):
        image_options_wid.selected_values['alpha'] = value
    alpha.on_trait_change(save_alpha, 'value')

    # Toggle button function
    def toggle_fun(name, value):
        options_wid.visible = value
    toggle_fun('', toggle_show_default)
    but.on_trait_change(toggle_fun, 'value')

    # assign plot_function
    if plot_function is not None:
        interpolation.on_trait_change(plot_function, 'value')
        alpha.on_trait_change(plot_function, 'value')

    return image_options_wid


def format_image_options(image_options_wid, container_padding='6px',
                         container_margin='6px',
                         container_border='1px solid black',
                         toggle_button_font_weight='bold', border_visible=True):
    r"""
    Function that corrects the align (style format) of a given image_options
    widget. Usage example:
        image_options_wid = image_options()
        display(image_options_wid)
        format_image_options(image_options_wid)

    Parameters
    ----------
    image_options_wid :
        The widget object generated by the `image_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    """
    # fix alpha slider width
    image_options_wid.children[1].children[1].set_css('width', '3cm')

    # set toggle button font bold
    image_options_wid.children[0].set_css('font-weight',
                                          toggle_button_font_weight)

    # margin and border around container widget
    image_options_wid.set_css('padding', container_padding)
    image_options_wid.set_css('margin', container_margin)
    if border_visible:
        image_options_wid.set_css('border', container_border)


def update_image_options(image_options_wid, image_options_dict):
    r"""
    Function that updates the state of a given image_options widget. Usage
    example:
        default_image_options={'interpolation': 'bilinear',
                               'alpha': 0.2}
        image_options_wid = image_options(default_image_options)
        display(image_options_wid)
        format_image_options(image_options_wid)
        default_image_options={'interpolation': 'none',
                              'alpha': 0.4}
        update_image_options(image_options_wid, default_image_options)

    Parameters
    ----------
    image_options_wid :
        The widget object generated by the `image_options()` function.
    image_options_dict : `dict`
        The new set of options. For example:
            image_options_dict = {'interpolation': 'bilinear',
                                  'alpha': 1.0}
    """
    # Assign new options dict to selected_values
    image_options_wid.selected_values = image_options_dict

    # update alpha slider
    if 'alpha' in image_options_dict.keys():
        image_options_wid.children[1].children[1].value = \
            image_options_dict['alpha']

    # update interpolation checkbox
    if 'interpolation' in image_options_dict.keys():
        image_options_wid.children[1].children[0].value = \
            image_options_dict['interpolation'] == 'none'


def line_options(line_options_default, plot_function=None,
                 toggle_show_visible=True, toggle_show_default=True,
                 toggle_title='Line Object', show_checkbox_title='Render lines',
                 labels=None):
    r"""
    Creates a widget with Line Options. Specifically, it has:
        1) A checkbox that controls line's visibility.
        2) A dropdown menu for line style.
        3) A bounded float text box for line width.
        4) A colour_selection widget for line colour.
        7) A toggle button that controls the visibility of all the above, i.e.
           the line options.

    The structure of the widgets is the following:
        line_options_wid.children = [toggle_button, options]
        options.children = [render_lines_checkbox, other_options]
        other_options.children = [line_style, line_width, line_colour]

    The returned widget saves the selected values in the following dictionary:
        line_options_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_line_options()` function.

    Parameters
    ----------
    line_options_default : `dict`
        The initial selected line options.
        Example:
            line_options={'render_lines': True,
                          'line_width': 1,
                          'line_colour': ['b'],
                          'line_style': '-'}
    plot_function : `function` or None, optional
        The plot function that is executed when a widgets' value changes.
        If None, then nothing is assigned.
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    toggle_title : `str`, optional
        The title of the toggle button.
    show_checkbox_title : `str`, optional
        The description of the show line checkbox.
    """
    import IPython.html.widgets as ipywidgets
    # Create widgets
    # toggle button
    but = ipywidgets.ToggleButtonWidget(description=toggle_title,
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # line_style, line_width, line_colour
    render_lines = ipywidgets.CheckboxWidget(description=show_checkbox_title,
                                             value=line_options_default[
                                                 'render_lines'])
    line_width = ipywidgets.BoundedFloatTextWidget(description='Width',
                                                   value=line_options_default[
                                                       'line_width'],
                                                   min=0.)
    line_style_dict = OrderedDict()
    line_style_dict['solid'] = '-'
    line_style_dict['dashed'] = '--'
    line_style_dict['dash-dot'] = '-.'
    line_style_dict['dotted'] = ':'
    line_style = ipywidgets.DropdownWidget(values=line_style_dict,
                                           value=line_options_default[
                                               'line_style'],
                                           description='Style')
    line_colour = colour_selection(line_options_default['line_colour'],
                                   title='Colour', labels=labels,
                                   plot_function=plot_function)

    # Options widget
    all_line_options = ipywidgets.ContainerWidget(
        children=[line_style, line_width,
                  line_colour])
    options_wid = ipywidgets.ContainerWidget(
        children=[render_lines, all_line_options])

    # Final widget
    line_options_wid = ipywidgets.ContainerWidget(children=[but, options_wid])

    # Assign output
    line_options_wid.selected_values = line_options_default

    # line options visibility
    def options_visible(name, value):
        line_style.disabled = not value
        line_width.disabled = not value
        line_colour.children[0].children[0].disabled = not value
        line_colour.children[0].children[1].disabled = not value
        line_colour.children[1].disabled = not value
        line_colour.children[2].children[0].disabled = not value
        line_colour.children[2].children[1].disabled = not value
        line_colour.children[2].children[2].disabled = not value
    options_visible('', line_options_default['render_lines'])
    render_lines.on_trait_change(options_visible, 'value')

    # get options functions
    def save_render_lines(name, value):
        line_options_wid.selected_values['render_lines'] = value
    render_lines.on_trait_change(save_render_lines, 'value')

    def save_line_width(name, value):
        line_options_wid.selected_values['line_width'] = float(value)
    line_width.on_trait_change(save_line_width, 'value')

    def save_line_style(name, value):
        line_options_wid.selected_values['line_style'] = value
    line_style.on_trait_change(save_line_style, 'value')

    line_options_wid.selected_values['line_colour'] = \
        line_colour.selected_values['colour']

    # Toggle button function
    def toggle_fun(name, value):
        options_wid.visible = value
    toggle_fun('', toggle_show_default)
    but.on_trait_change(toggle_fun, 'value')

    # assign plot_function
    if plot_function is not None:
        render_lines.on_trait_change(plot_function, 'value')
        line_style.on_trait_change(plot_function, 'value')
        line_width.on_trait_change(plot_function, 'value')

    return line_options_wid


def format_line_options(line_options_wid, container_padding='6px',
                        container_margin='6px',
                        container_border='1px solid black',
                        toggle_button_font_weight='bold', border_visible=True,
                        suboptions_border_visible=True):
    r"""
    Function that corrects the align (style format) of a given line_options
    widget. Usage example:
        line_options_wid = line_options()
        display(line_options_wid)
        format_line_options(line_options_wid)

    Parameters
    ----------
    line_options_wid :
        The widget object generated by the `line_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    suboptions_border_visible : `boolean`, optional
        Defines whether to draw the border line around the line options, under
        the show line checkbox.
    """
    # align line options with checkbox
    line_options_wid.children[1].add_class('align-end')

    # set linewidth text box width
    line_options_wid.children[1].children[1].children[1].set_css('width', '1cm')

    # format colour options
    format_colour_selection(line_options_wid.children[1].children[1].children[2])

    # border around options
    if suboptions_border_visible:
        line_options_wid.children[1].children[1].set_css('border',
                                                         container_border)

    # set toggle button font bold
    line_options_wid.children[0].set_css('font-weight',
                                         toggle_button_font_weight)

    # margin and border around container widget
    line_options_wid.set_css('padding', container_padding)
    line_options_wid.set_css('margin', container_margin)
    if border_visible:
        line_options_wid.set_css('border', container_border)


def update_line_options(line_options_wid, line_options_dict, labels=None):
    r"""
    Function that updates the state of a given line_options widget. Usage
    example:
        default_line_options={'render_lines':True,
                              'line_width':2,
                              'line_colour':['r'],
                              'line_style':'-'}
        line_options_wid = line_options(default_line_options)
        display(line_options_wid)
        format_line_options(line_options_wid)
        default_line_options={'render_lines':False,
                              'line_width':4,
                              'line_colour':[[0.1, 0.2, 0.3]],
                              'line_style':'-'}
        update_line_options(line_options_wid, default_line_options)

    Parameters
    ----------
    line_options_wid :
        The widget object generated by the `line_options()` function.

    line_options_dict : `dict`
        The new set of options. For example:
            line_options_dict={'render_lines':True,
                               'line_width':2,
                               'line_colour':['r'],
                               'line_style':'-'}
    """
    # Assign new options dict to selected_values
    line_options_wid.selected_values = line_options_dict

    # update render lines checkbox
    if 'render_lines' in line_options_dict.keys():
        line_options_wid.children[1].children[0].value = \
            line_options_dict['render_lines']

    # update line_style dropdown menu
    if 'line_style' in line_options_dict.keys():
        line_options_wid.children[1].children[1].children[0].value = \
            line_options_dict['line_style']

    # update line_width text box
    if 'line_width' in line_options_dict.keys():
        line_options_wid.children[1].children[1].children[1].value = \
            float(line_options_dict['line_width'])

    # update line_colour
    if 'line_colour' in line_options_dict.keys():
        update_colour_selection(
            line_options_wid.children[1].children[1].children[2],
            line_options_dict['line_colour'], labels=labels)


def marker_options(marker_options_default, plot_function=None,
                   toggle_show_visible=True, toggle_show_default=True,
                   toggle_title='Marker Object',
                   show_checkbox_title='Show markers'):
    r"""
    Creates a widget with Marker Options. Specifically, it has:
        1) A checkbox that controls marker's visibility.
        2) A dropdown menu for marker style.
        3) A bounded int text box for marker size.
        4) A bounded float text box for marker edge width.
        5) A colour_selection widget for face colour.
        6) A colour_selection widget for edge colour.
        7) A toggle button that controls the visibility of all the above, i.e.
           the marker options.

    The structure of the widgets is the following:
        marker_options_wid.children = [toggle_button, options]
        options.children = [render_markers_checkbox, other_options]
        other_options.children = [marker_style, marker_size, marker_edge_width,
                                  marker_face_colour, marker_edge_colour]

    The returned widget saves the selected values in the following dictionary:
        marker_options_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_marker_options()` function.

    Parameters
    ----------
    marker_options_default : `dict`
        The initial selected marker options.
        Example:
            marker_options_default={'render_markers':True,
                                    'marker_size':20,
                                    'marker_face_colour':['r'],
                                    'marker_edge_colour':['k'],
                                    'marker_style':'o',
                                    'marker_edge_width':1}

    plot_function : `function` or None, optional
        The plot function that is executed when a widgets' value changes.
        If None, then nothing is assigned.
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    toggle_title : `str`, optional
        The title of the toggle button.
    show_checkbox_title : `str`, optional
        The description of the show marker checkbox.
    """
    import IPython.html.widgets as ipywidgets
    # Create widgets
    # toggle button
    but = ipywidgets.ToggleButtonWidget(description=toggle_title,
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # marker_size, marker_edge_width, marker_style, marker_face_colour,
    # marker_edge_colour
    render_markers = ipywidgets.CheckboxWidget(
        description=show_checkbox_title,
        value=marker_options_default['render_markers'])
    marker_size = ipywidgets.BoundedIntTextWidget(
        description='Size', value=marker_options_default['marker_size'], min=0)
    marker_edge_width = ipywidgets.BoundedFloatTextWidget(
        description='Edge width',
        value=marker_options_default['marker_edge_width'], min=0.)
    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'
    marker_style = ipywidgets.DropdownWidget(values=marker_style_dict,
                                             value=marker_options_default[
                                                 'marker_style'],
                                             description='Style')
    marker_face_colour = colour_selection(
        marker_options_default['marker_face_colour'], title='Face Colour',
        plot_function=plot_function)
    marker_edge_colour = colour_selection(
        marker_options_default['marker_edge_colour'], title='Edge Colour',
        plot_function=plot_function)

    # Options widget
    all_marker_options = ipywidgets.ContainerWidget(
        children=[marker_style, marker_size,
                  marker_edge_width,
                  marker_face_colour,
                  marker_edge_colour])
    options_wid = ipywidgets.ContainerWidget(
        children=[render_markers, all_marker_options])

    # Final widget
    marker_options_wid = ipywidgets.ContainerWidget(children=[but, options_wid])

    # Assign output
    marker_options_wid.selected_values = marker_options_default

    # marker options visibility
    def options_visible(name, value):
        marker_style.disabled = not value
        marker_size.disabled = not value
        marker_edge_width.disabled = not value
        marker_face_colour.children[0].children[0].disabled = not value
        marker_face_colour.children[0].children[1].disabled = not value
        marker_face_colour.children[1].disabled = not value
        marker_face_colour.children[2].children[0].disabled = not value
        marker_face_colour.children[2].children[1].disabled = not value
        marker_face_colour.children[2].children[2].disabled = not value
        marker_edge_colour.children[0].children[0].disabled = not value
        marker_edge_colour.children[0].children[1].disabled = not value
        marker_edge_colour.children[1].disabled = not value
        marker_edge_colour.children[2].children[0].disabled = not value
        marker_edge_colour.children[2].children[1].disabled = not value
        marker_edge_colour.children[2].children[2].disabled = not value
    options_visible('', marker_options_default['render_markers'])
    render_markers.on_trait_change(options_visible, 'value')

    # get options functions
    def save_render_markers(name, value):
        marker_options_wid.selected_values['render_markers'] = value
    render_markers.on_trait_change(save_render_markers, 'value')

    def save_markersize(name, value):
        marker_options_wid.selected_values['marker_size'] = int(value)
    marker_size.on_trait_change(save_markersize, 'value')

    def save_markeredgewidth(name, value):
        marker_options_wid.selected_values['marker_edge_width'] = float(value)
    marker_edge_width.on_trait_change(save_markeredgewidth, 'value')

    def save_markerstyle(name, value):
        marker_options_wid.selected_values['marker_style'] = value
    marker_style.on_trait_change(save_markerstyle, 'value')

    marker_options_wid.selected_values['marker_edge_colour'] = \
        marker_edge_colour.selected_values['colour']
    marker_options_wid.selected_values['marker_face_colour'] = \
        marker_face_colour.selected_values['colour']

    # Toggle button function
    def toggle_fun(name, value):
        options_wid.visible = value
    toggle_fun('', toggle_show_default)
    but.on_trait_change(toggle_fun, 'value')

    # assign plot_function
    if plot_function is not None:
        render_markers.on_trait_change(plot_function, 'value')
        marker_style.on_trait_change(plot_function, 'value')
        marker_edge_width.on_trait_change(plot_function, 'value')
        marker_size.on_trait_change(plot_function, 'value')

    return marker_options_wid


def format_marker_options(marker_options_wid, container_padding='6px',
                          container_margin='6px',
                          container_border='1px solid black',
                          toggle_button_font_weight='bold', border_visible=True,
                          suboptions_border_visible=True):
    r"""
    Function that corrects the align (style format) of a given marker_options
    widget. Usage example:
        marker_options_wid = marker_options()
        display(marker_options_wid)
        format_marker_options(marker_options_wid)

    Parameters
    ----------
    marker_options_wid :
        The widget object generated by the `marker_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    suboptions_border_visible : `boolean`, optional
        Defines whether to draw the border line around the marker options, under
        the show marker checkbox.
    """
    # align marker options with checkbox
    marker_options_wid.children[1].add_class('align-end')

    # set text boxes width
    marker_options_wid.children[1].children[1].children[1].set_css('width',
                                                                   '1cm')
    marker_options_wid.children[1].children[1].children[2].set_css('width',
                                                                   '1cm')

    # border around options
    if suboptions_border_visible:
        marker_options_wid.children[1].children[1].set_css('border',
                                                           container_border)

    # format colour options
    format_colour_selection(
        marker_options_wid.children[1].children[1].children[3])
    format_colour_selection(
        marker_options_wid.children[1].children[1].children[4])

    # set toggle button font bold
    marker_options_wid.children[0].set_css('font-weight',
                                           toggle_button_font_weight)

    # margin and border around container widget
    marker_options_wid.set_css('padding', container_padding)
    marker_options_wid.set_css('margin', container_margin)
    if border_visible:
        marker_options_wid.set_css('border', container_border)


def update_marker_options(marker_options_wid, marker_options_dict):
    r"""
    Function that updates the state of a given marker_options widget. Usage
    example:
        default_marker_options={'render_markers':True,
                                'marker_size':20,
                                'marker_face_colour':['r'],
                                'marker_edge_colour':['k'],
                                'marker_style':'o',
                                'marker_edge_width':1}
        marker_options_wid = marker_options(default_marker_options)
        display(marker_options_wid)
        format_marker_options(marker_options_wid)
        default_marker_options={'render_markers':True,
                                'marker_size':40,
                                'marker_face_colour':[[0.1, 0.2, 0.3]],
                                'marker_edge_colour':['r'],
                                'marker_style':'d',
                                'marker_edge_width':1}
        update_marker_options(marker_options_wid, default_marker_options)

    Parameters
    ----------
    marker_options_wid :
        The widget object generated by the `marker_options()` function.
    marker_options_dict : `dict`
        The new set of options. For example:
            marker_options_dict={'render_markers':True,
                                 'marker_size':20,
                                 'marker_face_colour':['r'],
                                 'marker_edge_colour':['k'],
                                 'marker_style':'o',
                                 'marker_edge_width':1}
    """
    # Assign new options dict to selected_values
    marker_options_wid.selected_values = marker_options_dict

    # update render marker checkbox
    if 'render_markers' in marker_options_dict.keys():
        marker_options_wid.children[1].children[0].value = \
            marker_options_dict['render_markers']

    # update marker_style dropdown menu
    if 'marker_style' in marker_options_dict.keys():
        marker_options_wid.children[1].children[1].children[0].value = \
            marker_options_dict['marker_style']

    # update marker_size text box
    if 'marker_size' in marker_options_dict.keys():
        marker_options_wid.children[1].children[1].children[1].value = \
            int(marker_options_dict['marker_size'])

    # update marker_edge_width text box
    if 'marker_edge_width' in marker_options_dict.keys():
        marker_options_wid.children[1].children[1].children[2].value = \
            float(marker_options_dict['marker_edge_width'])

    # update marker_face_colour
    if 'marker_face_colour' in marker_options_dict.keys():
        update_colour_selection(
            marker_options_wid.children[1].children[1].children[3],
            marker_options_dict['marker_face_colour'])

    # update marker_edge_colour
    if 'marker_edge_colour' in marker_options_dict.keys():
        update_colour_selection(
            marker_options_wid.children[1].children[1].children[4],
            marker_options_dict['marker_edge_colour'])


def numbering_options(numbers_options_default, plot_function=None,
                      toggle_show_visible=True, toggle_show_default=True,
                      toggle_title='Numbering Options',
                      show_checkbox_title='Render numbering'):
    r"""
    Creates a widget with Numbering Options. Specifically, it has:
        1) A checkbox that controls text's visibility.
        2) A dropdown menu for font name.
        3) A bounded int text box for font size.
        4) A dropdown menu for font style.
        5) A dropdown menu for font weight.
        6) A colour_selection widget for font colour.
        7) A dropdown menu for horizontal alignment.
        8) A dropdown menu for vertical alignment.
        9) A toggle button that controls the visibility of all the above, i.e.
           the numbering options.

    The structure of the widgets is the following:
        numbering_options_wid.children = [toggle_button, options]
        options.children = [show_font_checkbox, other_options]
        other_options.children = [font_name, font_size, font_style, font_weight,
                                  font_colour, horizontal_align, vertical_align]

    The returned widget saves the selected values in the following dictionary:
        numbering_options_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_numbering_options()` function.

    Parameters
    ----------
    numbers_options_default : `dict`
        The initial selected font options.
        Example:
            numbers_options_default = {'render_numbering': True,
                                       'numbers_font_name': 'serif',
                                       'numbers_font_size': 10,
                                       'numbers_font_style': 'normal',
                                       'numbers_font_weight': 'normal',
                                       'numbers_font_colour': ['k'],
                                       'numbers_horizontal_align': 'center',
                                       'numbers_vertical_align': 'bottom'}
    plot_function : `function` or None, optional
        The plot function that is executed when a widgets' value changes.
        If None, then nothing is assigned.
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    toggle_title : `str`, optional
        The title of the toggle button.
    show_checkbox_title : `str`, optional
        The description of the show text checkbox.
    """
    import IPython.html.widgets as ipywidgets
    # Create widgets
    # toggle button
    but = ipywidgets.ToggleButtonWidget(description=toggle_title,
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # numbers_font_name, numbers_font_size, numbers_font_style,
    # numbers_font_weight, numbers_font_colour
    render_numbering = ipywidgets.CheckboxWidget(
        description=show_checkbox_title,
        value=numbers_options_default['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'
    numbers_font_name = ipywidgets.DropdownWidget(
        values=numbers_font_name_dict,
        value=numbers_options_default['numbers_font_name'], description='Font')
    numbers_font_size = ipywidgets.BoundedIntTextWidget(
        description='Size', value=numbers_options_default['numbers_font_size'],
        min=2)
    numbers_font_style_dict = OrderedDict()
    numbers_font_style_dict['normal'] = 'normal'
    numbers_font_style_dict['italic'] = 'italic'
    numbers_font_style_dict['oblique'] = 'oblique'
    numbers_font_style = ipywidgets.DropdownWidget(
        values=numbers_font_style_dict,
        value=numbers_options_default['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'
    numbers_font_weight = ipywidgets.DropdownWidget(
        values=numbers_font_weight_dict,
        value=numbers_options_default['numbers_font_weight'],
        description='Weight')
    numbers_font_colour = colour_selection(
        numbers_options_default['numbers_font_colour'], title='Colour',
        plot_function=plot_function)
    numbers_horizontal_align_dict = OrderedDict()
    numbers_horizontal_align_dict['center'] = 'center'
    numbers_horizontal_align_dict['right'] = 'right'
    numbers_horizontal_align_dict['left'] = 'left'
    numbers_horizontal_align = ipywidgets.DropdownWidget(
        values=numbers_horizontal_align_dict,
        value=numbers_options_default['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'
    numbers_vertical_align = ipywidgets.DropdownWidget(
        values=numbers_vertical_align_dict,
        value=numbers_options_default['numbers_vertical_align'],
        description='Align ver.')

    # Options widget
    all_font_options = ipywidgets.ContainerWidget(
        children=[numbers_font_name, numbers_font_size, numbers_font_style,
                  numbers_font_weight, numbers_font_colour,
                  numbers_horizontal_align, numbers_vertical_align])
    options_wid = ipywidgets.ContainerWidget(
        children=[render_numbering, all_font_options])

    # Final widget
    numbering_options_wid = ipywidgets.ContainerWidget(
        children=[but, options_wid])

    # Assign output
    numbering_options_wid.selected_values = numbers_options_default

    # font options visibility
    def options_visible(name, value):
        numbers_font_name.disabled = not value
        numbers_font_size.disabled = not value
        numbers_font_style.disabled = not value
        numbers_font_weight.disabled = not value
        numbers_font_colour.children[0].children[0].disabled = not value
        numbers_font_colour.children[0].children[1].disabled = not value
        numbers_font_colour.children[1].disabled = not value
        numbers_font_colour.children[2].children[0].disabled = not value
        numbers_font_colour.children[2].children[1].disabled = not value
        numbers_font_colour.children[2].children[2].disabled = not value
        numbers_horizontal_align.disabled = not value
        numbers_vertical_align.disabled = not value
    options_visible('', numbers_options_default['render_numbering'])
    render_numbering.on_trait_change(options_visible, 'value')

    # get options functions
    def save_render_numbering(name, value):
        numbering_options_wid.selected_values['render_numbering'] = value
    render_numbering.on_trait_change(save_render_numbering, 'value')

    def save_numbers_font_name(name, value):
        numbering_options_wid.selected_values['numbers_font_name'] = value
    numbers_font_name.on_trait_change(save_numbers_font_name, 'value')

    def save_numbers_font_size(name, value):
        numbering_options_wid.selected_values['numbers_font_size'] = int(value)
    numbers_font_size.on_trait_change(save_numbers_font_size, 'value')

    def save_numbers_font_style(name, value):
        numbering_options_wid.selected_values['numbers_font_style'] = value
    numbers_font_style.on_trait_change(save_numbers_font_style, 'value')

    def save_numbers_font_weight(name, value):
        numbering_options_wid.selected_values['numbers_font_weight'] = value
    numbers_font_weight.on_trait_change(save_numbers_font_weight, 'value')

    def save_numbers_horizontal_align(name, value):
        numbering_options_wid.selected_values['numbers_horizontal_align'] = \
            value
    numbers_horizontal_align.on_trait_change(save_numbers_horizontal_align,
                                             'value')

    def save_numbers_vertical_align(name, value):
        numbering_options_wid.selected_values['numbers_vertical_align'] = value
    numbers_vertical_align.on_trait_change(save_numbers_vertical_align, 'value')

    numbering_options_wid.selected_values['numbers_font_colour'] = \
        numbers_font_colour.selected_values['colour']

    # Toggle button function
    def toggle_fun(name, value):
        options_wid.visible = value
    toggle_fun('', toggle_show_default)
    but.on_trait_change(toggle_fun, 'value')

    # assign plot_function
    if plot_function is not None:
        render_numbering.on_trait_change(plot_function, 'value')
        numbers_font_name.on_trait_change(plot_function, 'value')
        numbers_font_style.on_trait_change(plot_function, 'value')
        numbers_font_size.on_trait_change(plot_function, 'value')
        numbers_font_weight.on_trait_change(plot_function, 'value')
        numbers_horizontal_align.on_trait_change(plot_function, 'value')
        numbers_vertical_align.on_trait_change(plot_function, 'value')

    return numbering_options_wid


def format_numbering_options(numbering_options_wid, container_padding='6px',
                             container_margin='6px',
                             container_border='1px solid black',
                             toggle_button_font_weight='bold',
                             border_visible=True,
                             suboptions_border_visible=True):
    r"""
    Function that corrects the align (style format) of a given numbering_options
    widget. Usage example:
        numbering_options_wid = numbering_options()
        display(numbering_options_wid)
        format_numbering_options(numbering_options_wid)

    Parameters
    ----------
    numbering_options_wid :
        The widget object generated by the `numbering_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    suboptions_border_visible : `boolean`, optional
        Defines whether to draw the border line around the font options, under
        the show font checkbox.
    """
    # align font options with checkbox
    numbering_options_wid.children[1].add_class('align-end')

    # set fontsize text box width
    numbering_options_wid.children[1].children[1].children[1].set_css('width',
                                                                      '1cm')

    # format colour options
    format_colour_selection(
        numbering_options_wid.children[1].children[1].children[4])

    # border around options
    if suboptions_border_visible:
        numbering_options_wid.children[1].children[1].set_css('border',
                                                              container_border)

    # set toggle button font bold
    numbering_options_wid.children[0].set_css('font-weight',
                                              toggle_button_font_weight)

    # margin and border around container widget
    numbering_options_wid.set_css('padding', container_padding)
    numbering_options_wid.set_css('margin', container_margin)
    if border_visible:
        numbering_options_wid.set_css('border', container_border)


def update_numbering_options(numbering_options_wid, numbering_options_dict):
    r"""
    Function that updates the state of a given numbering_options widget. Usage
    example:
        numbering_options_default = {'render_numbering': True,
                                      'numbers_font_name': 'serif',
                                      'numbers_font_size': 10,
                                      'numbers_font_style': 'normal',
                                      'numbers_font_weight': 'normal',
                                      'numbers_font_colour': ['k'],
                                      'numbers_horizontal_align': 'center',
                                      'numbers_vertical_align': 'bottom'}
        numbering_options_wid = numbering_options(numbering_options_default)
        display(numbering_options_wid)
        format_numbering_options(numbering_options_wid)
        numbering_options_default = {'render_numbering': False,
                                      'numbers_font_name': 'serif',
                                      'numbers_font_size': 10,
                                      'numbers_font_style': 'normal',
                                      'numbers_font_weight': 'normal',
                                      'numbers_font_colour': ['k'],
                                      'numbers_horizontal_align': 'center',
                                      'numbers_vertical_align': 'bottom'}
        update_numbering_options(numbering_options_wid,
                                 numbering_options_default)

    Parameters
    ----------
    numbering_options_wid :
        The widget object generated by the `numbering_options()` function.
    numbering_options_dict : `dict`
        The new set of options. For example:
            numbering_options_dict = {'render_numbering': True,
                                      'numbers_font_name': 'serif',
                                      'numbers_font_size': 10,
                                      'numbers_font_style': 'normal',
                                      'numbers_font_weight': 'normal',
                                      'numbers_font_colour': ['k'],
                                      'numbers_horizontal_align': 'center',
                                      'numbers_vertical_align': 'bottom'}
    """
    # Assign new options dict to selected_values
    numbering_options_wid.selected_values = numbering_options_dict

    # update render numbering checkbox
    if 'render_numbering' in numbering_options_dict.keys():
        numbering_options_wid.children[1].children[0].value = \
            numbering_options_dict['render_numbering']

    # update numbers_font_name dropdown menu
    if 'numbers_font_name' in numbering_options_dict.keys():
        numbering_options_wid.children[1].children[1].children[0].value = \
            numbering_options_dict['numbers_font_name']

    # update numbers_font_size text box
    if 'numbers_font_size' in numbering_options_dict.keys():
        numbering_options_wid.children[1].children[1].children[1].value = \
            int(numbering_options_dict['numbers_font_size'])

    # update numbers_font_style dropdown menu
    if 'numbers_font_style' in numbering_options_dict.keys():
        numbering_options_wid.children[1].children[1].children[2].value = \
            numbering_options_dict['numbers_font_style']

    # update numbers_font_weight dropdown menu
    if 'numbers_font_weight' in numbering_options_dict.keys():
        numbering_options_wid.children[1].children[1].children[3].value = \
            numbering_options_dict['numbers_font_weight']

    # update numbers_font_colour
    if 'numbers_font_colour' in numbering_options_dict.keys():
        update_colour_selection(
            numbering_options_wid.children[1].children[1].children[4],
            numbering_options_dict['numbers_font_colour'])

    # update numbers_horizontal_align dropdown menu
    if 'numbers_horizontal_align' in numbering_options_dict.keys():
        numbering_options_wid.children[1].children[1].children[5].value = \
            numbering_options_dict['numbers_horizontal_align']

    # update numbers_vertical_align dropdown menu
    if 'numbers_vertical_align' in numbering_options_dict.keys():
        numbering_options_wid.children[1].children[1].children[6].value = \
            numbering_options_dict['numbers_vertical_align']


def figure_options(figure_options_default, plot_function=None,
                   figure_scale_bounds=(0.1, 4), figure_scale_step=0.1,
                   figure_scale_visible=True, axes_visible=True,
                   toggle_show_default=True, toggle_show_visible=True):
    r"""
    Creates a widget with Figure Options. Specifically, it has:
        1) A slider that controls the scaling of the figure.
        2) A checkbox that controls the visibility of the figure's axes.
        3) Font options for the axes.
        4) A toggle button that controls the visibility of all the above, i.e.
           the figure options.

    The structure of the widgets is the following:
        figure_options_wid.children = [toggle_button, figure_scale_slider,
                                       show_axes_checkbox, axes_font_name,
                                       axes_font_size, axes_font_style,
                                       axes_font_weight, axes_x_limits,
                                       axes_y_limits]

    The returned widget saves the selected values in the following dictionary:
        figure_options_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_figure_options()` function.

    Parameters
    ----------
    figure_options_default : `dict`
        The initial selected figure options.
        Example:
            figure_options_default = {'x_scale': 1.,
                                      'y_scale': 1.,
                                      'render_axes': True,
                                      'axes_font_name': 'serif',
                                      'axes_font_size': 10,
                                      'axes_font_style': 'normal',
                                      'axes_font_weight': 'normal',
                                      'axes_x_limits': None,
                                      'axes_y_limits': None}
    plot_function : `function` or None, optional
        The plot function that is executed when a widgets' value changes.
        If None, then nothing is assigned.
    figure_scale_bounds : (`float`, `float`), optional
        The range of scales that can be optionally applied to the figure.
    figure_scale_step : `float`, optional
        The step of the scale sliders.
    figure_scale_visible : `boolean`, optional
        The visibility of the figure scales sliders.
    show_axes_visible : `boolean`, optional
        The visibility of the axes checkbox.
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    """
    import IPython.html.widgets as ipywidgets
    # Create widgets
    # toggle button
    but = ipywidgets.ToggleButtonWidget(description='Figure Options',
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # figure_scale, render_axes
    figure_scale = ipywidgets.FloatSliderWidget(description='Figure scale:',
                                                value=figure_options_default[
                                                    'x_scale'],
                                                min=figure_scale_bounds[0],
                                                max=figure_scale_bounds[1],
                                                step=figure_scale_step,
                                                visible=figure_scale_visible)
    render_axes = ipywidgets.CheckboxWidget(description='Render axes',
                                            value=figure_options_default[
                                                'render_axes'],
                                            visible=axes_visible)
    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'
    axes_font_name = ipywidgets.DropdownWidget(
        values=axes_font_name_dict,
        value=figure_options_default['axes_font_name'], description='Font',
        visible=axes_visible)
    axes_font_size = ipywidgets.BoundedIntTextWidget(
        description='Size', value=figure_options_default['axes_font_size'],
        min=0, visible=axes_visible)
    axes_font_style_dict = OrderedDict()
    axes_font_style_dict['normal'] = 'normal'
    axes_font_style_dict['italic'] = 'italic'
    axes_font_style_dict['oblique'] = 'oblique'
    axes_font_style = ipywidgets.DropdownWidget(
        values=axes_font_style_dict,
        value=figure_options_default['axes_font_style'],
        description='Style', visible=axes_visible)
    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'
    axes_font_weight = ipywidgets.DropdownWidget(
        values=axes_font_weight_dict,
        value=figure_options_default['axes_font_weight'],
        description='Weight', visible=axes_visible)
    if figure_options_default['axes_x_limits'] is None:
        tmp1 = False
        tmp2 = 0.
        tmp3 = 100.
    else:
        tmp1 = True
        tmp2 = figure_options_default['axes_x_limits'][0]
        tmp3 = figure_options_default['axes_x_limits'][1]
    axes_x_limits_enable = ipywidgets.CheckboxWidget(value=tmp1,
                                                     description='X limits')
    axes_x_limits_from = ipywidgets.FloatTextWidget(value=tmp2, description='')
    axes_x_limits_to = ipywidgets.FloatTextWidget(value=tmp3, description='')
    axes_x_limits = ipywidgets.ContainerWidget(children=[axes_x_limits_enable,
                                                         axes_x_limits_from,
                                                         axes_x_limits_to])
    if figure_options_default['axes_y_limits'] is None:
        tmp1 = False
        tmp2 = 0.
        tmp3 = 100.
    else:
        tmp1 = True
        tmp2 = figure_options_default['axes_y_limits'][0]
        tmp3 = figure_options_default['axes_y_limits'][1]
    axes_y_limits_enable = ipywidgets.CheckboxWidget(value=tmp1,
                                                     description='Y limits')
    axes_y_limits_from = ipywidgets.FloatTextWidget(value=tmp2, description='')
    axes_y_limits_to = ipywidgets.FloatTextWidget(value=tmp3, description='')
    axes_y_limits = ipywidgets.ContainerWidget(children=[axes_y_limits_enable,
                                                         axes_y_limits_from,
                                                         axes_y_limits_to])

    # Final widget
    figure_options_wid = ipywidgets.ContainerWidget(children=[but, figure_scale,
                                                              render_axes,
                                                              axes_font_name,
                                                              axes_font_size,
                                                              axes_font_style,
                                                              axes_font_weight,
                                                              axes_x_limits,
                                                              axes_y_limits])

    # Assign output
    figure_options_wid.selected_values = figure_options_default

    # font options visibility
    def options_visible(name, value):
        axes_font_name.disabled = not value
        axes_font_size.disabled = not value
        axes_font_style.disabled = not value
        axes_font_weight.disabled = not value
        axes_x_limits_enable.disabled = not value
        axes_y_limits_enable.disabled = not value
        if value:
            axes_x_limits_from.disabled = not axes_x_limits_enable.value
            axes_x_limits_to.disabled = not axes_x_limits_enable.value
            axes_y_limits_from.disabled = not axes_y_limits_enable.value
            axes_y_limits_to.disabled = not axes_y_limits_enable.value
        else:
            axes_x_limits_from.disabled = True
            axes_x_limits_to.disabled = True
            axes_y_limits_from.disabled = True
            axes_y_limits_to.disabled = True
    options_visible('', figure_options_default['render_axes'])
    render_axes.on_trait_change(options_visible, 'value')

    # get options functions
    def save_render_axes(name, value):
        figure_options_wid.selected_values['render_axes'] = value
    render_axes.on_trait_change(save_render_axes, 'value')

    def save_axes_font_name(name, value):
        figure_options_wid.selected_values['axes_font_name'] = value
    axes_font_name.on_trait_change(save_axes_font_name, 'value')

    def save_axes_font_size(name, value):
        figure_options_wid.selected_values['axes_font_size'] = int(value)
    axes_font_size.on_trait_change(save_axes_font_size, 'value')

    def save_axes_font_style(name, value):
        figure_options_wid.selected_values['axes_font_style'] = value
    axes_font_style.on_trait_change(save_axes_font_style, 'value')

    def save_axes_font_weight(name, value):
        figure_options_wid.selected_values['axes_font_weight'] = value
    axes_font_weight.on_trait_change(save_axes_font_weight, 'value')

    def axes_x_limits_disable(name, value):
        axes_x_limits_from.disabled = not value
        axes_x_limits_to.disabled = not value
    axes_x_limits_disable('', axes_x_limits_enable.value)
    axes_x_limits_enable.on_trait_change(axes_x_limits_disable, 'value')

    def axes_y_limits_disable(name, value):
        axes_y_limits_from.disabled = not value
        axes_y_limits_to.disabled = not value
    axes_y_limits_disable('', axes_y_limits_enable.value)
    axes_y_limits_enable.on_trait_change(axes_y_limits_disable, 'value')

    def save_axes_x_limits(name, value):
        if axes_x_limits_enable.value:
            figure_options_wid.selected_values['axes_x_limits'] = \
                (axes_x_limits_from.value, axes_x_limits_to.value)
        else:
            figure_options_wid.selected_values['axes_x_limits'] = None
    axes_x_limits_enable.on_trait_change(save_axes_x_limits, 'value')
    axes_x_limits_from.on_trait_change(save_axes_x_limits, 'value')
    axes_x_limits_to.on_trait_change(save_axes_x_limits, 'value')

    def save_axes_y_limits(name, value):
        if axes_y_limits_enable.value:
            figure_options_wid.selected_values['axes_y_limits'] = \
                (axes_y_limits_from.value, axes_y_limits_to.value)
        else:
            figure_options_wid.selected_values['axes_y_limits'] = None
    axes_y_limits_enable.on_trait_change(save_axes_y_limits, 'value')
    axes_y_limits_from.on_trait_change(save_axes_y_limits, 'value')
    axes_y_limits_to.on_trait_change(save_axes_y_limits, 'value')

    def save_scale(name, value):
        figure_options_wid.selected_values['x_scale'] = value
        figure_options_wid.selected_values['y_scale'] = value
    figure_scale.on_trait_change(save_scale, 'value')

    # Toggle button function
    def toggle_fun(name, value):
        figure_scale.visible = value
        render_axes.visible = value
        axes_font_name.visible = value
        axes_font_size.visible = value
        axes_font_style.visible = value
        axes_font_weight.visible = value
        axes_x_limits.visible = value
        axes_y_limits.visible = value
    toggle_fun('', toggle_show_default)
    but.on_trait_change(toggle_fun, 'value')

    # assign plot_function
    if plot_function is not None:
        figure_scale.on_trait_change(plot_function, 'value')
        render_axes.on_trait_change(plot_function, 'value')
        axes_font_name.on_trait_change(plot_function, 'value')
        axes_font_size.on_trait_change(plot_function, 'value')
        axes_font_style.on_trait_change(plot_function, 'value')
        axes_font_weight.on_trait_change(plot_function, 'value')
        axes_x_limits_from.on_trait_change(plot_function, 'value')
        axes_x_limits_to.on_trait_change(plot_function, 'value')
        axes_x_limits_enable.on_trait_change(plot_function, 'value')
        axes_y_limits_from.on_trait_change(plot_function, 'value')
        axes_y_limits_to.on_trait_change(plot_function, 'value')
        axes_y_limits_enable.on_trait_change(plot_function, 'value')

    return figure_options_wid


def format_figure_options(figure_options_wid, container_padding='6px',
                          container_margin='6px',
                          container_border='1px solid black',
                          toggle_button_font_weight='bold',
                          border_visible=True):
    r"""
    Function that corrects the align (style format) of a given figure_options
    widget. Usage example:
        figure_options_wid = figure_options()
        display(figure_options_wid)
        format_figure_options(figure_options_wid)

    Parameters
    ----------
    figure_options_wid :
        The widget object generated by the `figure_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    """
    # fix figure scale slider width
    figure_options_wid.children[1].set_css('width', '3cm')

    # fix font size width
    figure_options_wid.children[4].set_css('width', '1cm')

    # align and set width of axes_x_limits
    figure_options_wid.children[7].remove_class('vbox')
    figure_options_wid.children[7].add_class('hbox')
    figure_options_wid.children[7].children[1].set_css('width', '1cm')
    figure_options_wid.children[7].children[2].set_css('width', '1cm')

    # align and set width of axes_y_limits
    figure_options_wid.children[8].remove_class('vbox')
    figure_options_wid.children[8].add_class('hbox')
    figure_options_wid.children[8].children[1].set_css('width', '1cm')
    figure_options_wid.children[8].children[2].set_css('width', '1cm')

    # set toggle button font bold
    figure_options_wid.children[0].set_css('font-weight',
                                           toggle_button_font_weight)

    # margin and border around container widget
    figure_options_wid.set_css('padding', container_padding)
    figure_options_wid.set_css('margin', container_margin)
    if border_visible:
        figure_options_wid.set_css('border', container_border)


def update_figure_options(figure_options_wid, figure_options_dict):
    r"""
    Function that updates the state of a given figure_options widget. Usage
    example:
        figure_options_default = {'x_scale': 1.,
                                  'y_scale': 1.,
                                  'render_axes': True,
                                  'axes_font_name': 'serif',
                                  'axes_font_size': 10,
                                  'axes_font_style': 'normal',
                                  'axes_font_weight': 'normal',
                                  'axes_x_limits': None,
                                  'axes_y_limits': None}
        figure_options_wid = figure_options(figure_options_default)
        display(figure_options_wid)
        format_figure_options(figure_options_wid)
        figure_options_default = {'x_scale': 1.,
                                  'y_scale': 1.,
                                  'render_axes': True,
                                  'axes_font_name': 'serif',
                                  'axes_font_size': 10,
                                  'axes_font_style': 'normal',
                                  'axes_font_weight': 'normal',
                                  'axes_x_limits': None,
                                  'axes_y_limits': None}
        update_figure_options(figure_options_wid, figure_options_default)

    Parameters
    ----------
    figure_options_wid :
        The widget object generated by the `figure_options()` function.
    figure_options_dict : `dict`
        The new set of options. For example:
            figure_options_dict = {'x_scale': 1.,
                                   'y_scale': 1.,
                                   'render_axes': True,
                                   'axes_font_name': 'serif',
                                   'axes_font_size': 10,
                                   'axes_font_style': 'normal',
                                   'axes_font_weight': 'normal',
                                   'axes_x_limits': None,
                                   'axes_y_limits': None}
    """
    # Assign new options dict to selected_values
    figure_options_wid.selected_values = figure_options_dict

    # update scale slider
    if 'x_scale' in figure_options_dict.keys():
        figure_options_wid.children[1].value = figure_options_dict['x_scale']
    elif 'y_scale' in figure_options_dict.keys():
        figure_options_wid.children[1].value = figure_options_dict['y_scale']

    # update render axes checkbox
    if 'render_axes' in figure_options_dict.keys():
        figure_options_wid.children[2].value = \
            figure_options_dict['render_axes']

    # update axes_font_name dropdown menu
    if 'axes_font_name' in figure_options_dict.keys():
        figure_options_wid.children[3].value = \
            figure_options_dict['axes_font_name']

    # update axes_font_size text box
    if 'axes_font_size' in figure_options_dict.keys():
        figure_options_wid.children[4].value = \
            int(figure_options_dict['axes_font_size'])

    # update axes_font_style dropdown menu
    if 'axes_font_style' in figure_options_dict.keys():
        figure_options_wid.children[5].value = \
            figure_options_dict['axes_font_style']

    # update axes_font_weight dropdown menu
    if 'axes_font_weight' in figure_options_dict.keys():
        figure_options_wid.children[6].value = \
            figure_options_dict['axes_font_weight']

    # update axes_x_limits
    if 'axes_x_limits' in figure_options_dict.keys():
        if figure_options_dict['axes_x_limits'] is None:
            tmp1 = False
            tmp2 = 0.
            tmp3 = 100.
        else:
            tmp1 = True
            tmp2 = figure_options_dict['axes_x_limits'][0]
            tmp3 = figure_options_dict['axes_x_limits'][1]
        figure_options_wid.children[7].children[0].value = tmp1
        figure_options_wid.children[7].children[1].value = tmp2
        figure_options_wid.children[7].children[2].value = tmp3

    # update axes_y_limits
    if 'axes_y_limits' in figure_options_dict.keys():
        if figure_options_dict['axes_y_limits'] is None:
            tmp1 = False
            tmp2 = 0.
            tmp3 = 100.
        else:
            tmp1 = True
            tmp2 = figure_options_dict['axes_y_limits'][0]
            tmp3 = figure_options_dict['axes_y_limits'][1]
        figure_options_wid.children[8].children[0].value = tmp1
        figure_options_wid.children[8].children[1].value = tmp2
        figure_options_wid.children[8].children[2].value = tmp3


def figure_options_two_scales(figure_options_default, plot_function=None,
                              coupled_default=False,
                              figure_scales_bounds=(0.1, 4),
                              figure_scales_step=0.1,
                              figure_scales_visible=True,
                              axes_visible=True, toggle_show_default=True,
                              toggle_show_visible=True):
    r"""
    Creates a widget with Figure Options. Specifically, it has:
        1) A slider that controls the scaling of the figure.
        2) A checkbox that controls the visibility of the figure's axes.
        3) Font options for the axes.
        4) A toggle button that controls the visibility of all the above, i.e.
           the figure options.

    The structure of the widgets is the following:
        figure_options_wid.children = [toggle_button, figure_scale_slider,
                                       show_axes_checkbox, axes_font_name,
                                       axes_font_size, axes_font_style,
                                       axes_font_weight, axes_x_limits,
                                       axes_y_limits]

    The returned widget saves the selected values in the following dictionary:
        figure_options_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_figure_options()` function.

    Parameters
    ----------
    figure_options_default : `dict`
        The initial selected figure options.
        Example:
            figure_options_default = {'x_scale': 1.,
                                      'y_scale': 1.,
                                      'render_axes': True,
                                      'axes_font_name': 'serif',
                                      'axes_font_size': 10,
                                      'axes_font_style': 'normal',
                                      'axes_font_weight': 'normal',
                                      'axes_x_limits': None,
                                      'axes_y_limits': None}
    plot_function : `function` or None, optional
        The plot function that is executed when a widgets' value changes.
        If None, then nothing is assigned.
    figure_scale_bounds : (`float`, `float`), optional
        The range of scales that can be optionally applied to the figure.
    figure_scale_step : `float`, optional
        The step of the scale sliders.
    figure_scale_visible : `boolean`, optional
        The visibility of the figure scales sliders.
    show_axes_visible : `boolean`, optional
        The visibility of the axes checkbox.
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    """
    import IPython.html.widgets as ipywidgets
    # Create widgets
    # toggle button
    but = ipywidgets.ToggleButtonWidget(description='Figure Options',
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # figure_scale, render_axes
    x_scale = ipywidgets.FloatSliderWidget(description='Figure size: X scale',
                                           value=figure_options_default[
                                               'x_scale'],
                                           min=figure_scales_bounds[0],
                                           max=figure_scales_bounds[1],
                                           step=figure_scales_step)
    y_scale = ipywidgets.FloatSliderWidget(description='Y scale',
                                           value=figure_options_default[
                                               'y_scale'],
                                           min=figure_scales_bounds[0],
                                           max=figure_scales_bounds[1],
                                           step=figure_scales_step,
                                           disabled=coupled_default)
    coupled = ipywidgets.CheckboxWidget(description='Coupled',
                                        value=coupled_default)
    figure_scale = ipywidgets.ContainerWidget(
        children=[x_scale, y_scale, coupled],
        visible=figure_scales_visible)
    render_axes = ipywidgets.CheckboxWidget(description='Render axes',
                                            value=figure_options_default[
                                                'render_axes'],
                                            visible=axes_visible)
    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'
    axes_font_name = ipywidgets.DropdownWidget(
        values=axes_font_name_dict,
        value=figure_options_default['axes_font_name'], description='Font',
        visible=axes_visible)
    axes_font_size = ipywidgets.BoundedIntTextWidget(
        description='Size', value=figure_options_default['axes_font_size'],
        min=0, visible=axes_visible)
    axes_font_style_dict = OrderedDict()
    axes_font_style_dict['normal'] = 'normal'
    axes_font_style_dict['italic'] = 'italic'
    axes_font_style_dict['oblique'] = 'oblique'
    axes_font_style = ipywidgets.DropdownWidget(
        values=axes_font_style_dict,
        value=figure_options_default['axes_font_style'],
        description='Style', visible=axes_visible)
    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'
    axes_font_weight = ipywidgets.DropdownWidget(
        values=axes_font_weight_dict,
        value=figure_options_default['axes_font_weight'],
        description='Weight', visible=axes_visible)
    if figure_options_default['axes_x_limits'] is None:
        tmp1 = False
        tmp2 = 0.
        tmp3 = 0.
    else:
        tmp1 = True
        tmp2 = figure_options_default['axes_x_limits'][0]
        tmp3 = figure_options_default['axes_x_limits'][1]
    axes_x_limits_enable = ipywidgets.CheckboxWidget(value=tmp1,
                                                     description='X limits')
    axes_x_limits_from = ipywidgets.FloatTextWidget(value=tmp2, description='')
    axes_x_limits_to = ipywidgets.FloatTextWidget(value=tmp3, description='')
    axes_x_limits = ipywidgets.ContainerWidget(children=[axes_x_limits_enable,
                                                         axes_x_limits_from,
                                                         axes_x_limits_to])
    if figure_options_default['axes_y_limits'] is None:
        tmp1 = False
        tmp2 = 0.
        tmp3 = 0.
    else:
        tmp1 = True
        tmp2 = figure_options_default['axes_y_limits'][0]
        tmp3 = figure_options_default['axes_y_limits'][1]
    axes_y_limits_enable = ipywidgets.CheckboxWidget(value=tmp1,
                                                     description='Y limits')
    axes_y_limits_from = ipywidgets.FloatTextWidget(value=tmp2, description='')
    axes_y_limits_to = ipywidgets.FloatTextWidget(value=tmp3, description='')
    axes_y_limits = ipywidgets.ContainerWidget(children=[axes_y_limits_enable,
                                                         axes_y_limits_from,
                                                         axes_y_limits_to])

    # Final widget
    figure_options_wid = ipywidgets.ContainerWidget(children=[but, figure_scale,
                                                              render_axes,
                                                              axes_font_name,
                                                              axes_font_size,
                                                              axes_font_style,
                                                              axes_font_weight,
                                                              axes_x_limits,
                                                              axes_y_limits])

    # Assign output
    figure_options_wid.selected_values = figure_options_default

    # font options visibility
    def options_visible(name, value):
        axes_font_name.disabled = not value
        axes_font_size.disabled = not value
        axes_font_style.disabled = not value
        axes_font_weight.disabled = not value
        axes_x_limits.disabled = not value
        axes_y_limits.disabled = not value
    options_visible('', figure_options_default['render_axes'])
    render_axes.on_trait_change(options_visible, 'value')

    # Coupled sliders function
    def coupled_sliders(name, value):
        y_scale.disabled = value
    coupled_sliders('', coupled_default)
    coupled.on_trait_change(coupled_sliders, 'value')

    # get options functions
    def save_render_axes(name, value):
        figure_options_wid.selected_values['render_axes'] = value
    render_axes.on_trait_change(save_render_axes, 'value')

    def save_axes_font_name(name, value):
        figure_options_wid.selected_values['axes_font_name'] = value
    axes_font_name.on_trait_change(save_axes_font_name, 'value')

    def save_axes_font_size(name, value):
        figure_options_wid.selected_values['axes_font_size'] = int(value)
    axes_font_size.on_trait_change(save_axes_font_size, 'value')

    def save_axes_font_style(name, value):
        figure_options_wid.selected_values['axes_font_style'] = value
    axes_font_style.on_trait_change(save_axes_font_style, 'value')

    def save_axes_font_weight(name, value):
        figure_options_wid.selected_values['axes_font_weight'] = value
    axes_font_weight.on_trait_change(save_axes_font_weight, 'value')

    def axes_x_limits_disable(name, value):
        axes_x_limits_from.disabled = not value
        axes_x_limits_to.disabled = not value
    axes_x_limits_enable.on_trait_change(axes_x_limits_disable, 'value')

    def axes_y_limits_disable(name, value):
        axes_y_limits_from.disabled = not value
        axes_y_limits_to.disabled = not value
    axes_y_limits_enable.on_trait_change(axes_y_limits_disable, 'value')

    def save_axes_x_limits(name, value):
        if axes_x_limits_enable.value:
            figure_options_wid.selected_values['axes_x_limits'] = \
                (axes_x_limits_from.value, axes_x_limits_to.value)
        else:
            figure_options_wid.selected_values['axes_x_limits'] = None
    axes_x_limits_enable.on_trait_change(save_axes_x_limits, 'value')
    axes_x_limits_from.on_trait_change(save_axes_x_limits, 'value')
    axes_x_limits_to.on_trait_change(save_axes_x_limits, 'value')

    def save_axes_y_limits(name, value):
        if axes_y_limits_enable.value:
            figure_options_wid.selected_values['axes_y_limits'] = \
                (axes_y_limits_from.value, axes_y_limits_to.value)
        else:
            figure_options_wid.selected_values['axes_y_limits'] = None
    axes_y_limits_enable.on_trait_change(save_axes_y_limits, 'value')
    axes_y_limits_from.on_trait_change(save_axes_y_limits, 'value')
    axes_y_limits_to.on_trait_change(save_axes_y_limits, 'value')

    def save_x_scale(name, old_value, value):
        figure_options_wid.selected_values['x_scale'] = value
        if coupled.value:
            y_scale.value += value - old_value
    x_scale.on_trait_change(save_x_scale, 'value')

    def save_y_scale(name, value):
        figure_options_wid.selected_values['y_scale'] = value
    y_scale.on_trait_change(save_y_scale, 'value')

    # Toggle button function
    def toggle_fun(name, value):
        figure_scale.visible = value
        render_axes.visible = value
        axes_font_name.visible = value
        axes_font_size.visible = value
        axes_font_style.visible = value
        axes_font_weight.visible = value
        axes_x_limits.visible = value
        axes_y_limits.visible = value
    toggle_fun('', toggle_show_default)
    but.on_trait_change(toggle_fun, 'value')

    # assign plot_function
    if plot_function is not None:
        x_scale.on_trait_change(plot_function, 'value')
        y_scale.on_trait_change(plot_function, 'value')
        coupled.on_trait_change(plot_function, 'value')
        render_axes.on_trait_change(plot_function, 'value')
        axes_font_name.on_trait_change(plot_function, 'value')
        axes_font_size.on_trait_change(plot_function, 'value')
        axes_font_style.on_trait_change(plot_function, 'value')
        axes_font_weight.on_trait_change(plot_function, 'value')
        axes_x_limits_from.on_trait_change(plot_function, 'value')
        axes_x_limits_to.on_trait_change(plot_function, 'value')
        axes_x_limits_enable.on_trait_change(plot_function, 'value')
        axes_y_limits_from.on_trait_change(plot_function, 'value')
        axes_y_limits_to.on_trait_change(plot_function, 'value')
        axes_y_limits_enable.on_trait_change(plot_function, 'value')

    return figure_options_wid


def format_figure_options_two_scales(figure_options_wid,
                                     container_padding='6px',
                                     container_margin='6px',
                                     container_border='1px solid black',
                                     toggle_button_font_weight='bold',
                                     border_visible=True):
    r"""
    Function that corrects the align (style format) of a given
    figure_options_two_scales widget. Usage example:
        figure_options_wid = figure_options_two_scales()
        display(figure_options_wid)
        format_figure_options_two_scales(figure_options_wid)

    Parameters
    ----------
    figure_options_wid :
        The widget object generated by the `figure_options_two_scales()`
        function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    """
    # align figure scale sliders and checkbox
    # figure_options_wid.children[1].remove_class('vbox')
    # figure_options_wid.children[1].add_class('hbox')
    figure_options_wid.children[1].add_class('align-end')

    # fix figure scale sliders width
    figure_options_wid.children[1].children[0].set_css('width', '3cm')
    figure_options_wid.children[1].children[1].set_css('width', '3cm')

    # fix font size width
    figure_options_wid.children[4].set_css('width', '1cm')

    # align and set width of axes_x_limits
    figure_options_wid.children[7].remove_class('vbox')
    figure_options_wid.children[7].add_class('hbox')
    figure_options_wid.children[7].children[1].set_css('width', '1cm')
    figure_options_wid.children[7].children[2].set_css('width', '1cm')

    # align and set width of axes_y_limits
    figure_options_wid.children[8].remove_class('vbox')
    figure_options_wid.children[8].add_class('hbox')
    figure_options_wid.children[8].children[1].set_css('width', '1cm')
    figure_options_wid.children[8].children[2].set_css('width', '1cm')

    # set toggle button font bold
    figure_options_wid.children[0].set_css('font-weight',
                                           toggle_button_font_weight)

    # margin and border around container widget
    figure_options_wid.set_css('padding', container_padding)
    figure_options_wid.set_css('margin', container_margin)
    if border_visible:
        figure_options_wid.set_css('border', container_border)


def update_figure_options_two_scales(figure_options_wid, figure_options_dict):
    r"""
    Function that updates the state of a given figure_options_two_scales widget.
    Usage example:
        figure_options_default = {'x_scale': 1.,
                                  'y_scale': 1.,
                                  'render_axes': True,
                                  'axes_font_name': 'serif',
                                  'axes_font_size': 10,
                                  'axes_font_style': 'normal',
                                  'axes_font_weight': 'normal',
                                  'axes_x_limits': None,
                                  'axes_y_limits': None}
        figure_options_wid = figure_options_two_scales(default_figure_options)
        display(figure_options_wid)
        format_figure_options_two_scales(figure_options_wid)
        figure_options_default = {'x_scale': 1.,
                                  'y_scale': 1.,
                                  'render_axes': True,
                                  'axes_font_name': 'serif',
                                  'axes_font_size': 10,
                                  'axes_font_style': 'normal',
                                  'axes_font_weight': 'normal',
                                  'axes_x_limits': None,
                                  'axes_y_limits': None}
        update_figure_options_two_scales(figure_options_wid,
                                         default_figure_options)

    Parameters
    ----------
    figure_options_wid :
        The widget object generated by the `figure_options_two_scales()`
        function.
    figure_options_dict : `dict`
        The new set of options. For example:
            figure_options_default = {'x_scale': 1.,
                                      'y_scale': 1.,
                                      'render_axes': True,
                                      'axes_font_name': 'serif',
                                      'axes_font_size': 10,
                                      'axes_font_style': 'normal',
                                      'axes_font_weight': 'normal',
                                      'axes_x_limits': None,
                                      'axes_y_limits': None}
    """
    # Assign new options dict to selected_values
    figure_options_wid.selected_values = figure_options_dict

    # update scale slider
    if ('x_scale' in figure_options_dict.keys() and
            'y_scale' not in figure_options_dict.keys()):
        figure_options_wid.children[1].children[0].value = \
            figure_options_dict['x_scale']
        figure_options_wid.children[1].children[2].value = False
    elif ('x_scale' not in figure_options_dict.keys() and
            'y_scale' in figure_options_dict.keys()):
        figure_options_wid.children[1].children[1].value = \
            figure_options_dict['y_scale']
        figure_options_wid.children[1].children[2].value = False
    elif ('x_scale' in figure_options_dict.keys() and
            'y_scale' in figure_options_dict.keys()):
        figure_options_wid.children[1].children[0].value = \
            figure_options_dict['x_scale']
        figure_options_wid.children[1].children[1].value = \
            figure_options_dict['y_scale']
        figure_options_wid.children[1].children[2].value = \
            figure_options_dict['x_scale'] == figure_options_dict['y_scale']

    # update render axes checkbox
    if 'render_axes' in figure_options_dict.keys():
        figure_options_wid.children[2].value = \
            figure_options_dict['render_axes']

    # update axes_font_name dropdown menu
    if 'axes_font_name' in figure_options_dict.keys():
        figure_options_wid.children[3].value = \
            figure_options_dict['axes_font_name']

    # update axes_font_size text box
    if 'axes_font_size' in figure_options_dict.keys():
        figure_options_wid.children[4].value = \
            int(figure_options_dict['axes_font_size'])

    # update axes_font_style dropdown menu
    if 'axes_font_style' in figure_options_dict.keys():
        figure_options_wid.children[5].value = \
            figure_options_dict['axes_font_style']

    # update axes_font_weight dropdown menu
    if 'axes_font_weight' in figure_options_dict.keys():
        figure_options_wid.children[6].value = \
            figure_options_dict['axes_font_weight']

    # update axes_x_limits
    if 'axes_x_limits' in figure_options_dict.keys():
        if figure_options_dict['axes_x_limits'] is None:
            tmp1 = False
            tmp2 = 0.
            tmp3 = 0.
        else:
            tmp1 = True
            tmp2 = figure_options_dict['axes_x_limits'][0]
            tmp3 = figure_options_dict['axes_x_limits'][1]
        figure_options_wid.children[7].children[0].value = tmp1
        figure_options_wid.children[7].children[1].value = tmp2
        figure_options_wid.children[7].children[2].value = tmp3

    # update axes_y_limits
    if 'axes_y_limits' in figure_options_dict.keys():
        if figure_options_dict['axes_y_limits'] is None:
            tmp1 = False
            tmp2 = 0.
            tmp3 = 0.
        else:
            tmp1 = True
            tmp2 = figure_options_dict['axes_y_limits'][0]
            tmp3 = figure_options_dict['axes_y_limits'][1]
        figure_options_wid.children[8].children[0].value = tmp1
        figure_options_wid.children[8].children[1].value = tmp2
        figure_options_wid.children[8].children[2].value = tmp3


def legend_options(legend_options_default, plot_function=None,
                   toggle_show_visible=True, toggle_show_default=True,
                   toggle_title='Legend Options',
                   show_checkbox_title='Render legend'):
    r"""
    Creates a widget with Legend Options. Specifically, it has:
        1) A checkbox that controls legend's visibility.
        2) A tab widget with legend_location, font and formatting options.
        3) A toggle button that controls the visibility of all the above, i.e.
           the font options.

    The structure of the widgets is the following:
        legend_options_wid.children = [toggle_button, options]
        options.children = [show_legend_checkbox, other_options]
        other_options.children = [legend_location, font, formatting]
        ...

    The returned widget saves the selected values in the following dictionary:
        legend_options_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_legend_options()` function.

    Parameters
    ----------
    legend_options_default : `dict`
        The initial selected font options.
        Example:
            legend_options_default = {'render_legend':True,
                                      'legend_title':'',
                                      'legend_font_name':'serif',
                                      'legend_font_style':'normal',
                                      'legend_font_size':10,
                                      'legend_font_weight':'normal',
                                      'legend_marker_scale':1.,
                                      'legend_location':2,
                                      'legend_bbox_to_anchor':(1.05, 1.),
                                      'legend_border_axes_pad':1.,
                                      'legend_n_columns':1,
                                      'legend_horizontal_spacing':1.,
                                      'legend_vertical_spacing':1.,
                                      'legend_border':True,
                                      'legend_border_padding':0.5,
                                      'legend_shadow':False,
                                      'legend_rounded_corners':True}
    plot_function : `function` or None, optional
        The plot function that is executed when a widgets' value changes.
        If None, then nothing is assigned.
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    toggle_title : `str`, optional
        The legend_title of the toggle button.
    show_checkbox_title : `str`, optional
        The description of the show text checkbox.
    """
    import IPython.html.widgets as ipywidgets
    # Create widgets
    # toggle button
    but = ipywidgets.ToggleButtonWidget(description=toggle_title,
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # render legend
    render_legend = ipywidgets.CheckboxWidget(
        description=show_checkbox_title,
        value=legend_options_default['render_legend'])

    # font-related
    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'
    legend_font_name = ipywidgets.DropdownWidget(
        values=legend_font_name_dict,
        value=legend_options_default['legend_font_name'], description='Font')
    legend_font_size = ipywidgets.BoundedIntTextWidget(
        description='Size', value=legend_options_default['legend_font_size'],
        min=0)
    legend_font_style_dict = OrderedDict()
    legend_font_style_dict['normal'] = 'normal'
    legend_font_style_dict['italic'] = 'italic'
    legend_font_style_dict['oblique'] = 'oblique'
    legend_font_style = ipywidgets.DropdownWidget(
        values=legend_font_style_dict,
        value=legend_options_default['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'
    legend_font_weight = ipywidgets.DropdownWidget(
        values=legend_font_weight_dict,
        value=legend_options_default['legend_font_weight'],
        description='Weight')
    legend_title = ipywidgets.TextWidget(description='Title',
                                         value=legend_options_default[
                                             'legend_title'])
    font_cont_tmp = ipywidgets.ContainerWidget(
        children=[ipywidgets.ContainerWidget(children=[legend_font_name,
                                                       legend_font_size]),
                  ipywidgets.ContainerWidget(children=[legend_font_style,
                                                       legend_font_weight])])
    font_cont = ipywidgets.ContainerWidget(
        children=[legend_title, font_cont_tmp])

    # legend_location-related
    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
    legend_location = ipywidgets.DropdownWidget(
        values=legend_location_dict,
        value=legend_options_default['legend_location'],
        description='Predefined location')
    if legend_options_default['legend_bbox_to_anchor'] is None:
        tmp1 = False
        tmp2 = 0.
        tmp3 = 0.
    else:
        tmp1 = True
        tmp2 = legend_options_default['legend_bbox_to_anchor'][0]
        tmp3 = legend_options_default['legend_bbox_to_anchor'][1]
    bbox_to_anchor_enable = ipywidgets.CheckboxWidget(
        value=tmp1, description='Arbitrary location')
    bbox_to_anchor_x = ipywidgets.FloatTextWidget(value=tmp2, description='')
    bbox_to_anchor_y = ipywidgets.FloatTextWidget(value=tmp3, description='')
    legend_bbox_to_anchor = ipywidgets.ContainerWidget(
        children=[bbox_to_anchor_enable,
                  bbox_to_anchor_x,
                  bbox_to_anchor_y])
    legend_border_axes_pad = ipywidgets.BoundedFloatTextWidget(
        value=legend_options_default['legend_border_axes_pad'],
        description='Distance to axes', min=0.)
    location_cont = ipywidgets.ContainerWidget(
        children=[legend_location, legend_bbox_to_anchor,
                  legend_border_axes_pad])

    # formatting-related
    legend_n_columns = ipywidgets.BoundedIntTextWidget(
        value=legend_options_default['legend_n_columns'], description='Columns',
        min=0)
    legend_marker_scale = ipywidgets.BoundedFloatTextWidget(
        description='Marker scale',
        value=legend_options_default['legend_marker_scale'], min=0.)
    legend_horizontal_spacing = ipywidgets.BoundedFloatTextWidget(
        value=legend_options_default['legend_horizontal_spacing'],
        description='Horizontal space', min=0.)
    legend_vertical_spacing = ipywidgets.BoundedFloatTextWidget(
        value=legend_options_default['legend_vertical_spacing'],
        description='Vertical space', min=0.)
    spacing = ipywidgets.ContainerWidget(
        children=[ipywidgets.ContainerWidget(children=[legend_n_columns,
                                                       legend_marker_scale]),
                  ipywidgets.ContainerWidget(
                      children=[legend_horizontal_spacing,
                                legend_vertical_spacing])])
    legend_border = ipywidgets.CheckboxWidget(
        description='Border',
        value=legend_options_default['legend_border'])
    legend_border_padding = ipywidgets.BoundedFloatTextWidget(
        value=legend_options_default['legend_border_padding'],
        description='Border pad', min=0.)
    border = ipywidgets.ContainerWidget(
        children=[legend_border, legend_border_padding])
    legend_shadow = ipywidgets.CheckboxWidget(
        description='Shadow', value=legend_options_default['legend_shadow'])
    legend_rounded_corners = ipywidgets.CheckboxWidget(
        description='Rounded corners',
        value=legend_options_default['legend_rounded_corners'])
    shadow_fancy = ipywidgets.ContainerWidget(children=[legend_shadow,
                                                        legend_rounded_corners])

    formatting_cont = ipywidgets.ContainerWidget(
        children=[spacing, border, shadow_fancy])

    # Options widget
    tab_options = ipywidgets.TabWidget(children=[location_cont, font_cont,
                                                 formatting_cont])
    options_wid = ipywidgets.ContainerWidget(
        children=[render_legend, tab_options])

    # Final widget
    legend_options_wid = ipywidgets.ContainerWidget(children=[but, options_wid])

    # Assign output
    legend_options_wid.selected_values = legend_options_default

    # font options visibility
    def options_visible(name, value):
        legend_title.disabled = not value
        legend_font_name.disabled = not value
        legend_font_size.disabled = not value
        legend_font_style.disabled = not value
        legend_font_weight.disabled = not value
        legend_location.disabled = not value
        bbox_to_anchor_enable.disabled = not value
        bbox_to_anchor_x.disabled = not value or not bbox_to_anchor_enable.value
        bbox_to_anchor_y.disabled = not value or not bbox_to_anchor_enable.value
        legend_border_axes_pad.disabled = not value
        legend_n_columns.disabled = not value
        legend_marker_scale.disabled = not value
        legend_horizontal_spacing.disabled = not value
        legend_vertical_spacing.disabled = not value
        legend_border.disabled = not value
        legend_border_padding.disabled = not value or not legend_border.value
        legend_shadow.disabled = not value
        legend_rounded_corners.disabled = not value
    options_visible('', legend_options_default['render_legend'])
    render_legend.on_trait_change(options_visible, 'value')

    # get options functions
    def border_pad_disable(name, value):
        legend_border_padding.disabled = not value
    legend_border.on_trait_change(border_pad_disable, 'value')

    def bbox_to_anchor_disable(name, value):
        bbox_to_anchor_x.disabled = not value
        bbox_to_anchor_y.disabled = not value
    bbox_to_anchor_enable.on_trait_change(bbox_to_anchor_disable, 'value')

    def save_show_legend(name, value):
        legend_options_wid.selected_values['render_legend'] = value
    render_legend.on_trait_change(save_show_legend, 'value')

    def save_title(name, value):
        legend_options_wid.selected_values['legend_title'] = str(value)
    legend_title.on_trait_change(save_title, 'value')

    def save_fontname(name, value):
        legend_options_wid.selected_values['legend_font_name'] = value
    legend_font_name.on_trait_change(save_fontname, 'value')

    def save_fontsize(name, value):
        legend_options_wid.selected_values['legend_font_size'] = int(value)
    legend_font_size.on_trait_change(save_fontsize, 'value')

    def save_fontstyle(name, value):
        legend_options_wid.selected_values['legend_font_style'] = value
    legend_font_style.on_trait_change(save_fontstyle, 'value')

    def save_fontweight(name, value):
        legend_options_wid.selected_values['legend_font_weight'] = value
    legend_font_weight.on_trait_change(save_fontweight, 'value')

    def save_location(name, value):
        legend_options_wid.selected_values['legend_location'] = value
    legend_location.on_trait_change(save_location, 'value')

    def save_bbox_to_anchor(name, value):
        if bbox_to_anchor_enable.value:
            legend_options_wid.selected_values['legend_bbox_to_anchor'] = \
                (bbox_to_anchor_x.value, bbox_to_anchor_y.value)
        else:
            legend_options_wid.selected_values['legend_bbox_to_anchor'] = None
    bbox_to_anchor_enable.on_trait_change(save_bbox_to_anchor, 'value')
    bbox_to_anchor_x.on_trait_change(save_bbox_to_anchor, 'value')
    bbox_to_anchor_y.on_trait_change(save_bbox_to_anchor, 'value')

    def save_borderaxespad(name, value):
        key = 'legend_border_axes_pad'
        legend_options_wid.selected_values[key] = float(value)
    legend_border_axes_pad.on_trait_change(save_borderaxespad, 'value')

    def save_n_columns(name, value):
        legend_options_wid.selected_values['legend_n_columns'] = int(value)
    legend_n_columns.on_trait_change(save_n_columns, 'value')

    def save_markerscale(name, value):
        legend_options_wid.selected_values['legend_marker_scale'] = float(value)
    legend_marker_scale.on_trait_change(save_markerscale, 'value')

    def save_horizontal_spacing(name, value):
        legend_options_wid.selected_values['legend_horizontal_spacing'] = \
            float(value)
    legend_horizontal_spacing.on_trait_change(save_horizontal_spacing, 'value')

    def save_vertical_spacing(name, value):
        legend_options_wid.selected_values['legend_vertical_spacing'] = \
            float(value)
    legend_vertical_spacing.on_trait_change(save_vertical_spacing, 'value')

    def save_draw_border(name, value):
        legend_options_wid.selected_values['legend_border'] = value
    legend_border.on_trait_change(save_draw_border, 'value')

    def save_border_padding(name, value):
        legend_options_wid.selected_values['legend_border_padding'] = \
            float(value)
    legend_border_padding.on_trait_change(save_border_padding, 'value')

    def save_draw_shadow(name, value):
        legend_options_wid.selected_values['legend_shadow'] = value
    legend_shadow.on_trait_change(save_draw_shadow, 'value')

    def save_fancy_corners(name, value):
        legend_options_wid.selected_values['legend_rounded_corners'] = value
    legend_rounded_corners.on_trait_change(save_fancy_corners, 'value')

    # Toggle button function
    def toggle_fun(name, value):
        options_wid.visible = value
    toggle_fun('', toggle_show_default)
    but.on_trait_change(toggle_fun, 'value')

    # assign plot_function
    if plot_function is not None:
        render_legend.on_trait_change(plot_function, 'value')
        legend_title.on_trait_change(plot_function, 'value')
        legend_font_name.on_trait_change(plot_function, 'value')
        legend_font_style.on_trait_change(plot_function, 'value')
        legend_font_size.on_trait_change(plot_function, 'value')
        legend_font_weight.on_trait_change(plot_function, 'value')
        legend_location.on_trait_change(plot_function, 'value')
        bbox_to_anchor_enable.on_trait_change(plot_function, 'value')
        bbox_to_anchor_x.on_trait_change(plot_function, 'value')
        bbox_to_anchor_y.on_trait_change(plot_function, 'value')
        legend_border_axes_pad.on_trait_change(plot_function, 'value')
        legend_n_columns.on_trait_change(plot_function, 'value')
        legend_marker_scale.on_trait_change(plot_function, 'value')
        legend_horizontal_spacing.on_trait_change(plot_function, 'value')
        legend_vertical_spacing.on_trait_change(plot_function, 'value')
        legend_border.on_trait_change(plot_function, 'value')
        legend_border_padding.on_trait_change(plot_function, 'value')
        legend_shadow.on_trait_change(plot_function, 'value')
        legend_rounded_corners.on_trait_change(plot_function, 'value')

    return legend_options_wid


def format_legend_options(legend_options_wid, container_padding='6px',
                          container_margin='6px',
                          container_border='1px solid black',
                          toggle_button_font_weight='bold',
                          border_visible=True, suboptions_border_visible=False):
    r"""
    Function that corrects the align (style format) of a given legend_options
    widget. Usage example:
        legend_options_wid = legend_options()
        display(legend_options_wid)
        format_legend_options(legend_options_wid)

    Parameters
    ----------
    legend_options_wid :
        The widget object generated by the `legend_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    suboptions_border_visible : `boolean`, optional
        Defines whether to draw the border line around the legend options, under
        the show legend checkbox.
    """
    # set tab titles
    tab_titles = ['Location', 'Font', 'Formatting']
    for (k, tl) in enumerate(tab_titles):
        legend_options_wid.children[1].children[1].set_title(k, tl)

    # align font-related options
    # legend_options_wid.children[1].children[1].children[1].children[1].\
    #    remove_class('vbox')
    # legend_options_wid.children[1].children[1].children[1].children[1].\
    #    add_class('hbox')

    # set fontsize and title text box width
    legend_options_wid.children[1].children[1].children[1].children[1].children[
        0].children[1].set_css('width', '1cm')
    legend_options_wid.children[1].children[1].children[1].children[0]. \
        set_css('width', '4cm')

    # align and set width of bbox_to_anchor
    legend_options_wid.children[1].children[1].children[0].children[1]. \
        remove_class('vbox')
    legend_options_wid.children[1].children[1].children[0].children[1]. \
        add_class('hbox')
    legend_options_wid.children[1].children[1].children[0].children[1].children[
        1]. \
        set_css('width', '1cm')
    legend_options_wid.children[1].children[1].children[0].children[1].children[
        2]. \
        set_css('width', '1cm')

    # set distance to axes (borderaxespad) text box width
    legend_options_wid.children[1].children[1].children[0].children[2]. \
        set_css('width', '1cm')

    # align and set width of border options
    legend_options_wid.children[1].children[1].children[2].children[1]. \
        remove_class('vbox')
    legend_options_wid.children[1].children[1].children[2].children[1]. \
        add_class('hbox')
    legend_options_wid.children[1].children[1].children[2].children[1].children[
        0]. \
        set_css('width', '1cm')
    legend_options_wid.children[1].children[1].children[2].children[1].children[
        1]. \
        set_css('width', '1cm')

    # align shadow and fancy checkboxes
    legend_options_wid.children[1].children[1].children[2].children[2]. \
        remove_class('vbox')
    legend_options_wid.children[1].children[1].children[2].children[2]. \
        add_class('hbox')

    # align and set width of spacing options
    legend_options_wid.children[1].children[1].children[2].children[0].children[
        1]. \
        add_class('align-end')
    legend_options_wid.children[1].children[1].children[2].children[0].children[
        1].children[0].set_css('width', '1cm')
    legend_options_wid.children[1].children[1].children[2].children[0].children[
        1].children[1].set_css('width', '1cm')

    # set width of n_columns and markerspace
    legend_options_wid.children[1].children[1].children[2].children[0].children[
        0]. \
        add_class('align-end')
    legend_options_wid.children[1].children[1].children[2].children[0].children[
        0].children[0].set_css('width', '1cm')
    legend_options_wid.children[1].children[1].children[2].children[0].children[
        0].children[1].set_css('width', '1cm')

    # align n_columns with spacing
    legend_options_wid.children[1].children[1].children[2].children[0]. \
        remove_class('vbox')
    legend_options_wid.children[1].children[1].children[2].children[0]. \
        add_class('hbox')

    # border around options
    if suboptions_border_visible:
        legend_options_wid.children[1].children[1].set_css('border',
                                                           container_border)

    # set toggle button font bold
    legend_options_wid.children[0].set_css('font-weight',
                                           toggle_button_font_weight)

    # margin and border around container widget
    legend_options_wid.set_css('padding', container_padding)
    legend_options_wid.set_css('margin', container_margin)
    if border_visible:
        legend_options_wid.set_css('border', container_border)


def update_legend_options(legend_options_wid, legend_options_dict):
    r"""
    Function that updates the state of a given font_options widget. Usage
    example:
        legend_options_default = {'render_legend':True,
                                  'legend_title':'',
                                  'legend_font_name':'serif',
                                  'legend_font_style':'normal',
                                  'legend_font_size':10,
                                  'legend_font_weight':'normal',
                                  'legend_marker_scale':1.,
                                  'legend_location':2,
                                  'legend_bbox_to_anchor':(1.05, 1.),
                                  'legend_border_axes_pad':1.,
                                  'legend_n_columns':1,
                                  'legend_horizontal_spacing':1.,
                                  'legend_vertical_spacing':1.,
                                  'legend_border':True,
                                  'legend_border_padding':0.5,
                                  'legend_shadow':False,
                                  'legend_rounded_corners':True}
        legend_options_wid = legend_options(legend_options_default)
        display(legend_options_wid)
        format_legend_options(legend_options_wid)
        legend_options_default = {'render_legend':True,
                                  'legend_title':'',
                                  'legend_font_name':'serif',
                                  'legend_font_style':'normal',
                                  'legend_font_size':10,
                                  'legend_font_weight':'normal',
                                  'legend_marker_scale':1.,
                                  'legend_location':2,
                                  'legend_bbox_to_anchor':(1.05, 1.),
                                  'legend_border_axes_pad':1.,
                                  'legend_n_columns':1,
                                  'legend_horizontal_spacing':1.,
                                  'legend_vertical_spacing':1.,
                                  'legend_border':True,
                                  'legend_border_padding':0.5,
                                  'legend_shadow':False,
                                  'legend_rounded_corners':True}
        update_legend_options(legend_options_wid, legend_options_dict)

    Parameters
    ----------
    legend_options_wid :
        The widget object generated by the `legend_options()` function.
    legend_options_dict : `dict`
        The new set of options. For example:
            legend_options_dict = {'render_legend':True,
                                   'legend_title':'',
                                   'legend_font_name':'serif',
                                   'legend_font_style':'normal',
                                   'legend_font_size':10,
                                   'legend_font_weight':'normal',
                                   'legend_marker_scale':1.,
                                   'legend_location':2,
                                   'legend_bbox_to_anchor':(1.05, 1.),
                                   'legend_border_axes_pad':1.,
                                   'legend_n_columns':1,
                                   'legend_horizontal_spacing':1.,
                                   'legend_vertical_spacing':1.,
                                   'legend_border':True,
                                   'legend_border_padding':0.5,
                                   'legend_shadow':False,
                                   'legend_rounded_corners':True}
    """
    # Assign new options dict to selected_values
    legend_options_wid.selected_values = legend_options_dict

    # update render legend checkbox
    if 'render_legend' in legend_options_dict.keys():
        legend_options_wid.children[1].children[0].value = \
            legend_options_dict['render_legend']

    # update legend_title
    if 'legend_title' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[1].children[0]. \
            value = legend_options_dict['legend_title']

    # update legend_font_name dropdown menu
    if 'legend_font_name' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[1].children[
            1].children[0].children[0].value = \
            legend_options_dict['legend_font_name']

    # update legend_font_size text box
    if 'legend_font_size' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[1].children[
            1].children[0].children[1].value = \
            int(legend_options_dict['legend_font_size'])

    # update legend_font_style dropdown menu
    if 'legend_font_style' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[1].children[
            1].children[1].children[0].value = \
            legend_options_dict['legend_font_style']

    # update legend_font_weight dropdown menu
    if 'legend_font_weight' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[1].children[
            1].children[1].children[1].value = \
            legend_options_dict['legend_font_weight']

    # update legend_location dropdown menu
    if 'legend_location' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[0].children[0]. \
            value = legend_options_dict['legend_location']

    # update legend_bbox_to_anchor
    if 'legend_bbox_to_anchor' in legend_options_dict.keys():
        if legend_options_dict['legend_bbox_to_anchor'] is None:
            tmp1 = False
            tmp2 = 0.
            tmp3 = 0.
        else:
            tmp1 = True
            tmp2 = legend_options_dict['legend_bbox_to_anchor'][0]
            tmp3 = legend_options_dict['legend_bbox_to_anchor'][1]
        legend_options_wid.children[1].children[1].children[0].children[
            1].children[0].value = tmp1
        legend_options_wid.children[1].children[1].children[0].children[
            1].children[1].value = tmp2
        legend_options_wid.children[1].children[1].children[0].children[
            1].children[2].value = tmp3

    # update legend_border_axes_pad
    if 'legend_border_axes_pad' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[0].children[
            2].value = \
            legend_options_dict['legend_border_axes_pad']

    # update legend_n_columns text box
    if 'legend_n_columns' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[2].children[
            0].children[0].children[0].value = \
            int(legend_options_dict['legend_n_columns'])

    # update legend_marker_scale text box
    if 'legend_marker_scale' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[2].children[
            0].children[0].children[1].value = \
            float(legend_options_dict['legend_marker_scale'])

    # update legend_horizontal_spacing text box
    if 'legend_horizontal_spacing' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[2].children[
            0].children[1].children[0].value = \
            float(legend_options_dict['legend_horizontal_spacing'])

    # update legend_vertical_spacing text box
    if 'legend_vertical_spacing' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[2].children[
            0].children[1].children[1].value = \
            float(legend_options_dict['legend_vertical_spacing'])

    # update legend_border
    if 'legend_border' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[2].children[
            1].children[0].value = \
            legend_options_dict['legend_border']

    # update legend_border_padding text box
    if 'legend_border_padding' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[2].children[
            1].children[1].value = \
            float(legend_options_dict['legend_border_padding'])

    # update legend_shadow
    if 'legend_shadow' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[2].children[
            2].children[0].value = \
            legend_options_dict['legend_shadow']

    # update legend_rounded_corners
    if 'legend_rounded_corners' in legend_options_dict.keys():
        legend_options_wid.children[1].children[1].children[2].children[
            2].children[1].value = \
            legend_options_dict['legend_rounded_corners']


def grid_options(grid_options_default, plot_function=None,
                 toggle_show_visible=True, toggle_show_default=True,
                 toggle_title='Grid Object', show_checkbox_title='Render grid'):
    r"""
    Creates a widget with Grid Options. Specifically, it has:
        1) A checkbox that controls grid's visibility.
        2) A dropdown menu for grid style.
        3) A bounded float text box for line width.
        7) A toggle button that controls the visibility of all the above, i.e.
           the grid options.

    The structure of the widgets is the following:
        grid_options_wid.children = [toggle_button, options]
        options.children = [render_grid_checkbox, other_options]
        other_options.children = [grid_style, grid_width]

    The returned widget saves the selected values in the following dictionary:
        grid_options_wid.selected_values

    To fix the alignment within this widget please refer to
    `format_grid_options()` function.

    Parameters
    ----------
    grid_options_default : `dict`
        The initial selected grid options.
        Example:
            line_options={'render_grid': True,
                          'grid_line_width': 1,
                          'grid_line_style': '-'}
    plot_function : `function` or None, optional
        The plot function that is executed when a widgets' value changes.
        If None, then nothing is assigned.
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    toggle_title : `str`, optional
        The title of the toggle button.
    show_checkbox_title : `str`, optional
        The description of the show line checkbox.
    """
    import IPython.html.widgets as ipywidgets
    # Create widgets
    # toggle button
    but = ipywidgets.ToggleButtonWidget(description=toggle_title,
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # grid_line_style, grid_line_width
    render_grid = ipywidgets.CheckboxWidget(
        description=show_checkbox_title,
        value=grid_options_default['render_grid'])
    grid_line_width = ipywidgets.BoundedFloatTextWidget(
        description='Width', value=grid_options_default['grid_line_width'],
        min=0.)
    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'] = ':'
    grid_line_style = ipywidgets.DropdownWidget(
        values=grid_line_style_dict,
        value=grid_options_default['grid_line_style'], description='Style')

    # Options widget
    all_grid_options = ipywidgets.ContainerWidget(
        children=[grid_line_style, grid_line_width])
    options_wid = ipywidgets.ContainerWidget(
        children=[render_grid, all_grid_options])

    # Final widget
    grid_options_wid = ipywidgets.ContainerWidget(children=[but, options_wid])

    # Assign output
    grid_options_wid.selected_values = grid_options_default

    # line options visibility
    def options_visible(name, value):
        grid_line_style.disabled = not value
        grid_line_width.disabled = not value
    options_visible('', grid_options_default['render_grid'])
    render_grid.on_trait_change(options_visible, 'value')

    # get options functions
    def save_render_grid(name, value):
        grid_options_wid.selected_values['render_grid'] = value
    render_grid.on_trait_change(save_render_grid, 'value')

    def save_grid_line_width(name, value):
        grid_options_wid.selected_values['grid_line_width'] = float(value)
    grid_line_width.on_trait_change(save_grid_line_width, 'value')

    def save_grid_line_style(name, value):
        grid_options_wid.selected_values['grid_line_style'] = value
    grid_line_style.on_trait_change(save_grid_line_style, 'value')

    # Toggle button function
    def toggle_fun(name, value):
        options_wid.visible = value
    toggle_fun('', toggle_show_default)
    but.on_trait_change(toggle_fun, 'value')

    # assign plot_function
    if plot_function is not None:
        render_grid.on_trait_change(plot_function, 'value')
        grid_line_style.on_trait_change(plot_function, 'value')
        grid_line_width.on_trait_change(plot_function, 'value')

    return grid_options_wid


def format_grid_options(grid_options_wid, container_padding='6px',
                        container_margin='6px',
                        container_border='1px solid black',
                        toggle_button_font_weight='bold', border_visible=True,
                        suboptions_border_visible=True):
    r"""
    Function that corrects the align (style format) of a given grid_options
    widget. Usage example:
        grid_options_wid = grid_options()
        display(grid_options_wid)
        format_grid_options(grid_options_wid)

    Parameters
    ----------
    grid_options_wid :
        The widget object generated by the `grid_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    suboptions_border_visible : `boolean`, optional
        Defines whether to draw the border line around the line options, under
        the show line checkbox.
    """
    # align grid options with checkbox
    grid_options_wid.children[1].add_class('align-end')

    # set gridlinewidth text box width
    grid_options_wid.children[1].children[1].children[1].set_css('width', '1cm')

    # border around options
    if suboptions_border_visible:
        grid_options_wid.children[1].children[1].set_css('border',
                                                         container_border)

    # set toggle button font bold
    grid_options_wid.children[0].set_css('font-weight',
                                         toggle_button_font_weight)

    # margin and border around container widget
    grid_options_wid.set_css('padding', container_padding)
    grid_options_wid.set_css('margin', container_margin)
    if border_visible:
        grid_options_wid.set_css('border', container_border)


def update_grid_options(grid_options_wid, grid_options_dict):
    r"""
    Function that updates the state of a given grid_options widget. Usage
    example:
        default_grid_options={'render_grid':True,
                              'grid_line_width':2,
                              'grid_line_style':'-'}
        grid_options_wid = grid_options(default_grid_options)
        display(grid_options_wid)
        format_grid_options(grid_options_wid)
        default_grid_options={'render_grid':False,
                              'grid_line_width':4,
                              'grid_line_style':'-'}
        update_grid_options(grid_options_wid, default_grid_options)

    Parameters
    ----------
    grid_options_wid :
        The widget object generated by the `grid_options()` function.
    grid_options_dict : `dict`
        The new set of options. For example:
            grid_options_dict={'render_grid':True,
                               'grid_line_width':2,
                               'grid_line_style':'-'}
    """
    # Assign new options dict to selected_values
    grid_options_wid.selected_values = grid_options_dict

    # update render grid checkbox
    if 'render_grid' in grid_options_dict.keys():
        grid_options_wid.children[1].children[0].value = \
            grid_options_dict['render_grid']

    # update grid_line_style dropdown menu
    if 'grid_line_style' in grid_options_dict.keys():
        grid_options_wid.children[1].children[1].children[0].value = \
            grid_options_dict['grid_line_style']

    # update grid_line_width text box
    if 'grid_line_width' in grid_options_dict.keys():
        grid_options_wid.children[1].children[1].children[1].value = \
            float(grid_options_dict['grid_line_width'])


def hog_options(toggle_show_default=True, toggle_show_visible=True):
    r"""
    Creates a widget with HOG Features Options.

    The structure of the widgets is the following:
        hog_options_wid.children = [toggle_button, options]
        options.children = [window_wid, algorithm_wid]
        window_wid.children = [mode_wid, window_opts_wid]
        mode_wid.children = [mode_radiobuttons, padding_checkbox]
        window_opts_wid.children = [window_size_wid, window_step_wid]
        window_size_wid.children = [window_height, window_width,
                                    window_size_unit]
        window_step_wid.children = [window_vertical, window_horizontal,
                                    window_step_unit]
        algorithm_wid.children = [algorithm_radiobuttons, algorithm_options]
        algorithm_options.children = [algorithm_sizes, algorithm_other]
        algorithm_sizes.children = [cell_size, block_size, num_bins]
        algorithm_other.children = [signed_gradient, l2_norm_clipping]

    To fix the alignment within this widget please refer to
    `format_hog_options()` function.

    Parameters
    ----------
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    """
    import IPython.html.widgets as ipywidgets
    # Toggle button that controls options' visibility
    but = ipywidgets.ToggleButtonWidget(description='HOG Options',
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # window related options
    tmp = OrderedDict()
    tmp['Dense'] = 'dense'
    tmp['Sparse'] = 'sparse'
    mode = ipywidgets.RadioButtonsWidget(values=tmp, description='Mode')
    padding = ipywidgets.CheckboxWidget(value=True, description='Padding')
    mode_wid = ipywidgets.ContainerWidget(children=[mode, padding])
    window_height = ipywidgets.BoundedIntTextWidget(value='1',
                                                    description='Height', min=1)
    window_width = ipywidgets.BoundedIntTextWidget(value='1',
                                                   description='Width', min=1)
    tmp = OrderedDict()
    tmp['Blocks'] = 'blocks'
    tmp['Pixels'] = 'pixels'
    window_size_unit = ipywidgets.RadioButtonsWidget(values=tmp,
                                                     description=' Size unit')
    window_size_wid = ipywidgets.ContainerWidget(
        children=[window_height, window_width,
                  window_size_unit])
    window_vertical = ipywidgets.BoundedIntTextWidget(value='1',
                                                      description='Step Y',
                                                      min=1)
    window_horizontal = ipywidgets.BoundedIntTextWidget(value='1',
                                                        description='Step X',
                                                        min=1)
    tmp = OrderedDict()
    tmp['Pixels'] = 'pixels'
    tmp['Cells'] = 'cells'
    window_step_unit = ipywidgets.RadioButtonsWidget(values=tmp,
                                                     description='Step unit')
    window_step_wid = ipywidgets.ContainerWidget(children=[window_vertical,
                                                           window_horizontal,
                                                           window_step_unit])
    window_wid = ipywidgets.ContainerWidget(
        children=[window_size_wid, window_step_wid])
    window_wid = ipywidgets.ContainerWidget(children=[mode_wid, window_wid])

    # algorithm related options
    tmp = OrderedDict()
    tmp['Dalal & Triggs'] = 'dalaltriggs'
    tmp['Zhu & Ramanan'] = 'zhuramanan'
    algorithm = ipywidgets.RadioButtonsWidget(values=tmp, value='dalaltriggs',
                                              description='Algorithm')
    cell_size = ipywidgets.BoundedIntTextWidget(
        value='8', description='Cell size (in pixels)', min=1)
    block_size = ipywidgets.BoundedIntTextWidget(
        value='2', description='Block size (in cells)', min=1)
    num_bins = ipywidgets.BoundedIntTextWidget(
        value='9', description='Orientation bins', min=1)
    algorithm_sizes = ipywidgets.ContainerWidget(
        children=[cell_size, block_size,
                  num_bins])
    signed_gradient = ipywidgets.CheckboxWidget(value=True,
                                                description='Signed gradients')
    l2_norm_clipping = ipywidgets.BoundedFloatTextWidget(
        value='0.2', description='L2 norm clipping', min=0.)
    algorithm_other = ipywidgets.ContainerWidget(children=[signed_gradient,
                                                           l2_norm_clipping])
    algorithm_options = ipywidgets.ContainerWidget(children=[algorithm_sizes,
                                                             algorithm_other])
    algorithm_wid = ipywidgets.ContainerWidget(
        children=[algorithm, algorithm_options])

    # options tab widget
    all_options = ipywidgets.TabWidget(children=[window_wid, algorithm_wid])

    # Widget container
    hog_options_wid = ipywidgets.ContainerWidget(children=[but, all_options])

    # Initialize output dictionary
    hog_options_wid.options = {'mode': 'dense', 'algorithm': 'dalaltriggs',
                               'num_bins': 9, 'cell_size': 8, 'block_size': 2,
                               'signed_gradient': True, 'l2_norm_clip': 0.2,
                               'window_height': 1, 'window_width': 1,
                               'window_unit': 'blocks',
                               'window_step_vertical': 1,
                               'window_step_horizontal': 1,
                               'window_step_unit': 'pixels', 'padding': True,
                               'verbose': False}

    # mode function
    def window_mode(name, value):
        window_horizontal.disabled = value == 'sparse'
        window_vertical.disabled = value == 'sparse'
        window_step_unit.disabled = value == 'sparse'
        window_height.disabled = value == 'sparse'
        window_width.disabled = value == 'sparse'
        window_size_unit.disabled = value == 'sparse'
    mode.on_trait_change(window_mode, 'value')

    # algorithm function
    def algorithm_mode(name, value):
        l2_norm_clipping.disabled = value == 'zhuramanan'
        signed_gradient.disabled = value == 'zhuramanan'
        block_size.disabled = value == 'zhuramanan'
        num_bins.disabled = value == 'zhuramanan'
    algorithm.on_trait_change(algorithm_mode, 'value')

    # get options
    def get_mode(name, value):
        hog_options_wid.options['mode'] = value
    mode.on_trait_change(get_mode, 'value')

    def get_padding(name, value):
        hog_options_wid.options['padding'] = value
    padding.on_trait_change(get_padding, 'value')

    def get_window_height(name, value):
        hog_options_wid.options['window_height'] = value
    window_height.on_trait_change(get_window_height, 'value')

    def get_window_width(name, value):
        hog_options_wid.options['window_width'] = value
    window_width.on_trait_change(get_window_width, 'value')

    def get_window_size_unit(name, value):
        hog_options_wid.options['window_unit'] = value
    window_size_unit.on_trait_change(get_window_size_unit, 'value')

    def get_window_step_vertical(name, value):
        hog_options_wid.options['window_step_vertical'] = value
    window_vertical.on_trait_change(get_window_step_vertical, 'value')

    def get_window_step_horizontal(name, value):
        hog_options_wid.options['window_step_horizontal'] = value
    window_horizontal.on_trait_change(get_window_step_horizontal, 'value')

    def get_window_step_unit(name, value):
        hog_options_wid.options['window_step_unit'] = value
    window_step_unit.on_trait_change(get_window_step_unit, 'value')

    def get_algorithm(name, value):
        hog_options_wid.options['algorithm'] = value
    algorithm.on_trait_change(get_algorithm, 'value')

    def get_num_bins(name, value):
        hog_options_wid.options['num_bins'] = value
    num_bins.on_trait_change(get_num_bins, 'value')

    def get_cell_size(name, value):
        hog_options_wid.options['cell_size'] = value
    cell_size.on_trait_change(get_cell_size, 'value')

    def get_block_size(name, value):
        hog_options_wid.options['block_size'] = value
    block_size.on_trait_change(get_block_size, 'value')

    def get_signed_gradient(name, value):
        hog_options_wid.options['signed_gradient'] = value
    signed_gradient.on_trait_change(get_signed_gradient, 'value')

    def get_l2_norm_clip(name, value):
        hog_options_wid.options['l2_norm_clip'] = value
    l2_norm_clipping.on_trait_change(get_l2_norm_clip, 'value')

    # Toggle button function
    def toggle_options(name, value):
        all_options.visible = value
    but.on_trait_change(toggle_options, 'value')

    return hog_options_wid


def format_hog_options(hog_options_wid, container_padding='6px',
                       container_margin='6px',
                       container_border='1px solid black',
                       toggle_button_font_weight='bold',
                       border_visible=True):
    r"""
    Function that corrects the align (style format) of a given hog_options
    widget. Usage example:
        hog_options_wid = hog_options()
        display(hog_options_wid)
        format_hog_options(hog_options_wid)

    Parameters
    ----------
    hog_options_wid :
        The widget object generated by the `hog_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    tab_top_margin : `str`, optional
        The margin around the tab options' widget, e.g. '0.3cm'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    """
    # align window options
    hog_options_wid.children[1].children[0].children[1].remove_class('vbox')
    hog_options_wid.children[1].children[0].children[1].add_class('hbox')

    # set width of height, width, step x , step y textboxes
    hog_options_wid.children[1].children[0].children[1].children[0].children[0]. \
        set_css('width', '40px')
    hog_options_wid.children[1].children[0].children[1].children[0].children[1]. \
        set_css('width', '40px')
    hog_options_wid.children[1].children[0].children[1].children[1].children[0]. \
        set_css('width', '40px')
    hog_options_wid.children[1].children[0].children[1].children[1].children[1]. \
        set_css('width', '40px')

    # set margin and border around the window size and step options
    hog_options_wid.children[1].children[0].children[1].children[0].set_css(
        'margin', container_margin)
    hog_options_wid.children[1].children[0].children[1].children[1].set_css(
        'margin', container_margin)
    hog_options_wid.children[1].children[0].children[1].children[0].set_css(
        'border', '1px solid gray')
    hog_options_wid.children[1].children[0].children[1].children[1].set_css(
        'border', '1px solid gray')

    # align mode and padding
    hog_options_wid.children[1].children[0].children[0].remove_class('vbox')
    hog_options_wid.children[1].children[0].children[0].add_class('hbox')

    # set width of algorithm textboxes
    hog_options_wid.children[1].children[1].children[1].children[0].children[0]. \
        set_css('width', '40px')
    hog_options_wid.children[1].children[1].children[1].children[0].children[1]. \
        set_css('width', '40px')
    hog_options_wid.children[1].children[1].children[1].children[0].children[2]. \
        set_css('width', '40px')
    hog_options_wid.children[1].children[1].children[1].children[1].children[1]. \
        set_css('width', '40px')

    # align algorithm options
    hog_options_wid.children[1].children[1].children[1].remove_class('vbox')
    hog_options_wid.children[1].children[1].children[1].add_class('hbox')

    # set margin and border around the algorithm options
    hog_options_wid.children[1].children[1].children[1].set_css(
        'margin', container_margin)
    hog_options_wid.children[1].children[1].children[1].set_css(
        'border', '1px solid gray')

    hog_options_wid.children[1].set_css('margin-top', '6px')
    hog_options_wid.children[1].children[0].add_class('align-center')
    hog_options_wid.children[1].children[1].add_class('align-center')

    # set final tab titles
    tab_titles = ['Window', 'Algorithm']
    for (k, tl) in enumerate(tab_titles):
        hog_options_wid.children[1].set_title(k, tl)

    # set toggle button font bold
    hog_options_wid.children[0].set_css('font-weight',
                                        toggle_button_font_weight)

    # margin and border around container widget
    hog_options_wid.set_css('padding', container_padding)
    hog_options_wid.set_css('margin', container_margin)
    if border_visible:
        hog_options_wid.set_css('border', container_border)


def daisy_options(toggle_show_default=True, toggle_show_visible=True):
    r"""
    Creates a widget with Daisy Features Options.

    The structure of the widgets is the following:
        daisy_options_wid.children = [toggle_button, options]
        options.children = [options1, options2]
        options1.children = [step_int, radius_int, rings_int, histograms_int]
        options2.children = [orientations_int, normalization_dropdown,
                             sigmas_list, ring_radii_list]

    To fix the alignment within this widget please refer to
    `format_daisy_options()` function.

    Parameters
    ----------
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    """
    import IPython.html.widgets as ipywidgets
    # Toggle button that controls options' visibility
    but = ipywidgets.ToggleButtonWidget(description='Daisy Options',
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # options widgets
    step = ipywidgets.BoundedIntTextWidget(value='1', description='Step', min=1)
    radius = ipywidgets.BoundedIntTextWidget(value='15', description='Radius',
                                             min=1)
    rings = ipywidgets.BoundedIntTextWidget(value='2', description='Rings',
                                            min=1)
    histograms = ipywidgets.BoundedIntTextWidget(value='2',
                                                 description='Histograms',
                                                 min=1)
    orientations = ipywidgets.BoundedIntTextWidget(value='8',
                                                   description='Orientations',
                                                   min=1)
    tmp = OrderedDict()
    tmp['L1'] = 'l1'
    tmp['L2'] = 'l2'
    tmp['Daisy'] = 'daisy'
    tmp['None'] = None
    normalization = ipywidgets.DropdownWidget(value='l1', values=tmp,
                                              description='Normalization')
    sigmas = ipywidgets.TextWidget(description='Sigmas')
    ring_radii = ipywidgets.TextWidget(description='Ring radii')

    # group widgets
    cont1 = ipywidgets.ContainerWidget(
        children=[step, radius, rings, histograms])
    cont2 = ipywidgets.ContainerWidget(
        children=[orientations, normalization, sigmas,
                  ring_radii])
    options = ipywidgets.ContainerWidget(children=[cont1, cont2])

    # Widget container
    daisy_options_wid = ipywidgets.ContainerWidget(children=[but, options])

    # Initialize output dictionary
    daisy_options_wid.options = {'step': 1, 'radius': 15,
                                 'rings': 2, 'histograms': 2,
                                 'orientations': 8,
                                 'normalization': 'l1',
                                 'sigmas': None,
                                 'ring_radii': None}

    # get options
    def get_step(name, value):
        daisy_options_wid.options['step'] = value

    step.on_trait_change(get_step, 'value')

    def get_radius(name, value):
        daisy_options_wid.options['radius'] = value

    radius.on_trait_change(get_radius, 'value')

    def get_rings(name, value):
        daisy_options_wid.options['rings'] = value

    rings.on_trait_change(get_rings, 'value')

    def get_histograms(name, value):
        daisy_options_wid.options['histograms'] = value

    histograms.on_trait_change(get_histograms, 'value')

    def get_orientations(name, value):
        daisy_options_wid.options['orientations'] = value

    orientations.on_trait_change(get_orientations, 'value')

    def get_normalization(name, value):
        daisy_options_wid.options['normalization'] = value

    normalization.on_trait_change(get_normalization, 'value')

    def get_sigmas(name, value):
        daisy_options_wid.options['sigmas'] = _convert_str_to_list_int(
            str(value))

    sigmas.on_trait_change(get_sigmas, 'value')

    def get_ring_radii(name, value):
        daisy_options_wid.options['ring_radii'] = _convert_str_to_list_float(
            str(value))

    ring_radii.on_trait_change(get_ring_radii, 'value')

    # Toggle button function
    def toggle_options(name, value):
        options.visible = value

    but.on_trait_change(toggle_options, 'value')

    return daisy_options_wid


def format_daisy_options(daisy_options_wid, container_padding='6px',
                         container_margin='6px',
                         container_border='1px solid black',
                         toggle_button_font_weight='bold',
                         border_visible=True):
    r"""
    Function that corrects the align (style format) of a given daisy_options
    widget. Usage example:
        daisy_options_wid = daisy_options()
        display(daisy_options_wid)
        format_daisy_options(daisy_options_wid)

    Parameters
    ----------
    daisy_options_wid :
        The widget object generated by the `daisy_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    tab_top_margin : `str`, optional
        The margin around the tab options' widget, e.g. '0.3cm'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    """
    # align window options
    daisy_options_wid.children[1].remove_class('vbox')
    daisy_options_wid.children[1].add_class('hbox')

    # set textboxes length
    daisy_options_wid.children[1].children[0].children[0].set_css('width',
                                                                  '40px')
    daisy_options_wid.children[1].children[0].children[1].set_css('width',
                                                                  '40px')
    daisy_options_wid.children[1].children[0].children[2].set_css('width',
                                                                  '40px')
    daisy_options_wid.children[1].children[0].children[3].set_css('width',
                                                                  '40px')
    daisy_options_wid.children[1].children[1].children[0].set_css('width',
                                                                  '40px')
    daisy_options_wid.children[1].children[1].children[2].set_css('width',
                                                                  '80px')
    daisy_options_wid.children[1].children[1].children[3].set_css('width',
                                                                  '80px')

    # set toggle button font bold
    daisy_options_wid.children[0].set_css('font-weight',
                                          toggle_button_font_weight)

    # margin and border around container widget
    daisy_options_wid.set_css('padding', container_padding)
    daisy_options_wid.set_css('margin', container_margin)
    if border_visible:
        daisy_options_wid.set_css('border', container_border)


def lbp_options(toggle_show_default=True, toggle_show_visible=True):
    r"""
    Creates a widget with LBP Features Options.

    The structure of the widgets is the following:
        lbp_options_wid.children = [toggle_button, options]
        options.children = [window_wid, algorithm_wid]
        window_wid.children = [window_vertical, window_horizontal,
                               window_step_unit, padding]
        algorithm_wid.children = [mapping_type, radius, samples]

    To fix the alignment within this widget please refer to
    `format_lbp_options()` function.

    Parameters
    ----------
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    """
    import IPython.html.widgets as ipywidgets
    # Toggle button that controls options' visibility
    but = ipywidgets.ToggleButtonWidget(description='LBP Options',
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # method related options
    tmp = OrderedDict()
    tmp['Uniform-2'] = 'u2'
    tmp['Rotation-Invariant'] = 'ri'
    tmp['Both'] = 'riu2'
    tmp['None'] = 'none'
    mapping_type = ipywidgets.DropdownWidget(value='u2', values=tmp,
                                             description='Mapping')
    radius = ipywidgets.TextWidget(value='1, 2, 3, 4', description='Radius')
    samples = ipywidgets.TextWidget(value='8, 8, 8, 8', description='Samples')
    algorithm_wid = ipywidgets.ContainerWidget(children=[radius,
                                                         samples,
                                                         mapping_type])

    # window related options
    window_vertical = ipywidgets.BoundedIntTextWidget(value='1',
                                                      description='Step Y',
                                                      min=1)
    window_horizontal = ipywidgets.BoundedIntTextWidget(value='1',
                                                        description='Step X',
                                                        min=1)
    tmp = OrderedDict()
    tmp['Pixels'] = 'pixels'
    tmp['Windows'] = 'cells'
    window_step_unit = ipywidgets.RadioButtonsWidget(values=tmp,
                                                     description='Step unit')
    padding = ipywidgets.CheckboxWidget(value=True, description='Padding')
    window_wid = ipywidgets.ContainerWidget(children=[window_vertical,
                                                      window_horizontal,
                                                      window_step_unit,
                                                      padding])

    # options widget
    options = ipywidgets.ContainerWidget(children=[window_wid, algorithm_wid])

    # Widget container
    lbp_options_wid = ipywidgets.ContainerWidget(children=[but, options])

    # Initialize output dictionary
    lbp_options_wid.options = {'radius': range(1, 5), 'samples': [8] * 4,
                               'mapping_type': 'u2',
                               'window_step_vertical': 1,
                               'window_step_horizontal': 1,
                               'window_step_unit': 'pixels', 'padding': True,
                               'verbose': False, 'skip_checks': False}

    # get options
    def get_mapping_type(name, value):
        lbp_options_wid.options['mapping_type'] = value
    mapping_type.on_trait_change(get_mapping_type, 'value')

    def get_window_vertical(name, value):
        lbp_options_wid.options['window_step_vertical'] = value
    window_vertical.on_trait_change(get_window_vertical, 'value')

    def get_window_horizontal(name, value):
        lbp_options_wid.options['window_step_horizontal'] = value
    window_horizontal.on_trait_change(get_window_horizontal, 'value')

    def get_window_step_unit(name, value):
        lbp_options_wid.options['window_step_unit'] = value
    window_step_unit.on_trait_change(get_window_step_unit, 'value')

    def get_padding(name, value):
        lbp_options_wid.options['padding'] = value
    padding.on_trait_change(get_padding, 'value')

    def get_radius(name, value):
        lbp_options_wid.options['radius'] = _convert_str_to_list_int(str(value))
    radius.on_trait_change(get_radius, 'value')

    def get_samples(name, value):
        str_val = _convert_str_to_list_int(str(value))
        lbp_options_wid.options['samples'] = str_val
    samples.on_trait_change(get_samples, 'value')

    # Toggle button function
    def toggle_options(name, value):
        options.visible = value
    but.on_trait_change(toggle_options, 'value')

    return lbp_options_wid


def format_lbp_options(lbp_options_wid, container_padding='6px',
                       container_margin='6px',
                       container_border='1px solid black',
                       toggle_button_font_weight='bold',
                       border_visible=True):
    r"""
    Function that corrects the align (style format) of a given lbp_options
    widget. Usage example:
        lbp_options_wid = lbp_options()
        display(lbp_options_wid)
        format_lbp_options(lbp_options_wid)

    Parameters
    ----------
    lbp_options_wid :
        The widget object generated by the `lbp_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    tab_top_margin : `str`, optional
        The margin around the tab options' widget, e.g. '0.3cm'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    """
    # align window options
    lbp_options_wid.children[1].remove_class('vbox')
    lbp_options_wid.children[1].add_class('hbox')

    # set textboxes length
    lbp_options_wid.children[1].children[0].children[0].set_css('width',
                                                                '40px')
    lbp_options_wid.children[1].children[0].children[1].set_css('width',
                                                                '40px')
    lbp_options_wid.children[1].children[1].children[0].set_css('width',
                                                                '80px')
    lbp_options_wid.children[1].children[1].children[1].set_css('width',
                                                                '80px')

    # set toggle button font bold
    lbp_options_wid.children[0].set_css('font-weight',
                                        toggle_button_font_weight)

    # margin and border around container widget
    lbp_options_wid.set_css('padding', container_padding)
    lbp_options_wid.set_css('margin', container_margin)
    if border_visible:
        lbp_options_wid.set_css('border', container_border)


def igo_options(toggle_show_default=True, toggle_show_visible=True):
    r"""
    Creates a widget with IGO Features Options.

    The structure of the widgets is the following:
        igo_options_wid.children = [toggle_button, double_angles_checkbox]

    To fix the alignment within this widget please refer to
    `format_igo_options()` function.

    Parameters
    ----------
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    """
    import IPython.html.widgets as ipywidgets
    # Toggle button that controls options' visibility
    but = ipywidgets.ToggleButtonWidget(description='IGO Options',
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # options widget
    double_angles = ipywidgets.CheckboxWidget(value=False,
                                              description='Double angles')

    # Widget container
    igo_options_wid = ipywidgets.ContainerWidget(children=[but, double_angles])

    # Initialize output dictionary
    igo_options_wid.options = {'double_angles': False}

    # get double_angles
    def get_double_angles(name, value):
        igo_options_wid.options['double_angles'] = value
    double_angles.on_trait_change(get_double_angles, 'value')

    # Toggle button function
    def toggle_options(name, value):
        double_angles.visible = value
    but.on_trait_change(toggle_options, 'value')

    return igo_options_wid


def format_igo_options(igo_options_wid, container_padding='6px',
                       container_margin='6px',
                       container_border='1px solid black',
                       toggle_button_font_weight='bold',
                       border_visible=True):
    r"""
    Function that corrects the align (style format) of a given igo_options
    widget. Usage example:
        igo_options_wid = igo_options()
        display(igo_options_wid)
        format_igo_options(igo_options_wid)

    Parameters
    ----------
    igo_options_wid :
        The widget object generated by the `igo_options()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    tab_top_margin : `str`, optional
        The margin around the tab options' widget, e.g. '0.3cm'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    """
    # set toggle button font bold
    igo_options_wid.children[0].set_css('font-weight',
                                        toggle_button_font_weight)

    # margin and border around container widget
    igo_options_wid.set_css('padding', container_padding)
    igo_options_wid.set_css('margin', container_margin)
    if border_visible:
        igo_options_wid.set_css('border', container_border)


def function_definition(default_function='def my_function():\n    pass',
                        toggle_show_default=True, toggle_show_visible=True):
    r"""
    Creates a widget for Function Definition.

    The structure of the widgets is the following:
        function_definition_wid.children = [toggle_button, options]
        options.children = [code_textarea, define]
        define.children = [message_text, define_button]

    To fix the alignment within this widget please refer to
    `format_function_definition()` function.

    Parameters
    ----------
    toggle_show_default : `boolean`, optional
        Defines whether the options will be visible upon construction.
    toggle_show_visible : `boolean`, optional
        The visibility of the toggle button.
    """
    import IPython.html.widgets as ipywidgets
    # Toggle button that controls options' visibility
    but = ipywidgets.ToggleButtonWidget(description='Features Options',
                                        value=toggle_show_default,
                                        visible=toggle_show_visible)

    # code widget
    code = ipywidgets.TextareaWidget(value=default_function)
    define_but = ipywidgets.ButtonWidget(description='Define')
    msg_wid = ipywidgets.LatexWidget(value='')
    define_wid = ipywidgets.ContainerWidget(children=[msg_wid, define_but])

    # options widget
    all_options = ipywidgets.ContainerWidget(children=[code, define_wid])

    # Widget container
    function_definition_wid = ipywidgets.ContainerWidget(
        children=[but, all_options])

    # Initialize output dictionary
    f, msg = _get_function_handle_from_string(default_function)
    function_definition_wid.function = f

    # get code
    def get_code(name):
        function_handle, msg = _get_function_handle_from_string(code.value)
        if function_handle is not None:
            function_definition_wid.function = function_handle
            msg_wid.value = ''
        else:
            f, _ = _get_function_handle_from_string(default_function)
            function_definition_wid.function = f
            msg_wid.value = msg
    define_but.on_click(get_code)

    # Toggle button function
    def toggle_options(name, value):
        all_options.visible = value
    but.on_trait_change(toggle_options, 'value')

    return function_definition_wid


def format_function_definition(function_definition_wid, container_padding='6px',
                               container_margin='6px',
                               container_border='1px solid black',
                               toggle_button_font_weight='bold',
                               border_visible=True):
    r"""
    Function that corrects the align (style format) of a given features_options
    widget. Usage example:
        function_definition_wid = function_definition()
        display(function_definition_wid)
        format_function_definition(function_definition_wid)

    Parameters
    ----------
    function_definition_wid :
        The widget object generated by the `function_definition()` function.
    container_padding : `str`, optional
        The padding around the widget, e.g. '6px'
    container_margin : `str`, optional
        The margin around the widget, e.g. '6px'
    tab_top_margin : `str`, optional
        The margin around the tab options' widget, e.g. '0.3cm'
    container_border : `str`, optional
        The border around the widget, e.g. '1px solid black'
    toggle_button_font_weight : `str`
        The font weight of the toggle button, e.g. 'bold'
    border_visible : `boolean`, optional
        Defines whether to draw the border line around the widget.
    """
    # align message text and button horizontally
    function_definition_wid.children[1].children[1].remove_class('vbox')
    function_definition_wid.children[1].children[1].add_class('hbox')

    # set margin between message and button
    function_definition_wid.children[1].children[1].children[0].set_css(
        'margin-right', '0.5cm')

    # align code textarea and button to the right
    function_definition_wid.children[1].add_class('align-end')

    # set error message background to red
    function_definition_wid.children[1].children[1].children[0].set_css(
        'background', 'red')

    # set toggle button font bold
    function_definition_wid.children[0].set_css('font-weight',
                                                toggle_button_font_weight)

    # margin and border around container widget
    function_definition_wid.set_css('padding', container_padding)
    function_definition_wid.set_css('margin', container_margin)
    if border_visible:
        function_definition_wid.set_css('border', container_border)


class IntListTextWidget():
    r"""
    Basic widget that returns a `list` of `int` numbers. It uses
    `IPython.html.widgets.TextWidget()` and converts its value to a `list` of
    `int`.

    Parameters
    ----------
    value : `str` or `list` of `int`, Optional
        The initial value of the widget.
    description : `str`, Optional
        The description of the widget.

    Raises
    ------
    ValueError
        value must be str or list
    """

    def __init__(self, value='', description=''):
        import IPython.html.widgets as ipywidgets

        if isinstance(value, list):
            val = _convert_list_to_str(value)
        elif isinstance(value, str):
            val = value
        else:
            raise ValueError("value must be str or list")
        self.text_wid = ipywidgets.TextWidget(value=val,
                                              description=description)

    @property
    def value(self):
        r"""
        The value fo the widget.
        """
        return _convert_str_to_list_int(str(self.text_wid.value))

    @property
    def description(self):
        r"""
        The description of the widget.
        """
        return self.text_wid.description

    @property
    def model_id(self):
        r"""
        The id of the widget.
        """
        return self.text_wid.model_id


class FloatListTextWidget(IntListTextWidget):
    r"""
    Basic widget that returns a `list` of `float` numbers. It uses
    `IPython.html.widgets.TextWidget()` and converts its value to a `list` of
    `float`.

    Parameters
    ----------
    value : `str` or `list` of `int`, Optional
        The initial value of the widget.
    description : `str`, Optional
        The description of the widget.

    Raises
    ------
    ValueError
        value must be str or list
    """

    @property
    def value(self):
        r"""
        The value fo the widget.
        """
        return _convert_str_to_list_float(str(self.text_wid.value))


def _convert_list_to_str(l):
    r"""
    Function that converts a given list of numbers to a string. For example:
        convert_list_to_str([1, 2, 3]) returns '1, 2, 3'
    """
    if isinstance(l, list):
        return str(l)[1:-1]
    else:
        return ''


def _convert_str_to_list_int(s):
    r"""
    Function that converts a given string to a list of int numbers. For example:
        _convert_str_to_list_int('1, 2, 3') returns [1, 2, 3]
    """
    if isinstance(s, str):
        return [int(i[:-1]) if i[-1] == ',' else int(i) for i in s.split()]
    else:
        return []


def _convert_str_to_list_float(s):
    r"""
    Function that converts a given string to a list of float numbers.
    For example:
        _convert_str_to_list_float('1, 2, 3') returns [1.0, 2.0, 3.0]
    """
    if isinstance(s, str):
        return [float(i[:-1]) if i[-1] == ',' else float(i) for i in s.split()]
    else:
        return []


def _get_function_handle_from_string(s):
    r"""
    Function that returns a function handle given the function code as a string.
    """
    try:
        exec s
        function_name = s[4:s.find('(')]
        return eval(function_name), None
    except:
        return None, 'Invalid syntax!'


def _convert_image_to_bytes(image):
    r"""
    Function that given a menpo.Image object, it converts it to the correct
    bytes format that can be used by IPython.html.widgets.ImageWidget().
    """
    fp = StringIO()
    image.as_PILImage().save(fp, format='png')
    fp.seek(0)
    return fp.read()


def _lists_are_the_same(a, b):
    if len(a) == len(b):
        for i, j in zip(a, b):
            if i != j:
                return False
        return True
    else:
        return False
