import numpy as np
from collections import Sized
from matplotlib.pyplot import show as pltshow
import IPython.html.widgets as ipywidgets
import IPython.display as ipydisplay
from menpo.visualize.viewmatplotlib import (MatplotlibImageViewer2d,
sample_colours_from_colourmap)
from .options import (RendererOptionsWidget, TextPrintWidget,
SaveFigureOptionsWidget, AnimationOptionsWidget,
LandmarkOptionsWidget, ChannelOptionsWidget,
FeatureOptionsWidget, GraphOptionsWidget)
from .tools import _format_box, LogoWidget, _map_styles_to_hex_colours
# This glyph import is called frequently during visualisation, so we ensure
# that we only import it once. The same for the sum_channels method.
glyph = None
sum_channels = None
[docs]def visualize_pointclouds(pointclouds, figure_size=(10, 8), style='coloured',
browser_style='buttons'):
r"""
Widget that allows browsing through a `list` of :map:`PointCloud`,
:map:`PointUndirectedGraph`, :map:`PointDirectedGraph`, :map:`PointTree`,
:map:`TriMesh` or subclasses. All the above can be combined in the `list`.
The widget has options tabs regarding the renderer (lines, markers, figure,
axes) and saving the figure to file.
Parameters
----------
pointclouds : `list`
The `list` of objects to be visualized. It can contain a combination of
:map:`PointCloud`, :map:`PointUndirectedGraph`,
:map:`PointDirectedGraph`, :map:`PointTree`, :map:`TriMesh` or
subclasses of those.
figure_size : (`int`, `int`), optional
The initial size of the rendered figure.
style : {``'coloured'``, ``'minimal'``}, optional
If ``'coloured'``, then the style of the widget will be coloured. If
``minimal``, then the style is simple using black and white colours.
browser_style : {``'buttons'``, ``'slider'``}, optional
It defines whether the selector of the objects will have the form of
plus/minus buttons or a slider.
"""
print('Initializing...')
# Make sure that pointclouds is a list even with one pointcloud member
if not isinstance(pointclouds, Sized):
pointclouds = [pointclouds]
# Get the number of pointclouds
n_pointclouds = len(pointclouds)
# Define the styling options
if style == 'coloured':
logo_style = 'warning'
widget_box_style = 'warning'
widget_border_radius = 10
widget_border_width = 1
animation_style = 'warning'
info_style = 'info'
renderer_box_style = 'info'
renderer_box_border_colour = _map_styles_to_hex_colours('info')
renderer_box_border_radius = 10
renderer_style = 'danger'
renderer_tabs_style = 'minimal'
save_figure_style = 'danger'
else:
logo_style = 'minimal'
widget_box_style = ''
widget_border_radius = 0
widget_border_width = 0
animation_style = 'minimal'
info_style = 'minimal'
renderer_box_style = ''
renderer_box_border_colour = 'black'
renderer_box_border_radius = 0
renderer_style = 'minimal'
renderer_tabs_style = 'minimal'
save_figure_style = 'minimal'
# Initial options dictionaries
line_options = {'render_lines': True, 'line_width': 1, 'line_colour': ['r'],
'line_style': '-'}
marker_options = {'render_markers': True, 'marker_size': 20,
'marker_face_colour': ['r'], 'marker_edge_colour': ['k'],
'marker_style': 'o', 'marker_edge_width': 1}
figure_options = {'x_scale': 1., 'y_scale': 1., 'render_axes': False,
'axes_font_name': 'sans-serif', 'axes_font_size': 10,
'axes_font_style': 'normal', 'axes_font_weight': 'normal',
'axes_x_limits': None, 'axes_y_limits': None}
renderer_options = {'lines': line_options, 'markers': marker_options,
'figure': figure_options}
index = {'min': 0, 'max': n_pointclouds-1, 'step': 1, 'index': 0}
# Define render function
def render_function(name, value):
# Clear current figure, but wait until the generation of the new data
# that will be rendered
ipydisplay.clear_output(wait=True)
# Get selected pointcloud index
im = 0
if n_pointclouds > 1:
im = pointcloud_number_wid.selected_values['index']
# Update info text widget
update_info(pointclouds[im])
# Render pointcloud with selected options
tmp1 = renderer_options_wid.selected_values[0]['lines']
tmp2 = renderer_options_wid.selected_values[0]['markers']
tmp3 = renderer_options_wid.selected_values[0]['figure']
new_figure_size = (tmp3['x_scale'] * figure_size[0],
tmp3['y_scale'] * figure_size[1])
renderer = pointclouds[im].view(
figure_id=save_figure_wid.renderer.figure_id,
new_figure=False, image_view=axes_mode_wid.value == 1,
render_lines=tmp1['render_lines'],
line_colour=tmp1['line_colour'][0],
line_style=tmp1['line_style'], line_width=tmp1['line_width'],
render_markers=tmp2['render_markers'],
marker_style=tmp2['marker_style'], marker_size=tmp2['marker_size'],
marker_face_colour=tmp2['marker_face_colour'][0],
marker_edge_colour=tmp2['marker_edge_colour'][0],
marker_edge_width=tmp2['marker_edge_width'],
render_axes=tmp3['render_axes'],
axes_font_name=tmp3['axes_font_name'],
axes_font_size=tmp3['axes_font_size'],
axes_font_style=tmp3['axes_font_style'],
axes_font_weight=tmp3['axes_font_weight'],
axes_x_limits=tmp3['axes_x_limits'],
axes_y_limits=tmp3['axes_y_limits'], figure_size=new_figure_size,
label=None)
pltshow()
# Save the current figure id
save_figure_wid.renderer = renderer
# Define function that updates the info text
def update_info(pointcloud):
min_b, max_b = pointcloud.bounds()
rang = pointcloud.range()
cm = pointcloud.centre()
text_per_line = [
"> {} points".format(pointcloud.n_points),
"> Bounds: [{0:.1f}-{1:.1f}]W, [{2:.1f}-{3:.1f}]H".format(
min_b[0], max_b[0], min_b[1], max_b[1]),
"> Range: {0:.1f}W, {1:.1f}H".format(rang[0], rang[1]),
"> Centre of mass: ({0:.1f}, {1:.1f})".format(cm[0], cm[1]),
"> Norm: {0:.2f}".format(pointcloud.norm())]
info_wid.set_widget_state(n_lines=5, text_per_line=text_per_line)
# Create widgets
axes_mode_wid = ipywidgets.RadioButtons(
options={'Image': 1, 'Point cloud': 2}, description='Axes mode:',
value=2)
axes_mode_wid.on_trait_change(render_function, 'value')
renderer_options_wid = RendererOptionsWidget(
renderer_options, ['lines', 'markers', 'figure_one'],
object_selection_dropdown_visible=False,
render_function=render_function, style=renderer_style,
tabs_style=renderer_tabs_style)
renderer_options_box = ipywidgets.VBox(
children=[axes_mode_wid, renderer_options_wid], align='center',
margin='0.1cm')
info_wid = TextPrintWidget(n_lines=5, text_per_line=[''] * 5,
style=info_style)
initial_renderer = MatplotlibImageViewer2d(figure_id=None, new_figure=True,
image=np.zeros((10, 10)))
save_figure_wid = SaveFigureOptionsWidget(initial_renderer,
style=save_figure_style)
# Group widgets
if n_pointclouds > 1:
# Pointcloud selection slider
pointcloud_number_wid = AnimationOptionsWidget(
index, render_function=render_function, index_style=browser_style,
interval=0.3, description='Pointcloud ', minus_description='<',
plus_description='>', loop_enabled=True, text_editable=True,
style=animation_style)
# Header widget
header_wid = ipywidgets.HBox(
children=[LogoWidget(style=logo_style), pointcloud_number_wid],
align='start')
else:
# Header widget
header_wid = LogoWidget(style=logo_style)
header_wid.margin = '0.1cm'
options_box = ipywidgets.Tab(children=[info_wid, renderer_options_box,
save_figure_wid], margin='0.1cm')
tab_titles = ['Info', 'Renderer', 'Export']
for (k, tl) in enumerate(tab_titles):
options_box.set_title(k, tl)
if n_pointclouds > 1:
wid = ipywidgets.VBox(children=[header_wid, options_box], align='start')
else:
wid = ipywidgets.HBox(children=[header_wid, options_box], align='start')
# Set widget's style
wid.box_style = widget_box_style
wid.border_radius = widget_border_radius
wid.border_width = widget_border_width
wid.border_color = _map_styles_to_hex_colours(widget_box_style)
_format_box(renderer_options_box, renderer_box_style, True,
renderer_box_border_colour, 'solid', 1,
renderer_box_border_radius, '0.1cm', '0.2cm')
# Display final widget
ipydisplay.display(wid)
# Reset value to trigger initial visualization
axes_mode_wid.value = 1
[docs]def visualize_landmarkgroups(landmarkgroups, figure_size=(10, 8),
style='coloured', browser_style='buttons'):
r"""
Widget that allows browsing through a `list` of :map:`LandmarkGroup`
(or subclass) objects.
The landmark groups can have a combination of different attributes, e.g.
different labels, number of points etc. The widget has options tabs
regarding the landmarks, the renderer (lines, markers, numbering, legend,
figure, axes) and saving the figure to file.
Parameters
----------
landmarkgroups : `list` of :map:`LandmarkGroup` or subclass
The `list` of landmark groups to be visualized.
figure_size : (`int`, `int`), optional
The initial size of the rendered figure.
style : {``'coloured'``, ``'minimal'``}, optional
If ``'coloured'``, then the style of the widget will be coloured. If
``minimal``, then the style is simple using black and white colours.
browser_style : {``'buttons'``, ``'slider'``}, optional
It defines whether the selector of the objects will have the form of
plus/minus buttons or a slider.
"""
print('Initializing...')
# Make sure that landmarkgroups is a list even with one landmark group
# member
if not isinstance(landmarkgroups, list):
landmarkgroups = [landmarkgroups]
# Get the number of landmarkgroups
n_landmarkgroups = len(landmarkgroups)
# Define the styling options
if style == 'coloured':
logo_style = 'success'
widget_box_style = 'success'
widget_border_radius = 10
widget_border_width = 1
animation_style = 'success'
landmarks_style = 'info'
info_style = 'info'
renderer_box_style = 'info'
renderer_box_border_colour = _map_styles_to_hex_colours('info')
renderer_box_border_radius = 10
renderer_style = 'danger'
renderer_tabs_style = 'minimal'
save_figure_style = 'danger'
else:
logo_style = 'minimal'
widget_box_style = ''
widget_border_radius = 0
widget_border_width = 0
landmarks_style = 'minimal'
animation_style = 'minimal'
info_style = 'minimal'
renderer_box_style = ''
renderer_box_border_colour = 'black'
renderer_box_border_radius = 0
renderer_style = 'minimal'
renderer_tabs_style = 'minimal'
save_figure_style = 'minimal'
# Find all available groups and the respective labels from all the landmarks
# that are passed in
all_groups = []
all_labels = []
groups_l = 0
for i, l in enumerate(landmarkgroups):
labels_l = l.labels
if labels_l not in all_labels:
groups_l += 1
all_groups.append(str(groups_l))
all_labels.append(labels_l)
# Get initial line and marker colours for each available group
colours = []
for l in all_labels:
if len(l) == 1:
colours.append(['r'])
else:
colours.append(sample_colours_from_colourmap(len(l), 'jet'))
# initial options dictionaries
landmark_options = {'has_landmarks': True, 'render_landmarks': True,
'group_keys': ['0'],
'labels_keys': [landmarkgroups[0].labels],
'group': '0', 'with_labels': landmarkgroups[0].labels}
index = {'min': 0, 'max': n_landmarkgroups-1, 'step': 1, 'index': 0}
numbering_options = {'render_numbering': False,
'numbers_font_name': 'sans-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'}
legend_options = {'render_legend': True, 'legend_title': '',
'legend_font_name': 'sans-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': False}
figure_options = {'x_scale': 1., 'y_scale': 1., 'render_axes': False,
'axes_font_name': 'sans-serif', 'axes_font_size': 10,
'axes_font_style': 'normal', 'axes_font_weight': 'normal',
'axes_x_limits': None, 'axes_y_limits': None}
renderer_options = []
for i in range(len(all_labels)):
lines_options = {'render_lines': True, 'line_width': 1,
'line_colour': colours[i], 'line_style': '-'}
marker_options = {'render_markers': True, 'marker_size': 20,
'marker_face_colour': list(colours[i]),
'marker_edge_colour': list(colours[i]),
'marker_style': 'o', 'marker_edge_width': 1}
tmp = {'lines': lines_options, 'markers': marker_options,
'numbering': numbering_options, 'legend': legend_options,
'figure': figure_options}
renderer_options.append(tmp)
# Define render function
def render_function(name, value):
# Clear current figure, but wait until the generation of the new data
# that will be rendered
ipydisplay.clear_output(wait=True)
# get selected index
im = 0
if n_landmarkgroups > 1:
im = landmark_number_wid.selected_values['index']
# update info text widget
update_info(landmarkgroups[im])
# show landmarks with selected options
group_idx = all_labels.index(landmarkgroups[im].labels)
tmp1 = renderer_options_wid.selected_values[group_idx]['lines']
tmp2 = renderer_options_wid.selected_values[group_idx]['markers']
tmp3 = renderer_options_wid.selected_values[group_idx]['numbering']
tmp4 = renderer_options_wid.selected_values[group_idx]['legend']
tmp5 = renderer_options_wid.selected_values[group_idx]['figure']
new_figure_size = (tmp5['x_scale'] * figure_size[0],
tmp5['y_scale'] * figure_size[1])
# find the with_labels' indices
with_labels_idx = [
landmark_options_wid.selected_values['labels_keys'][0].index(lbl)
for lbl in landmark_options_wid.selected_values['with_labels']]
# get line and marker colours
line_colour = [tmp1['line_colour'][lbl_idx]
for lbl_idx in with_labels_idx]
marker_face_colour = [tmp2['marker_face_colour'][lbl_idx]
for lbl_idx in with_labels_idx]
marker_edge_colour = [tmp2['marker_edge_colour'][lbl_idx]
for lbl_idx in with_labels_idx]
if landmark_options_wid.selected_values['render_landmarks']:
renderer = landmarkgroups[im].view(
with_labels=landmark_options_wid.selected_values['with_labels'],
figure_id=save_figure_wid.renderer.figure_id, new_figure=False,
image_view=axes_mode_wid.value == 1,
render_lines=tmp1['render_lines'], line_colour=line_colour,
line_style=tmp1['line_style'], line_width=tmp1['line_width'],
render_markers=tmp2['render_markers'],
marker_style=tmp2['marker_style'],
marker_size=tmp2['marker_size'],
marker_face_colour=marker_face_colour,
marker_edge_colour=marker_edge_colour,
marker_edge_width=tmp2['marker_edge_width'],
render_numbering=tmp3['render_numbering'],
numbers_font_name=tmp3['numbers_font_name'],
numbers_font_size=tmp3['numbers_font_size'],
numbers_font_style=tmp3['numbers_font_style'],
numbers_font_weight=tmp3['numbers_font_weight'],
numbers_font_colour=tmp3['numbers_font_colour'][0],
numbers_horizontal_align=tmp3['numbers_horizontal_align'],
numbers_vertical_align=tmp3['numbers_vertical_align'],
legend_n_columns=tmp4['legend_n_columns'],
legend_border_axes_pad=tmp4['legend_border_axes_pad'],
legend_rounded_corners=tmp4['legend_rounded_corners'],
legend_title=tmp4['legend_title'],
legend_horizontal_spacing=tmp4['legend_horizontal_spacing'],
legend_shadow=tmp4['legend_shadow'],
legend_location=tmp4['legend_location'],
legend_font_name=tmp4['legend_font_name'],
legend_bbox_to_anchor=tmp4['legend_bbox_to_anchor'],
legend_border=tmp4['legend_border'],
legend_marker_scale=tmp4['legend_marker_scale'],
legend_vertical_spacing=tmp4['legend_vertical_spacing'],
legend_font_weight=tmp4['legend_font_weight'],
legend_font_size=tmp4['legend_font_size'],
render_legend=tmp4['render_legend'],
legend_font_style=tmp4['legend_font_style'],
legend_border_padding=tmp4['legend_border_padding'],
render_axes=tmp5['render_axes'],
axes_font_name=tmp5['axes_font_name'],
axes_font_size=tmp5['axes_font_size'],
axes_font_style=tmp5['axes_font_style'],
axes_font_weight=tmp5['axes_font_weight'],
axes_x_limits=tmp5['axes_x_limits'],
axes_y_limits=tmp5['axes_y_limits'],
figure_size=new_figure_size)
pltshow()
# Save the current figure id
save_figure_wid.renderer = renderer
else:
ipydisplay.clear_output()
# Define function that updates the info text
def update_info(landmarkgroup):
min_b, max_b = landmarkgroup.lms.bounds()
rang = landmarkgroup.lms.range()
cm = landmarkgroup.lms.centre()
text_per_line = [
"> {} landmark points".format(landmarkgroup.n_landmarks),
"> Bounds: [{0:.1f}-{1:.1f}]W, [{2:.1f}-{3:.1f}]H".format(
min_b[0], max_b[0], min_b[1], max_b[1]),
"> Range: {0:.1f}W, {1:.1f}H".format(rang[0], rang[1]),
"> Centre of mass: ({0:.1f}, {1:.1f})".format(cm[0], cm[1]),
"> Norm: {0:.2f}".format(landmarkgroup.lms.norm())]
info_wid.set_widget_state(n_lines=5, text_per_line=text_per_line)
# Create widgets
landmark_options_wid = LandmarkOptionsWidget(
landmark_options, render_function=render_function,
style=landmarks_style)
axes_mode_wid = ipywidgets.RadioButtons(
options={'Image': 1, 'Point cloud': 2}, description='Axes mode:',
value=2)
axes_mode_wid.on_trait_change(render_function, 'value')
renderer_options_wid = RendererOptionsWidget(
renderer_options,
['lines', 'markers', 'numbering', 'legend', 'figure_one'],
object_selection_dropdown_visible=False, labels_per_object=all_labels,
render_function=render_function, selected_object=0,
style=renderer_style, tabs_style=renderer_tabs_style)
renderer_options_box = ipywidgets.VBox(
children=[axes_mode_wid, renderer_options_wid], align='center',
margin='0.1cm')
info_wid = TextPrintWidget(n_lines=5, text_per_line=[''] * 5,
style=info_style)
initial_renderer = MatplotlibImageViewer2d(figure_id=None, new_figure=True,
image=np.zeros((10, 10)))
save_figure_wid = SaveFigureOptionsWidget(initial_renderer,
style=save_figure_style)
# Define function that updates options' widgets state
def update_widgets(name, value):
# Get new groups and labels, then update landmark options
im = 0
if n_landmarkgroups > 1:
im = landmark_number_wid.selected_values['index']
landmark_options = {
'has_landmarks': True,
'render_landmarks':
landmark_options_wid.selected_values['render_landmarks'],
'group_keys': ['0'], 'labels_keys': [landmarkgroups[im].labels],
'group': '0', 'with_labels': None}
landmark_options_wid.set_widget_state(landmark_options, False)
landmark_options_wid.predefined_style(landmarks_style)
# Set correct group to renderer options' selection
renderer_options_wid.object_selection_dropdown.value = \
all_labels.index(landmarkgroups[im].labels)
# Group widgets
if n_landmarkgroups > 1:
# Landmark selection slider
landmark_number_wid = AnimationOptionsWidget(
index, render_function=render_function,
update_function=update_widgets, index_style=browser_style,
interval=0.3, description='Shape', minus_description='<',
plus_description='>', loop_enabled=True, text_editable=True,
style=animation_style)
# Header widget
header_wid = ipywidgets.HBox(
children=[LogoWidget(style=logo_style), landmark_number_wid],
align='start')
else:
# Header widget
header_wid = LogoWidget(style=logo_style)
header_wid.margin = '0.2cm'
options_box = ipywidgets.Tab(
children=[info_wid, landmark_options_wid, renderer_options_box,
save_figure_wid], margin='0.2cm')
tab_titles = ['Info', 'Landmarks', 'Renderer', 'Export']
for (k, tl) in enumerate(tab_titles):
options_box.set_title(k, tl)
if n_landmarkgroups > 1:
wid = ipywidgets.VBox(children=[header_wid, options_box], align='start')
else:
wid = ipywidgets.HBox(children=[header_wid, options_box], align='start')
# Set widget's style
wid.box_style = widget_box_style
wid.border_radius = widget_border_radius
wid.border_width = widget_border_width
wid.border_color = _map_styles_to_hex_colours(widget_box_style)
_format_box(renderer_options_box, renderer_box_style, True,
renderer_box_border_colour, 'solid', 1,
renderer_box_border_radius, '0.1cm', '0.2cm')
# Display final widget
ipydisplay.display(wid)
# Reset value to trigger initial visualization
axes_mode_wid.value = 1
[docs]def visualize_landmarks(landmarks, figure_size=(10, 8), style='coloured',
browser_style='buttons'):
r"""
Widget that allows browsing through a `list` of :map:`LandmarkManager`
(or subclass) objects.
The landmark managers can have a combination of different attributes, e.g.
landmark groups and labels etc. The widget has options tabs regarding the
landmarks, the renderer (lines, markers, numbering, legend, figure, axes)
and saving the figure to file.
Parameters
----------
landmarks : `list` of :map:`LandmarkManager` or subclass
The `list` of landmark managers to be visualized.
figure_size : (`int`, `int`), optional
The initial size of the rendered figure.
style : {``'coloured'``, ``'minimal'``}, optional
If ``'coloured'``, then the style of the widget will be coloured. If
``minimal``, then the style is simple using black and white colours.
browser_style : {``'buttons'``, ``'slider'``}, optional
It defines whether the selector of the objects will have the form of
plus/minus buttons or a slider.
"""
print('Initializing...')
# Make sure that landmarks is a list even with one landmark manager member
if not isinstance(landmarks, list):
landmarks = [landmarks]
# Get the number of landmark managers
n_landmarks = len(landmarks)
# Define the styling options
if style == 'coloured':
logo_style = 'info'
widget_box_style = 'info'
widget_border_radius = 10
widget_border_width = 1
animation_style = 'info'
landmarks_style = 'danger'
info_style = 'danger'
renderer_box_style = 'danger'
renderer_box_border_colour = _map_styles_to_hex_colours('danger')
renderer_box_border_radius = 10
renderer_style = 'warning'
renderer_tabs_style = 'minimal'
save_figure_style = 'danger'
else:
logo_style = 'minimal'
widget_box_style = ''
widget_border_radius = 0
widget_border_width = 0
landmarks_style = 'minimal'
animation_style = 'minimal'
info_style = 'minimal'
renderer_box_style = ''
renderer_box_border_colour = 'black'
renderer_box_border_radius = 0
renderer_style = 'minimal'
renderer_tabs_style = 'minimal'
save_figure_style = 'minimal'
# Find all available groups and the respective labels from all the landmarks
# that are passed in
all_groups = []
all_labels = []
for l in landmarks:
groups_l, labels_l = _extract_group_labels_landmarks(l)
for i, g in enumerate(groups_l):
if g not in all_groups:
all_groups.append(g)
all_labels.append(labels_l[i])
# Get initial line and marker colours for each available group
colours = []
for l in all_labels:
if len(l) == 1:
colours.append(['r'])
else:
colours.append(sample_colours_from_colourmap(len(l), 'jet'))
# Initial options dictionaries
initial_groups_keys, initial_labels_keys = \
_extract_group_labels_landmarks(landmarks[0])
landmark_options = {'has_landmarks': landmarks[0].has_landmarks,
'render_landmarks': True,
'group_keys': initial_groups_keys,
'labels_keys': initial_labels_keys,
'group': initial_groups_keys[0],
'with_labels': initial_labels_keys[0]}
index = {'min': 0, 'max': n_landmarks-1, 'step': 1, 'index': 0}
numbering_options = {'render_numbering': False,
'numbers_font_name': 'sans-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'}
legend_options = {'render_legend': True, 'legend_title': '',
'legend_font_name': 'sans-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': False}
figure_options = {'x_scale': 1., 'y_scale': 1., 'render_axes': False,
'axes_font_name': 'sans-serif', 'axes_font_size': 10,
'axes_font_style': 'normal', 'axes_font_weight': 'normal',
'axes_x_limits': None, 'axes_y_limits': None}
renderer_options = []
for i in range(len(all_labels)):
lines_options = {'render_lines': True, 'line_width': 1,
'line_colour': colours[i], 'line_style': '-'}
marker_options = {'render_markers': True, 'marker_size': 20,
'marker_face_colour': list(colours[i]),
'marker_edge_colour': list(colours[i]),
'marker_style': 'o', 'marker_edge_width': 1}
tmp = {'lines': lines_options, 'markers': marker_options,
'numbering': numbering_options, 'legend': legend_options,
'figure': figure_options}
renderer_options.append(tmp)
# Define render function
def render_function(name, value):
# Clear current figure, but wait until the generation of the new data
# that will be rendered
ipydisplay.clear_output(wait=True)
# get selected index
im = 0
if n_landmarks > 1:
im = landmark_number_wid.selected_values['index']
# update info text widget
update_info(landmarks[im],
landmark_options_wid.selected_values['group'])
# show landmarks with selected options
group_idx = all_groups.index(
landmark_options_wid.selected_values['group'])
tmp1 = renderer_options_wid.selected_values[group_idx]['lines']
tmp2 = renderer_options_wid.selected_values[group_idx]['markers']
tmp3 = renderer_options_wid.selected_values[group_idx]['numbering']
tmp4 = renderer_options_wid.selected_values[group_idx]['legend']
tmp5 = renderer_options_wid.selected_values[group_idx]['figure']
new_figure_size = (tmp5['x_scale'] * figure_size[0],
tmp5['y_scale'] * figure_size[1])
# get selected group
sel_group = landmark_options_wid.selected_values['group']
sel_group_idx = landmark_options_wid.selected_values[
'group_keys'].index(sel_group)
# find the with_labels' indices
with_labels_idx = [
landmark_options_wid.selected_values['labels_keys'][
sel_group_idx].index(lbl)
for lbl in landmark_options_wid.selected_values['with_labels']]
# get line and marker colours
line_colour = [tmp1['line_colour'][lbl_idx]
for lbl_idx in with_labels_idx]
marker_face_colour = [tmp2['marker_face_colour'][lbl_idx]
for lbl_idx in with_labels_idx]
marker_edge_colour = [tmp2['marker_edge_colour'][lbl_idx]
for lbl_idx in with_labels_idx]
if landmark_options_wid.selected_values['render_landmarks']:
renderer = landmarks[im][sel_group].view(
with_labels=landmark_options_wid.selected_values['with_labels'],
figure_id=save_figure_wid.renderer.figure_id, new_figure=False,
image_view=axes_mode_wid.value == 1,
render_lines=tmp1['render_lines'], line_colour=line_colour,
line_style=tmp1['line_style'], line_width=tmp1['line_width'],
render_markers=tmp2['render_markers'],
marker_style=tmp2['marker_style'],
marker_size=tmp2['marker_size'],
marker_face_colour=marker_face_colour,
marker_edge_colour=marker_edge_colour,
marker_edge_width=tmp2['marker_edge_width'],
render_numbering=tmp3['render_numbering'],
numbers_font_name=tmp3['numbers_font_name'],
numbers_font_size=tmp3['numbers_font_size'],
numbers_font_style=tmp3['numbers_font_style'],
numbers_font_weight=tmp3['numbers_font_weight'],
numbers_font_colour=tmp3['numbers_font_colour'][0],
numbers_horizontal_align=tmp3['numbers_horizontal_align'],
numbers_vertical_align=tmp3['numbers_vertical_align'],
legend_n_columns=tmp4['legend_n_columns'],
legend_border_axes_pad=tmp4['legend_border_axes_pad'],
legend_rounded_corners=tmp4['legend_rounded_corners'],
legend_title=tmp4['legend_title'],
legend_horizontal_spacing=tmp4['legend_horizontal_spacing'],
legend_shadow=tmp4['legend_shadow'],
legend_location=tmp4['legend_location'],
legend_font_name=tmp4['legend_font_name'],
legend_bbox_to_anchor=tmp4['legend_bbox_to_anchor'],
legend_border=tmp4['legend_border'],
legend_marker_scale=tmp4['legend_marker_scale'],
legend_vertical_spacing=tmp4['legend_vertical_spacing'],
legend_font_weight=tmp4['legend_font_weight'],
legend_font_size=tmp4['legend_font_size'],
render_legend=tmp4['render_legend'],
legend_font_style=tmp4['legend_font_style'],
legend_border_padding=tmp4['legend_border_padding'],
render_axes=tmp5['render_axes'],
axes_font_name=tmp5['axes_font_name'],
axes_font_size=tmp5['axes_font_size'],
axes_font_style=tmp5['axes_font_style'],
axes_font_weight=tmp5['axes_font_weight'],
axes_x_limits=tmp5['axes_x_limits'],
axes_y_limits=tmp5['axes_y_limits'],
figure_size=new_figure_size)
pltshow()
# Save the current figure id
save_figure_wid.renderer = renderer
else:
ipydisplay.clear_output()
# Define function that updates the info text
def update_info(landmarks, group):
if group != ' ':
min_b, max_b = landmarks[group][None].bounds()
rang = landmarks[group][None].range()
cm = landmarks[group][None].centre()
text_per_line = [
"> {} landmark points".format(landmarks[group][None].n_points),
"> Bounds: [{0:.1f}-{1:.1f}]W, [{2:.1f}-{3:.1f}]H".
format(min_b[0], max_b[0], min_b[1], max_b[1]),
"> Range: {0:.1f}W, {1:.1f}H".format(rang[0], rang[1]),
"> Centre of mass: ({0:.1f}, {1:.1f})".format(cm[0], cm[1]),
"> Norm: {0:.2f}".format(landmarks[group][None].norm())]
n_lines = 5
else:
text_per_line = ["No landmarks available."]
n_lines = 1
info_wid.set_widget_state(n_lines=n_lines, text_per_line=text_per_line)
# Define update function of landmark widget
def update_renderer_widget(name, value):
renderer_options_wid.object_selection_dropdown.value = \
all_groups.index(landmark_options_wid.selected_values['group'])
# Create widgets
landmark_options_wid = LandmarkOptionsWidget(
landmark_options, render_function=render_function,
update_function=update_renderer_widget, style=landmarks_style)
axes_mode_wid = ipywidgets.RadioButtons(
options={'Image': 1, 'Point cloud': 2}, description='Axes mode:',
value=2)
axes_mode_wid.on_trait_change(render_function, 'value')
renderer_options_wid = RendererOptionsWidget(
renderer_options,
['lines', 'markers', 'numbering', 'legend', 'figure_one'],
objects_names=all_groups,
object_selection_dropdown_visible=False, labels_per_object=all_labels,
render_function=render_function, selected_object=0,
style=renderer_style, tabs_style=renderer_tabs_style)
renderer_options_box = ipywidgets.VBox(
children=[axes_mode_wid, renderer_options_wid], align='center',
margin='0.1cm')
info_wid = TextPrintWidget(n_lines=5, text_per_line=[''] * 5,
style=info_style)
initial_renderer = MatplotlibImageViewer2d(figure_id=None, new_figure=True,
image=np.zeros((10, 10)))
save_figure_wid = SaveFigureOptionsWidget(initial_renderer,
style=save_figure_style)
# Define function that updates options' widgets state
def update_widgets(name, value):
# Get new groups and labels, then update landmark options
im = 0
if n_landmarks > 1:
im = landmark_number_wid.selected_values['index']
group_keys, labels_keys = _extract_group_labels_landmarks(landmarks[im])
landmark_options = {
'has_landmarks': landmarks[im].has_landmarks,
'render_landmarks':
landmark_options_wid.selected_values['render_landmarks'],
'group_keys': group_keys, 'labels_keys': labels_keys,
'group': None, 'with_labels': None}
landmark_options_wid.set_widget_state(landmark_options, False)
landmark_options_wid.predefined_style(landmarks_style)
# Set correct group to renderer options' selection
renderer_options_wid.object_selection_dropdown.value = \
all_groups.index(landmark_options_wid.selected_values['group'])
# Group widgets
if n_landmarks > 1:
# Landmark selection slider
landmark_number_wid = AnimationOptionsWidget(
index, render_function=render_function,
update_function=update_widgets, index_style=browser_style,
interval=0.3, description='Shape', minus_description='<',
plus_description='>', loop_enabled=True, text_editable=True,
style=animation_style)
# Header widget
header_wid = ipywidgets.HBox(
children=[LogoWidget(style=logo_style), landmark_number_wid],
align='start')
else:
# Header widget
header_wid = LogoWidget(style=logo_style)
header_wid.margin = '0.2cm'
options_box = ipywidgets.Tab(
children=[info_wid, landmark_options_wid, renderer_options_box,
save_figure_wid], margin='0.2cm')
tab_titles = ['Info', 'Landmarks', 'Renderer', 'Export']
for (k, tl) in enumerate(tab_titles):
options_box.set_title(k, tl)
if n_landmarks > 1:
wid = ipywidgets.VBox(children=[header_wid, options_box], align='start')
else:
wid = ipywidgets.HBox(children=[header_wid, options_box], align='start')
# Set widget's style
wid.box_style = widget_box_style
wid.border_radius = widget_border_radius
wid.border_width = widget_border_width
wid.border_color = _map_styles_to_hex_colours(widget_box_style)
_format_box(renderer_options_box, renderer_box_style, True,
renderer_box_border_colour, 'solid', 1,
renderer_box_border_radius, '0.1cm', '0.2cm')
# Display final widget
ipydisplay.display(wid)
# Reset value to trigger initial visualization
axes_mode_wid.value = 1
[docs]def visualize_images(images, figure_size=(10, 8), style='coloured',
browser_style='buttons'):
r"""
Widget that allows browsing through a `list` of :map:`Image` (or subclass)
objects.
The images can have a combination of different attributes, e.g. masked or
not, landmarked or not, without multiple landmark groups and labels etc.
The widget has options tabs regarding the visualized channels, the
landmarks, the renderer (lines, markers, numbering, legend, figure, axes)
and saving the figure to file.
Parameters
----------
images : `list` of :map:`Image` or subclass
The `list` of images to be visualized.
figure_size : (`int`, `int`), optional
The initial size of the rendered figure.
style : {``'coloured'``, ``'minimal'``}, optional
If ``'coloured'``, then the style of the widget will be coloured. If
``minimal``, then the style is simple using black and white colours.
browser_style : {``'buttons'``, ``'slider'``}, optional
It defines whether the selector of the objects will have the form of
plus/minus buttons or a slider.
"""
from menpo.image import MaskedImage
print('Initializing...')
# Make sure that images is a list even with one image member
if not isinstance(images, Sized):
images = [images]
# Get the number of images
n_images = len(images)
# Define the styling options
if style == 'coloured':
logo_style = 'info'
widget_box_style = 'info'
widget_border_radius = 10
widget_border_width = 1
animation_style = 'info'
channels_style = 'danger'
landmarks_style = 'danger'
info_style = 'danger'
renderer_style = 'danger'
renderer_tabs_style = 'minimal'
save_figure_style = 'danger'
else:
logo_style = 'minimal'
widget_box_style = ''
widget_border_radius = 0
widget_border_width = 0
channels_style = 'minimal'
landmarks_style = 'minimal'
animation_style = 'minimal'
info_style = 'minimal'
renderer_style = 'minimal'
renderer_tabs_style = 'minimal'
save_figure_style = 'minimal'
# Find all available groups and the respective labels from all the landmarks
# that are passed in
all_groups = []
all_labels = []
for l in images:
groups_l, labels_l = _extract_groups_labels(l)
for i, g in enumerate(groups_l):
if g not in all_groups:
all_groups.append(g)
all_labels.append(labels_l[i])
# Get initial line and marker colours for each available group
colours = []
for l in all_labels:
if len(l) == 1:
colours.append(['r'])
else:
colours.append(sample_colours_from_colourmap(len(l), 'jet'))
# Initial options dictionaries
channels_default = 0
if images[0].n_channels == 3:
channels_default = None
channel_options = {'n_channels': images[0].n_channels,
'image_is_masked': isinstance(images[0], MaskedImage),
'channels': channels_default, 'glyph_enabled': False,
'glyph_block_size': 3, 'glyph_use_negative': False,
'sum_enabled': False,
'masked_enabled': isinstance(images[0], MaskedImage)}
initial_groups_keys, initial_labels_keys = _extract_groups_labels(images[0])
landmark_options = {'has_landmarks': images[0].has_landmarks,
'render_landmarks': True,
'group_keys': initial_groups_keys,
'labels_keys': initial_labels_keys,
'group': initial_groups_keys[0],
'with_labels': initial_labels_keys[0]}
index = {'min': 0, 'max': n_images-1, 'step': 1, 'index': 0}
image_options = {'alpha': 1.0, 'interpolation': 'bilinear',
'cmap_name': None}
numbering_options = {'render_numbering': False,
'numbers_font_name': 'sans-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'}
legend_options = {'render_legend': True, 'legend_title': '',
'legend_font_name': 'sans-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': False}
figure_options = {'x_scale': 1., 'y_scale': 1., 'render_axes': False,
'axes_font_name': 'sans-serif', 'axes_font_size': 10,
'axes_font_style': 'normal', 'axes_font_weight': 'normal',
'axes_x_limits': None, 'axes_y_limits': None}
renderer_options = []
for i in range(len(all_labels)):
lines_options = {'render_lines': True, 'line_width': 1,
'line_colour': colours[i], 'line_style': '-'}
marker_options = {'render_markers': True, 'marker_size': 20,
'marker_face_colour': list(colours[i]),
'marker_edge_colour': list(colours[i]),
'marker_style': 'o', 'marker_edge_width': 1}
tmp = {'lines': lines_options, 'markers': marker_options,
'numbering': numbering_options, 'legend': legend_options,
'figure': figure_options, 'image': image_options}
renderer_options.append(tmp)
# Define render function
def render_function(name, value):
# Clear current figure, but wait until the generation of the new data
# that will be rendered
ipydisplay.clear_output(wait=True)
# get selected index
im = 0
if n_images > 1:
im = image_number_wid.selected_values['index']
# update info text widget
image_is_masked = isinstance(images[im], MaskedImage)
update_info(images[im], image_is_masked,
landmark_options_wid.selected_values['group'])
# show image with selected options
group_idx = all_groups.index(
landmark_options_wid.selected_values['group'])
tmp1 = renderer_options_wid.selected_values[group_idx]['lines']
tmp2 = renderer_options_wid.selected_values[group_idx]['markers']
tmp3 = renderer_options_wid.selected_values[group_idx]['numbering']
tmp4 = renderer_options_wid.selected_values[group_idx]['legend']
tmp5 = renderer_options_wid.selected_values[group_idx]['figure']
tmp6 = renderer_options_wid.selected_values[group_idx]['image']
new_figure_size = (tmp5['x_scale'] * figure_size[0],
tmp5['y_scale'] * figure_size[1])
# get selected group index
sel_group_idx = landmark_options_wid.selected_values[
'group_keys'].index(landmark_options_wid.selected_values['group'])
# find the with_labels' indices
with_labels_idx = [
landmark_options_wid.selected_values['labels_keys'][
sel_group_idx].index(lbl)
for lbl in landmark_options_wid.selected_values['with_labels']]
# get line and marker colours
line_colour = [tmp1['line_colour'][lbl_idx]
for lbl_idx in with_labels_idx]
marker_face_colour = [tmp2['marker_face_colour'][lbl_idx]
for lbl_idx in with_labels_idx]
marker_edge_colour = [tmp2['marker_edge_colour'][lbl_idx]
for lbl_idx in with_labels_idx]
renderer = _visualize(
images[im], save_figure_wid.renderer,
landmark_options_wid.selected_values['render_landmarks'],
image_is_masked,
channel_options_wid.selected_values['masked_enabled'],
channel_options_wid.selected_values['channels'],
channel_options_wid.selected_values['glyph_enabled'],
channel_options_wid.selected_values['glyph_block_size'],
channel_options_wid.selected_values['glyph_use_negative'],
channel_options_wid.selected_values['sum_enabled'],
landmark_options_wid.selected_values['group'],
landmark_options_wid.selected_values['with_labels'],
tmp1['render_lines'], tmp1['line_style'], tmp1['line_width'],
line_colour, tmp2['render_markers'], tmp2['marker_style'],
tmp2['marker_size'], tmp2['marker_edge_width'], marker_edge_colour,
marker_face_colour, tmp3['render_numbering'],
tmp3['numbers_font_name'], tmp3['numbers_font_size'],
tmp3['numbers_font_style'], tmp3['numbers_font_weight'],
tmp3['numbers_font_colour'][0], tmp3['numbers_horizontal_align'],
tmp3['numbers_vertical_align'], tmp4['legend_n_columns'],
tmp4['legend_border_axes_pad'], tmp4['legend_rounded_corners'],
tmp4['legend_title'], tmp4['legend_horizontal_spacing'],
tmp4['legend_shadow'], tmp4['legend_location'],
tmp4['legend_font_name'], tmp4['legend_bbox_to_anchor'],
tmp4['legend_border'], tmp4['legend_marker_scale'],
tmp4['legend_vertical_spacing'], tmp4['legend_font_weight'],
tmp4['legend_font_size'], tmp4['render_legend'],
tmp4['legend_font_style'], tmp4['legend_border_padding'],
new_figure_size, tmp5['render_axes'], tmp5['axes_font_name'],
tmp5['axes_font_size'], tmp5['axes_font_style'],
tmp5['axes_x_limits'], tmp5['axes_y_limits'],
tmp5['axes_font_weight'], tmp6['interpolation'], tmp6['alpha'],
tmp6['cmap_name'])
# Save the current figure id
save_figure_wid.renderer = renderer
# Define function that updates the info text
def update_info(img, image_is_masked, group):
# Prepare masked (or non-masked) string
masked_str = 'Masked Image' if image_is_masked else 'Image'
# Get image path, if available
path_str = img.path if hasattr(img, 'path') else 'No path available'
# Create text lines
text_per_line = [
"> {} of size {} with {} channel{}".format(
masked_str, img._str_shape, img.n_channels,
's' * (img.n_channels > 1)),
"> Path: '{}'".format(path_str)]
n_lines = 2
if image_is_masked:
text_per_line.append(
"> {} masked pixels (attached mask {:.1%} true)".format(
img.n_true_pixels(), img.mask.proportion_true()))
n_lines += 1
text_per_line.append("> min={:.3f}, max={:.3f}".format(
img.pixels.min(), img.pixels.max()))
n_lines += 1
if img.has_landmarks:
text_per_line.append("> {} landmark points".format(
img.landmarks[group].lms.n_points))
n_lines += 1
info_wid.set_widget_state(n_lines=n_lines, text_per_line=text_per_line)
# Define update function of renderer widget
def update_renderer_widget(name, value):
renderer_options_wid.object_selection_dropdown.value = \
all_groups.index(landmark_options_wid.selected_values['group'])
# Create widgets
channel_options_wid = ChannelOptionsWidget(
channel_options, render_function=render_function, style=channels_style)
landmark_options_wid = LandmarkOptionsWidget(
landmark_options, render_function=render_function,
update_function=update_renderer_widget, style=landmarks_style)
renderer_options_wid = RendererOptionsWidget(
renderer_options,
['lines', 'markers', 'numbering', 'legend', 'figure_one', 'image'],
objects_names=all_groups,
object_selection_dropdown_visible=False, labels_per_object=all_labels,
render_function=render_function, selected_object=0,
style=renderer_style, tabs_style=renderer_tabs_style)
info_wid = TextPrintWidget(n_lines=1, text_per_line=[''],
style=info_style)
initial_renderer = MatplotlibImageViewer2d(figure_id=None, new_figure=True,
image=np.zeros((10, 10)))
save_figure_wid = SaveFigureOptionsWidget(initial_renderer,
style=save_figure_style)
# Define function that updates options' widgets state
def update_widgets(name, value):
# Get new groups and labels, then update landmark options
im = 0
if n_images > 1:
im = image_number_wid.selected_values['index']
group_keys, labels_keys = _extract_groups_labels(images[im])
landmark_options = {
'has_landmarks': images[im].has_landmarks,
'render_landmarks':
landmark_options_wid.selected_values['render_landmarks'],
'group_keys': group_keys, 'labels_keys': labels_keys,
'group': None, 'with_labels': None}
landmark_options_wid.set_widget_state(landmark_options, False)
landmark_options_wid.predefined_style(landmarks_style)
# Update channel options
tmp_channels = channel_options_wid.selected_values['channels']
tmp_glyph_enabled = channel_options_wid.selected_values['glyph_enabled']
tmp_sum_enabled = channel_options_wid.selected_values['sum_enabled']
if np.max(tmp_channels) > images[im].n_channels - 1:
tmp_channels = 0
tmp_glyph_enabled = False
tmp_sum_enabled = False
tmp_glyph_block_size = \
channel_options_wid.selected_values['glyph_block_size']
tmp_glyph_use_negative = \
channel_options_wid.selected_values['glyph_use_negative']
if not(images[im].n_channels == 3) and tmp_channels is None:
tmp_channels = 0
channel_options = {
'n_channels': images[im].n_channels,
'image_is_masked': isinstance(images[im], MaskedImage),
'channels': tmp_channels, 'glyph_enabled': tmp_glyph_enabled,
'glyph_block_size': tmp_glyph_block_size,
'glyph_use_negative': tmp_glyph_use_negative,
'sum_enabled': tmp_sum_enabled,
'masked_enabled': isinstance(images[im], MaskedImage)}
channel_options_wid.set_widget_state(channel_options, False)
# Set correct group to renderer options' selection
renderer_options_wid.object_selection_dropdown.value = \
all_groups.index(landmark_options_wid.selected_values['group'])
# Group widgets
if n_images > 1:
# Image selection slider
image_number_wid = AnimationOptionsWidget(
index, render_function=render_function,
update_function=update_widgets, index_style=browser_style,
interval=0.3, description='Image', minus_description='<',
plus_description='>', loop_enabled=True, text_editable=True,
style=animation_style)
# Header widget
header_wid = ipywidgets.HBox(
children=[LogoWidget(style=logo_style), image_number_wid],
align='start')
else:
# Header widget
header_wid = LogoWidget(style=logo_style)
header_wid.margin = '0.2cm'
options_box = ipywidgets.Tab(
children=[info_wid, channel_options_wid, landmark_options_wid,
renderer_options_wid, save_figure_wid], margin='0.2cm')
tab_titles = ['Info', 'Channels', 'Landmarks', 'Renderer', 'Export']
for (k, tl) in enumerate(tab_titles):
options_box.set_title(k, tl)
if n_images > 1:
wid = ipywidgets.VBox(children=[header_wid, options_box], align='start')
else:
wid = ipywidgets.HBox(children=[header_wid, options_box], align='start')
# Set widget's style
wid.box_style = widget_box_style
wid.border_radius = widget_border_radius
wid.border_width = widget_border_width
wid.border_color = _map_styles_to_hex_colours(widget_box_style)
# Display final widget
ipydisplay.display(wid)
# Reset value to trigger initial visualization
renderer_options_wid.options_widgets[3].render_legend_checkbox.value = False
[docs]def plot_graph(x_axis, y_axis, legend_entries=None, title=None, x_label=None,
y_label=None, x_axis_limits=None, y_axis_limits=None,
figure_size=(10, 6), style='coloured'):
r"""
Widget that allows plotting various curves in a graph using
:map:`GraphPlotter`.
The widget has options tabs regarding the graph and the renderer (lines,
markers, legend, figure, axes, grid) and saving the figure to file.
Parameters
----------
x_axis : `list` of `float`
The values of the horizontal axis. Note that these values are common for
all the curves.
y_axis : `list` of `lists` of `float`
A `list` that stores a `list` of values to be plotted for each curve.
legend_entries : `list` or `str` or ``None``, optional
The `list` of names that will appear on the legend for each curve. If
``None``, then the names format is ``curve {}.format(i)``.
title : `str` or ``None``, optional
The title of the graph.
x_label : `str` or ``None``, optional
The label on the horizontal axis of the graph.
y_label : `str` or ``None``, optional
The label on the vertical axis of the graph.
x_axis_limits : (`float`, `float`) or ``None``, optional
The limits of the horizontal axis. If ``None``, the limits are set
based on the min and max values of `x_axis`.
y_axis_limits : (`float`, `float`), optional
The limits of the vertical axis. If ``None``, the limits are set based
on the min and max values of `y_axis`.
figure_size : (`int`, `int`), optional
The initial size of the rendered figure.
style : {``'coloured'``, ``'minimal'``}, optional
If ``'coloured'``, then the style of the widget will be coloured. If
``minimal``, then the style is simple using black and white colours.
"""
from menpo.visualize import GraphPlotter
print('Initializing...')
# Get number of curves to be plotted
n_curves = len(y_axis)
# Define the styling options
if style == 'coloured':
logo_style = 'danger'
widget_box_style = 'danger'
tabs_style = 'warning'
renderer_tabs_style = 'info'
save_figure_style = 'warning'
else:
logo_style = 'minimal'
widget_box_style = 'minimal'
tabs_style = 'minimal'
renderer_tabs_style = 'minimal'
save_figure_style = 'minimal'
# Parse options
if legend_entries is None:
legend_entries = ["curve {}".format(i) for i in range(n_curves)]
if title is None:
title = ''
if x_label is None:
x_label = ''
if y_label is None:
y_label = ''
x_min = np.floor(np.min(x_axis))
x_max = np.ceil(np.max(x_axis))
x_step = 0.05 * (x_max - x_min + 1)
x_slider_options = (x_min - 2 * x_step, x_max + 2 * x_step, x_step)
y_min = np.floor(np.min([np.min(i) for i in y_axis]))
y_max = np.ceil(np.max([np.max(i) for i in y_axis]))
y_step = 0.05 * (y_max - y_min + 1)
y_slider_options = (y_min - 2 * y_step, y_max + 2 * y_step, y_step)
if x_axis_limits is None:
x_axis_limits = (x_min, x_max)
if y_axis_limits is None:
y_axis_limits = (y_min, y_max)
# Get initial line and marker colours for each curve
if n_curves == 1:
line_colours = ['b']
marker_edge_colours = ['b']
else:
colours_tmp = sample_colours_from_colourmap(n_curves, 'jet')
line_colours = [list(i) for i in colours_tmp]
marker_edge_colours = [list(i) for i in colours_tmp]
# Initial options dictionaries
graph_options = {'legend_entries': legend_entries, 'x_label': x_label,
'y_label': y_label, 'title': title,
'x_axis_limits': x_axis_limits,
'y_axis_limits': y_axis_limits,
'render_lines': [True] * n_curves,
'line_colour': line_colours,
'line_style': ['-'] * n_curves,
'line_width': [2] * n_curves,
'render_markers': [True] * n_curves,
'marker_style': ['s'] * n_curves,
'marker_size': [8] * n_curves,
'marker_face_colour': ['w'] * n_curves,
'marker_edge_colour': marker_edge_colours,
'marker_edge_width': [2] * n_curves,
'render_legend': n_curves > 1, 'legend_title': '',
'legend_font_name': 'sans-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': False, 'render_axes': False,
'axes_font_name': 'sans-serif', 'axes_font_size': 10,
'axes_font_style': 'normal', 'axes_font_weight': 'normal',
'figure_size': figure_size, 'render_grid': True,
'grid_line_style': '--', 'grid_line_width': 1}
# Define render function
def render_function(name, value):
# Clear current figure, but wait until the generation of the new data
# that will be rendered
ipydisplay.clear_output(wait=True)
# plot with selected options
opts = wid.selected_values
plotter = GraphPlotter(
figure_id=save_figure_wid.renderer.figure_id, new_figure=False,
x_axis=x_axis, y_axis=y_axis, title=opts['title'],
legend_entries=opts['legend_entries'], x_label=opts['x_label'],
y_label=opts['y_label'], x_axis_limits=opts['x_axis_limits'],
y_axis_limits=opts['y_axis_limits'])
renderer = plotter.render(
render_lines=opts['render_lines'], line_colour=opts['line_colour'],
line_style=opts['line_style'], line_width=opts['line_width'],
render_markers=opts['render_markers'],
marker_style=opts['marker_style'], marker_size=opts['marker_size'],
marker_face_colour=opts['marker_face_colour'],
marker_edge_colour=opts['marker_edge_colour'],
marker_edge_width=opts['marker_edge_width'],
render_legend=opts['render_legend'],
legend_title=opts['legend_title'],
legend_font_name=opts['legend_font_name'],
legend_font_style=opts['legend_font_style'],
legend_font_size=opts['legend_font_size'],
legend_font_weight=opts['legend_font_weight'],
legend_marker_scale=opts['legend_marker_scale'],
legend_location=opts['legend_location'],
legend_bbox_to_anchor=opts['legend_bbox_to_anchor'],
legend_border_axes_pad=opts['legend_border_axes_pad'],
legend_n_columns=opts['legend_n_columns'],
legend_horizontal_spacing=opts['legend_horizontal_spacing'],
legend_vertical_spacing=opts['legend_vertical_spacing'],
legend_border=opts['legend_border'],
legend_border_padding=opts['legend_border_padding'],
legend_shadow=opts['legend_shadow'],
legend_rounded_corners=opts['legend_rounded_corners'],
render_axes=opts['render_axes'],
axes_font_name=opts['axes_font_name'],
axes_font_size=opts['axes_font_size'],
axes_font_style=opts['axes_font_style'],
axes_font_weight=opts['axes_font_weight'],
figure_size=opts['figure_size'], render_grid=opts['render_grid'],
grid_line_style=opts['grid_line_style'],
grid_line_width=opts['grid_line_width'])
# show plot
pltshow()
# Save the current figure id
save_figure_wid.renderer = renderer
# Create widgets
wid = GraphOptionsWidget(graph_options, x_slider_options, y_slider_options,
render_function=render_function,
style=widget_box_style, tabs_style=tabs_style,
renderer_tabs_style=renderer_tabs_style)
initial_renderer = MatplotlibImageViewer2d(figure_id=None, new_figure=True,
image=np.zeros((10, 10)))
save_figure_wid = SaveFigureOptionsWidget(initial_renderer,
style=save_figure_style)
# Group widgets
logo = LogoWidget(style=logo_style)
logo.margin = '0.1cm'
wid.options_tab.children = [wid.graph_related_options, wid.renderer_widget,
save_figure_wid]
wid.options_tab.set_title(0, 'Graph')
wid.options_tab.set_title(1, 'Renderer')
wid.options_tab.set_title(2, 'Export')
wid.children = [logo, wid.options_tab]
wid.align = 'start'
# Display final widget
ipydisplay.display(wid)
# Reset value to trigger initial visualization
wid.renderer_widget.options_widgets[3].render_axes_checkbox.value = True
[docs]def features_selection(style='coloured'):
r"""
Widget that allows selecting a features function and its options. The
widget supports all features from :ref:`api-feature-index` and has a
preview tab. It returns a `list` of length 1 with the selected features
function closure.
Parameters
----------
style : {``'coloured'``, ``'minimal'``}, optional
If ``'coloured'``, then the style of the widget will be coloured. If
``minimal``, then the style is simple using black and white colours.
Returns
-------
features_function : `list` of length ``1``
The function closure of the features function using `functools.partial`.
So the function can be called as: ::
features_image = features_function[0](image)
"""
# Styling options
if style == 'coloured':
logo_style = 'info'
outer_style = 'info'
inner_style = 'warning'
but_style = 'primary'
rad = 10
elif style == 'minimal':
logo_style = 'minimal'
outer_style = ''
inner_style = 'minimal'
but_style = ''
rad = 0
else:
raise ValueError('style must be either coloured or minimal')
# Create sub-widgets
logo_wid = LogoWidget(style=logo_style)
features_options_wid = FeatureOptionsWidget(style=inner_style)
features_wid = ipywidgets.HBox(children=[logo_wid, features_options_wid])
select_but = ipywidgets.Button(description='Select')
# Create final widget
wid = ipywidgets.VBox(children=[features_wid, select_but])
_format_box(wid, outer_style, True,
_map_styles_to_hex_colours(outer_style), 'solid', 1, rad, 0, 0)
logo_wid.margin = '0.3cm'
features_options_wid.margin = '0.3cm'
select_but.margin = '0.2cm'
select_but.button_style = but_style
wid.align = 'center'
# function for select button
def select_function(name):
wid.close()
output.pop(0)
output.append(features_options_wid.function)
select_but.on_click(select_function)
# Display widget
ipydisplay.display(wid)
# Initialize output with empty list. It needs to be a list so that
# it's mutable and synchronizes with frontend.
output = [features_options_wid.function]
return output
def _visualize(image, renderer, render_landmarks, image_is_masked,
masked_enabled, channels, glyph_enabled, glyph_block_size,
glyph_use_negative, sum_enabled, group, with_labels,
render_lines, line_style, line_width, line_colour,
render_markers, marker_style, marker_size,
marker_edge_width, marker_edge_colour, marker_face_colour,
render_numbering, numbers_font_name, numbers_font_size,
numbers_font_style, numbers_font_weight, numbers_font_colour,
numbers_horizontal_align, numbers_vertical_align,
legend_n_columns, legend_border_axes_pad, legend_rounded_corners,
legend_title, legend_horizontal_spacing, legend_shadow,
legend_location, legend_font_name, legend_bbox_to_anchor,
legend_border, legend_marker_scale, legend_vertical_spacing,
legend_font_weight, legend_font_size, render_legend,
legend_font_style, legend_border_padding, figure_size,
render_axes, axes_font_name, axes_font_size, axes_font_style,
axes_x_limits, axes_y_limits, axes_font_weight, interpolation,
alpha, cmap_name):
global glyph
if glyph is None:
from menpo.feature.visualize import glyph
global sum_channels
if sum_channels is None:
from menpo.feature.visualize import sum_channels
# This makes the code shorter for dealing with masked images vs non-masked
# images
mask_arguments = ({'masked': masked_enabled}
if image_is_masked else {})
# plot
if render_landmarks and not group == ' ':
# show image with landmarks
if glyph_enabled:
# image, landmarks, masked, glyph
renderer = glyph(image, vectors_block_size=glyph_block_size,
use_negative=glyph_use_negative,
channels=channels).view_landmarks(
group=group, with_labels=with_labels, without_labels=None,
figure_id=renderer.figure_id, new_figure=False,
render_lines=render_lines, line_colour=line_colour,
line_style=line_style, line_width=line_width,
render_markers=render_markers, marker_style=marker_style,
marker_size=marker_size, marker_face_colour=marker_face_colour,
marker_edge_colour=marker_edge_colour,
marker_edge_width=marker_edge_width,
render_numbering=render_numbering,
numbers_horizontal_align=numbers_horizontal_align,
numbers_vertical_align=numbers_vertical_align,
numbers_font_name=numbers_font_name,
numbers_font_size=numbers_font_size,
numbers_font_style=numbers_font_style,
numbers_font_weight=numbers_font_weight,
numbers_font_colour=numbers_font_colour,
render_legend=render_legend, legend_title=legend_title,
legend_font_name=legend_font_name,
legend_font_style=legend_font_style,
legend_font_size=legend_font_size,
legend_font_weight=legend_font_weight,
legend_marker_scale=legend_marker_scale,
legend_location=legend_location,
legend_bbox_to_anchor=legend_bbox_to_anchor,
legend_border_axes_pad=legend_border_axes_pad,
legend_n_columns=legend_n_columns,
legend_horizontal_spacing=legend_horizontal_spacing,
legend_vertical_spacing=legend_vertical_spacing,
legend_border=legend_border,
legend_border_padding=legend_border_padding,
legend_shadow=legend_shadow,
legend_rounded_corners=legend_rounded_corners,
render_axes=render_axes, axes_font_name=axes_font_name,
axes_font_size=axes_font_size, axes_font_style=axes_font_style,
axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
axes_y_limits=axes_y_limits, figure_size=figure_size,
interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
**mask_arguments)
elif sum_enabled:
# image, landmarks, masked, sum
renderer = sum_channels(image, channels=channels).view_landmarks(
group=group, with_labels=with_labels, without_labels=None,
figure_id=renderer.figure_id, new_figure=False,
render_lines=render_lines, line_colour=line_colour,
line_style=line_style, line_width=line_width,
render_markers=render_markers, marker_style=marker_style,
marker_size=marker_size, marker_face_colour=marker_face_colour,
marker_edge_colour=marker_edge_colour,
marker_edge_width=marker_edge_width,
render_numbering=render_numbering,
numbers_horizontal_align=numbers_horizontal_align,
numbers_vertical_align=numbers_vertical_align,
numbers_font_name=numbers_font_name,
numbers_font_size=numbers_font_size,
numbers_font_style=numbers_font_style,
numbers_font_weight=numbers_font_weight,
numbers_font_colour=numbers_font_colour,
render_legend=render_legend, legend_title=legend_title,
legend_font_name=legend_font_name,
legend_font_style=legend_font_style,
legend_font_size=legend_font_size,
legend_font_weight=legend_font_weight,
legend_marker_scale=legend_marker_scale,
legend_location=legend_location,
legend_bbox_to_anchor=legend_bbox_to_anchor,
legend_border_axes_pad=legend_border_axes_pad,
legend_n_columns=legend_n_columns,
legend_horizontal_spacing=legend_horizontal_spacing,
legend_vertical_spacing=legend_vertical_spacing,
legend_border=legend_border,
legend_border_padding=legend_border_padding,
legend_shadow=legend_shadow,
legend_rounded_corners=legend_rounded_corners,
render_axes=render_axes, axes_font_name=axes_font_name,
axes_font_size=axes_font_size, axes_font_style=axes_font_style,
axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
axes_y_limits=axes_y_limits, figure_size=figure_size,
interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
**mask_arguments)
else:
renderer = image.view_landmarks(
channels=channels, group=group, with_labels=with_labels,
without_labels=None, figure_id=renderer.figure_id,
new_figure=False, render_lines=render_lines,
line_colour=line_colour, line_style=line_style,
line_width=line_width, render_markers=render_markers,
marker_style=marker_style, marker_size=marker_size,
marker_face_colour=marker_face_colour,
marker_edge_colour=marker_edge_colour,
marker_edge_width=marker_edge_width,
render_numbering=render_numbering,
numbers_horizontal_align=numbers_horizontal_align,
numbers_vertical_align=numbers_vertical_align,
numbers_font_name=numbers_font_name,
numbers_font_size=numbers_font_size,
numbers_font_style=numbers_font_style,
numbers_font_weight=numbers_font_weight,
numbers_font_colour=numbers_font_colour,
render_legend=render_legend, legend_title=legend_title,
legend_font_name=legend_font_name,
legend_font_style=legend_font_style,
legend_font_size=legend_font_size,
legend_font_weight=legend_font_weight,
legend_marker_scale=legend_marker_scale,
legend_location=legend_location,
legend_bbox_to_anchor=legend_bbox_to_anchor,
legend_border_axes_pad=legend_border_axes_pad,
legend_n_columns=legend_n_columns,
legend_horizontal_spacing=legend_horizontal_spacing,
legend_vertical_spacing=legend_vertical_spacing,
legend_border=legend_border,
legend_border_padding=legend_border_padding,
legend_shadow=legend_shadow,
legend_rounded_corners=legend_rounded_corners,
render_axes=render_axes, axes_font_name=axes_font_name,
axes_font_size=axes_font_size, axes_font_style=axes_font_style,
axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
axes_y_limits=axes_y_limits, figure_size=figure_size,
interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
**mask_arguments)
else:
# either there are not any landmark groups selected or they won't
# be displayed
if glyph_enabled:
# image, not landmarks, masked, glyph
renderer = glyph(image, vectors_block_size=glyph_block_size,
use_negative=glyph_use_negative,
channels=channels).view(
render_axes=render_axes, axes_font_name=axes_font_name,
axes_font_size=axes_font_size, axes_font_style=axes_font_style,
axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
axes_y_limits=axes_y_limits, figure_size=figure_size,
interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
**mask_arguments)
elif sum_enabled:
# image, not landmarks, masked, sum
renderer = sum_channels(image, channels=channels).view(
render_axes=render_axes, axes_font_name=axes_font_name,
axes_font_size=axes_font_size, axes_font_style=axes_font_style,
axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
axes_y_limits=axes_y_limits, figure_size=figure_size,
interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
**mask_arguments)
else:
# image, not landmarks, masked, not glyph/sum
renderer = image.view(
channels=channels, render_axes=render_axes,
axes_font_name=axes_font_name, axes_font_size=axes_font_size,
axes_font_style=axes_font_style,
axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
axes_y_limits=axes_y_limits, figure_size=figure_size,
interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
**mask_arguments)
# show plot
pltshow()
return renderer
def _extract_groups_labels(image):
r"""
Function that extracts the groups and labels from an image's landmarks.
Parameters
----------
image : :map:`Image` or subclass
The input image object.
Returns
-------
group_keys : `list` of `str`
The list of landmark groups found.
labels_keys : `list` of `str`
The list of lists of each landmark group's labels.
"""
groups_keys, labels_keys = _extract_group_labels_landmarks(image.landmarks)
return groups_keys, labels_keys
def _extract_group_labels_landmarks(landmark_manager):
r"""
Function that extracts the groups and labels from a landmark manager object.
Parameters
----------
landmark_manager : :map:`LandmarkManager` or subclass
The input landmark manager object.
Returns
-------
group_keys : `list` of `str`
The list of landmark groups found.
labels_keys : `list` of `str`
The list of lists of each landmark group's labels.
"""
if landmark_manager.has_landmarks:
groups_keys = landmark_manager.keys()
labels_keys = [landmark_manager[g].keys() for g in groups_keys]
else:
groups_keys = [' ']
labels_keys = [[' ']]
return groups_keys, labels_keys