Repository URL to install this package:
Version:
5.0.0 ▾
|
# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
"""A simple inspector overlay for plots
This module provides the SimpleInspectorOverlay for displaying
information gathered from an inspector tool in a TextGrid. By default
it is configured to work with a SimpleInspectorTool.
The module also provides some helper factory functions for creating text
formatters for dictionary values.
"""
from numpy import array
from traits.api import Any, List, Callable, Enum, Bool
from .text_grid_overlay import TextGridOverlay
def basic_formatter(key, decimals):
"""Create a basic '<key>: <value>' formatting function
This factory creates a function that formats a specified key and with a
numerical value from a dictionary into a string.
Parameters
----------
key
The dictionary key to format.
decimals
The number of decimal places to show.
Returns
-------
format
A factory function that takes a dictionary and returns a string.
"""
format_string = "%s: %%(%s).%df" % (key, key, decimals)
def format(**kwargs):
return format_string % kwargs
return format
def datetime_formatter(key, time_format="%Y/%m/%d %H:%M:%S"):
"""Create a datetime formatting function
This factory creates a function that formats a specified key and with a
timestamp value from a dictionary into a string.
Parameters
----------
key
The dictionary key to format. The corresponding value should be a
timestamp.
time_format
A format string suitable for strftime().
Returns
-------
format
A factory function that takes a dictionary and returns a string.
"""
import datetime
def format(**kwargs):
dt = datetime.datetime.fromtimestamp(kwargs[key])
return key + ": " + dt.strftime(time_format)
return format
def time_formatter(key):
"""Create a time formatting function
This factory creates a function that formats a specified key and with a
timestamp value from a dictionary into a 'HH:MM:SS' format string.
Parameters
----------
key
The dictionary key to format. The corresponding value should be a
timestamp.
Returns
-------
format
A factory function that takes a dictionary and returns a string.
"""
return datetime_formatter(key, time_format="%H:%M:%S")
def date_formatter(key):
"""Create a date formatting function
This factory creates a function that formats a specified key and with a
timestamp value from a dictionary into a 'yyyy/mm/dd' format string.
Parameters
----------
key
The dictionary key to format. The corresponding value should be a
timestamp.
Returns
-------
format
A factory function that takes a dictionary and returns a string.
"""
return datetime_formatter(key, time_format="%Y/%m/%d")
class SimpleInspectorOverlay(TextGridOverlay):
"""Simple inspector overlay for plots
This is a simple overlay that listens for new_value events on a
SimpleInspectorTool and displays formatted values in a grid.
By default this displays the 'x' and 'y' values provided by the
SimpleInspectorTool, but instances can provide a field_formatters
trait which is a list of lists of callables which extract values
from a dictionary and formats them. Each callable corresponds to a
cell in the underlying TextGrid component.
Although by default this works with the SimpleInspectorTool, with
appropriate field_formatters this class can be used with any inspector
tool that follows the same API.
"""
# XXX We should probably refactor this into a BaseInspectorOverlay
# which handles the visibility and basic event handling, and smaller
# version of this class which handles inserting values into a text grid
# the inspector that I am listening to. This should have a new_value
# event and a visible trait for me to listen to.
inspector = Any
# fields to display
field_formatters = List(List(Callable))
# Anchor the text to the mouse? (If False, then the text is in one of the
# corners.) Use the **align** trait to determine which corner.
tooltip_mode = Bool(False)
# The default state of the overlay is visible.
visible = True
# Whether the overlay should auto-hide and auto-show based on the
# tool's location, or whether it should be forced to be hidden or visible.
visibility = Enum("auto", True, False)
#########################################################################
# Traits Handlers
#########################################################################
def _field_formatters_default(self):
return [[basic_formatter("x", 2)], [basic_formatter("y", 2)]]
def _new_value_updated(self, event):
new_value_event = event.new
if new_value_event is None:
self.text_grid = array()
if self.visibility == "auto":
self.visibility = False
elif self.visibility == "auto":
self.visible = True
if self.tooltip_mode:
self.alternate_position = self.inspector.last_mouse_position
d = new_value_event
text = []
self.text_grid.string_array = array(
[
[formatter(**d) for formatter in row]
for row in self.field_formatters
]
)
self.text_grid.request_redraw()
def _visible_changed(self):
if self.component:
self.request_redraw()
def _inspector_changed(self, old, new):
if old:
old.observe(self._new_value_updated, "new_value", remove=True)
old.observe(self._tool_visible_changed, "visible", remove=True)
if new:
new.observe(self._new_value_updated, "new_value")
new.observe(self._tool_visible_changed, "visible")
self._tool_visible_changed()
def _tool_visible_changed(self, event=None):
self.visibility = self.inspector.visible
if self.visibility != "auto":
self.visible = self.visibility