# ============================================================================
#
# Copyright (C) 2007-2016 Conceptive Engineering bvba.
# www.conceptive.be / info@conceptive.be
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Conceptive Engineering nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# ============================================================================
from camelot.container import Container
[docs]class AxesMethod(object):
"""Helper class to substitute a method on an Axes object and
record its calls"""
def __init__(self, method_name, commands):
"""
:param method_name: the name of the method for which this object is a substitute
:param commands: a list in which to store invocations of the method
"""
self._method_name = method_name
self._commands = commands
def __call__(self, *args, **kwargs):
"""record a call the the substitute method into the commands list"""
self._commands.append( (self._method_name, args, kwargs) )
[docs]class AxesContainer( Container ):
"""A container that is able to generate a plot on a matplotlib axes. Methods
can be called on this class as if it were a matplotlib Axes class. All method
calls will be recorded. Of course the methods won't return matplotlib objects.
The set_auto_legend method can be used to turn legends on without the need for
matplotlib objects.
"""
def __init__(self):
"""
:param legend: True or False, to put a legend on the chart
"""
super(AxesContainer, self).__init__()
# store all the method calls that need to be called on a
# matplotlib axes object in a list
self._commands = list()
self._auto_legend = False
def __getattr__(self, attribute_name):
"""Suppose the caller wants to call a function on a matplotlib
axes object"""
return AxesMethod( attribute_name, self._commands )
[docs] def set_auto_legend(self, auto_legend):
"""Specify if the container should try to put a legend on the
plot.
:param auto_legend: True or False
"""
self._auto_legend = auto_legend
[docs] def plot_on_axes(self, ax):
"""Replay the list of stored commands to the real Axes object"""
for name, args, kwargs in self._commands:
getattr(ax, name)(*args, **kwargs)
if self._auto_legend:
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)
[docs]class PlotContainer( AxesContainer ):
# this line drives pylint crazy because it need axes to be imported
#__doc__ = axes.Axes.plot.__doc__
def __init__(self, *args, **kwargs):
""":param *args, **kwargs: the arguments to be passed to the matplotlib plot command"""
super(PlotContainer, self).__init__()
self.plot( *args, **kwargs )
[docs]class BarContainer( AxesContainer ):
# this line drives pylint crazy because it need axes to be imported
#__doc__ = axes.Axes.bar.__doc__
def __init__(self, *args, **kwargs):
""":param *args, **kwargs: the arguments to be passed to the matplotlib bar command"""
super(BarContainer, self).__init__()
self.bar( *args, **kwargs )