ur"""

.. _sec-display:

Display
====================================================================================================

Description
----------------------------------------------------------------------------------------------------

The function :func:`display` displays a signal and the change points provided in alternating colors.
If another set of change point indexes is provided, they are displayed with dashed vertical dashed lines.

Usage
----------------------------------------------------------------------------------------------------

Start with the usual imports and create a signal.

.. code-block:: python

    import numpy as np
    import matplotlib.pylab as plt
    import ruptures as rpt
    # creation of data
    n, dim = 500, 2  # number of samples, dimension
    n_bkps, sigma = 3, 5  # number of change points, noise standart deviation
    signal, bkps = rpt.pw_constant(n, dim, n_bkps, noise_std=sigma)
    rpt.display(signal, bkps)

If we computed another set of change points, for instance ``[110, 150, 320, 500]``, we can easily compare the two segmentations.

.. code-block:: python

    rpt.display(signal, bkps, [110, 150, 320, 500])

.. figure:: /images/example-display.png
    :scale: 50 %

    Example output of the function :func:`display`.

Code explanation
----------------------------------------------------------------------------------------------------

.. autofunction:: ruptures.show.display.display

"""

from __future__ import absolute_import
from itertools import cycle

import numpy as np

from ruptures.utils import pairwise
from itertools import izip

COLOR_CYCLE = [u"#4286f4", u"#f44174"]


class MatplotlibMissingError(RuntimeError):
    pass
try:
    import matplotlib
    import os
    # must be before importing matplotlib.pyplot or pylab!
#    if os.name == 'posix' and ("DISPLAY" not in os.environ or os.environ['DISPLAY'] == ':0.0'):
#        matplotlib.use('Agg')

    # now import other things from matplotlib
    import matplotlib.pyplot as plt
except ImportError:
    raise MatplotlibMissingError(
        u'This feature requires the optional dependency matpotlib, you can install it using `pip install matplotlib`.')

def display(signal, true_chg_pts, computed_chg_pts=None, **kwargs):
    u"""
    Display a signal and the change points provided in alternating colors. If another set of change
    point is provided, they are displayed with dashed vertical dashed lines.
    The following matplotlib subplots options is set by default, but can be changed when calling `display`):
    - "figsize": (10, 2 * n_features),  # figure size

    Args:
        signal (array): signal array, shape (n_samples,) or (n_samples, n_features).
        true_chg_pts (list): list of change point indexes.
        computed_chg_pts (list, optional): list of change point indexes.
        **kwargs : all additional keyword arguments are passed to the plt.subplots call.

    Returns:
        tuple: (figure, axarr) with a :class:`matplotlib.figure.Figure` object and an array of Axes objects.

    """

    if type(signal) != np.ndarray:
        # Try to get array from Pandas dataframe
        signal = signal.values

    if signal.ndim == 1:
        signal = signal.reshape(-1, 1)
    n_samples, n_features = signal.shape

    # let's set a sensible defaut size for the subplots
    matplotlib_options = {
        u"figsize": (10, 2 * n_features),  # figure size
    }
    # add/update the options given by the user
    # REMOVED - couldn't figure out how to make compatible with matplotlib 2.2
    # matplotlib_options.update(kwargs)

    # create plots
    fig, axarr = plt.subplots(n_features, sharex=True, **matplotlib_options)
    if n_features == 1:
        axarr = [axarr]

    for axe, sig in izip(axarr, signal.T):
        color_cycle = cycle(COLOR_CYCLE)
        # plot s
        axe.plot(xrange(n_samples), sig)

        # color each (true) regime
        bkps = [0] + sorted(true_chg_pts)
        alpha = 0.2  # transparency of the colored background

        for (start, end), col in izip(pairwise(bkps), color_cycle):
            axe.axvspan(max(0, start - 0.5),
                        end - 0.5,
                        facecolor=col, alpha=alpha)

        color = u"k"  # color of the lines indicating the computed_chg_pts
        linewidth = 3  # linewidth of the lines indicating the computed_chg_pts
        linestyle = u"--"  # linestyle of the lines indicating the computed_chg_pts
        # vertical lines to mark the computed_chg_pts
        if computed_chg_pts is not None:
            for bkp in computed_chg_pts:
                if bkp != 0 and bkp < n_samples:
                    axe.axvline(x=bkp - 0.5,
                                color=color,
                                linewidth=linewidth,
                                linestyle=linestyle)

    fig.tight_layout()

    return fig, axarr
