Exemple #1
0
def camera(**kwargs):
    """
    Sets the camera settings.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'camera_aspect', 'elevation', 'azimuth'}**
        Keywords arguments such as ``{'camera_aspect': unicode
        (Matplotlib axes aspect), 'elevation' : numeric, 'azimuth' : numeric}``

    Returns
    -------
    Axes
        Current axes.
    """

    settings = Structure(
        **{'camera_aspect': 'equal',
           'elevation': None,
           'azimuth': None})
    settings.update(kwargs)

    axes = matplotlib.pyplot.gca()
    if settings.camera_aspect == 'equal':
        equal_axes3d(axes)

    axes.view_init(elev=settings.elevation, azim=settings.azimuth)

    return axes
Exemple #2
0
def canvas(**kwargs):
    """
    Sets the figure size.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'figure_size', }**
        Keywords arguments such as ``{'figure_size': array_like
        (width, height), }``

    Returns
    -------
    Figure
        Current figure.
    """

    settings = Structure(
        **{'figure_size': DEFAULT_FIGURE_SIZE})
    settings.update(kwargs)

    figure = matplotlib.pyplot.gcf()
    if figure is None:
        figure = matplotlib.pyplot.figure(figsize=settings.figure_size)
    else:
        figure.set_size_inches(settings.figure_size)

    return figure
Exemple #3
0
def camera(**kwargs):
    """
    Sets the camera settings.

    Other Parameters
    ----------------
    azimuth : numeric, optional
        Camera azimuth.
    camera_aspect : unicode, optional
        Matplotlib axes aspect. Default is *equal*.
    elevation : numeric, optional
        Camera elevation.

    Returns
    -------
    Axes
        Current axes.
    """

    axes = kwargs.get('axes', plt.gca())

    settings = Structure(**{
        'camera_aspect': 'equal',
        'elevation': None,
        'azimuth': None
    })
    settings.update(kwargs)

    if settings.camera_aspect == 'equal':
        uniform_axes3d(axes)

    axes.view_init(elev=settings.elevation, azim=settings.azimuth)

    return axes
Exemple #4
0
def display(**kwargs):
    """
    Sets the figure display.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'standalone', 'filename'}**
        Keywords arguments such as ``{'standalone': bool (figure is shown),
        'filename': unicode (figure is saved as `filename`)}``

    Returns
    -------
    bool
        Definition success.
    """

    settings = Structure(
        **{'standalone': True,
           'filename': None})
    settings.update(kwargs)

    if settings.standalone:
        if settings.filename is not None:
            pylab.savefig(**kwargs)
        else:
            pylab.show()
        pylab.close()

    return True
Exemple #5
0
def colour_cycle(**kwargs: Any) -> itertools.cycle:
    """
    Return a colour cycle iterator using given colour map.

    Other Parameters
    ----------------
    colour_cycle_map
        Matplotlib colourmap name.
    colour_cycle_count
        Colours count to pick in the colourmap.

    Returns
    -------
    :class:`itertools.cycle`
        Colour cycle iterator.
    """

    settings = Structure(
        **{
            "colour_cycle_map": CONSTANTS_COLOUR_STYLE.colour.map,
            "colour_cycle_count": len(CONSTANTS_COLOUR_STYLE.colour.cycle),
        })
    settings.update(kwargs)

    samples = np.linspace(0, 1, settings.colour_cycle_count)
    if isinstance(settings.colour_cycle_map, LinearSegmentedColormap):
        cycle = settings.colour_cycle_map(samples)
    else:
        cycle = getattr(plt.cm, settings.colour_cycle_map)(samples)

    return itertools.cycle(cycle)
    def test_Structure(self):
        """Test :class:`colour.utilities.data_structures.Structure` class."""

        structure = Structure(John="Doe", Jane="Doe")
        self.assertIn("John", structure)
        self.assertTrue(hasattr(structure, "John"))

        setattr(structure, "John", "Nemo")
        self.assertEqual(structure["John"], "Nemo")

        structure["John"] = "Vador"
        self.assertEqual(structure["John"], "Vador")

        del structure["John"]
        self.assertNotIn("John", structure)
        self.assertFalse(hasattr(structure, "John"))

        structure.John = "Doe"
        self.assertIn("John", structure)
        self.assertTrue(hasattr(structure, "John"))

        del structure.John
        self.assertNotIn("John", structure)
        self.assertFalse(hasattr(structure, "John"))

        structure = Structure(John=None, Jane=None)
        self.assertIsNone(structure.John)
        self.assertIsNone(structure["John"])

        structure.update(**{"John": "Doe", "Jane": "Doe"})
        self.assertEqual(structure.John, "Doe")
        self.assertEqual(structure["John"], "Doe")
Exemple #7
0
def camera(**kwargs: Union[KwargsCamera, Any]) -> Tuple[plt.Figure, plt.Axes]:
    """
    Set the camera settings.

    Other Parameters
    ----------------
    kwargs
        {:func:`colour.plotting.common.KwargsCamera`},
        See the documentation of the previously listed class.

    Returns
    -------
    :class:`tuple`
        Current figure and axes.
    """

    figure = cast(plt.Figure, kwargs.get("figure", plt.gcf()))
    axes = cast(plt.Axes, kwargs.get("axes", plt.gca()))

    settings = Structure(**{
        "camera_aspect": "equal",
        "elevation": None,
        "azimuth": None
    })
    settings.update(kwargs)

    if settings.camera_aspect == "equal":
        uniform_axes3d(axes=axes)

    axes.view_init(elev=settings.elevation, azim=settings.azimuth)

    return figure, axes
Exemple #8
0
def display(**kwargs):
    """
    Sets the figure display.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'standalone', 'filename'}**
        Keywords arguments such as ``{'standalone': bool (figure is shown),
        'filename': unicode (figure is saved as `filename`)}``

    Returns
    -------
    Figure
        Current figure or None.
    """

    settings = Structure(
        **{'standalone': True,
           'filename': None})
    settings.update(kwargs)

    figure = matplotlib.pyplot.gcf()
    if settings.standalone:
        if settings.filename is not None:
            pylab.savefig(**kwargs)
        else:
            pylab.show()
        pylab.close()

        return None
    else:
        return figure
Exemple #9
0
def colour_cycle(**kwargs):
    """
    Returns a colour cycle iterator using given colour map.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'colour_cycle_map', 'colour_cycle_count'}**
        Keywords arguments such as ``{'colour_cycle_map': unicode
        (Matplotlib colormap name), 'colour_cycle_count': int}``

    Returns
    -------
    cycle
        Colour cycle iterator.
    """

    settings = Structure(
        **{'colour_cycle_map': 'hsv',
           'colour_cycle_count': len(DEFAULT_COLOUR_CYCLE)})
    settings.update(kwargs)

    if settings.colour_cycle_map is None:
        cycle = DEFAULT_COLOUR_CYCLE
    else:
        cycle = getattr(matplotlib.pyplot.cm,
                        settings.colour_cycle_map)(
            np.linspace(0, 1, settings.colour_cycle_count))

    return itertools.cycle(cycle)
Exemple #10
0
    def test_Structure(self):
        """
        Tests :class:`colour.utilities.data_structures.Structure` class.
        """

        structure = Structure(John='Doe', Jane='Doe')
        self.assertIn('John', structure)
        self.assertTrue(hasattr(structure, 'John'))
        setattr(structure, 'John', 'Nemo')
        self.assertEqual(structure['John'], 'Nemo')
        structure['John'] = 'Vador'
        self.assertEqual(structure['John'], 'Vador')
        del structure['John']
        self.assertNotIn('John', structure)
        self.assertFalse(hasattr(structure, 'John'))
        structure.John = 'Doe'
        self.assertIn('John', structure)
        self.assertTrue(hasattr(structure, 'John'))
        del structure.John
        self.assertNotIn('John', structure)
        self.assertFalse(hasattr(structure, 'John'))

        structure = Structure(John=None, Jane=None)
        self.assertIsNone(structure.John)
        self.assertIsNone(structure['John'])
        structure.update(**{'John': 'Doe', 'Jane': 'Doe'})
        self.assertEqual(structure.John, 'Doe')
        self.assertEqual(structure['John'], 'Doe')
Exemple #11
0
def colour_cycle(**kwargs):
    """
    Returns a colour cycle iterator using given colour map.

   Parameters
    ----------
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    cycle
        Colour cycle iterator.
    """

    settings = Structure(
        **{'colour_cycle_map': 'hsv',
           'colour_cycle_count': len(DEFAULT_COLOUR_CYCLE)})
    settings.update(kwargs)

    if settings.colour_cycle_map is None:
        cycle = DEFAULT_COLOUR_CYCLE
    else:
        cycle = getattr(matplotlib.pyplot.cm,
                        settings.colour_cycle_map)(
            np.linspace(0, 1, settings.colour_cycle_count))

    return itertools.cycle(cycle)
    def test_Structure(self):
        """
        Tests :class:`colour.utilities.data_structures.Structure` class.
        """

        structure = Structure(John='Doe', Jane='Doe')
        self.assertIn('John', structure)
        self.assertTrue(hasattr(structure, 'John'))

        setattr(structure, 'John', 'Nemo')
        self.assertEqual(structure['John'], 'Nemo')

        structure['John'] = 'Vador'
        self.assertEqual(structure['John'], 'Vador')

        del structure['John']
        self.assertNotIn('John', structure)
        self.assertFalse(hasattr(structure, 'John'))

        structure.John = 'Doe'
        self.assertIn('John', structure)
        self.assertTrue(hasattr(structure, 'John'))

        del structure.John
        self.assertNotIn('John', structure)
        self.assertFalse(hasattr(structure, 'John'))

        structure = Structure(John=None, Jane=None)
        self.assertIsNone(structure.John)
        self.assertIsNone(structure['John'])

        structure.update(**{'John': 'Doe', 'Jane': 'Doe'})
        self.assertEqual(structure.John, 'Doe')
        self.assertEqual(structure['John'], 'Doe')
Exemple #13
0
def display(**kwargs):
    """
    Sets the figure display.

    Parameters
    ----------
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.
    """

    settings = Structure(
        **{'standalone': True,
           'filename': None})
    settings.update(kwargs)

    if settings.standalone:
        if settings.filename is not None:
            pylab.savefig(**kwargs)
        else:
            pylab.show()
        pylab.close()

    return True
Exemple #14
0
def colour_cycle(**kwargs):
    """
    Returns a colour cycle iterator using given colour map.

    Other Parameters
    ----------------
    colour_cycle_map : unicode or LinearSegmentedColormap, optional
        Matplotlib colourmap name.
    colour_cycle_count : int, optional
        Colours count to pick in the colourmap.

    Returns
    -------
    cycle
        Colour cycle iterator.
    """

    settings = Structure(
        **{
            'colour_cycle_map': COLOUR_STYLE_CONSTANTS.colour.map,
            'colour_cycle_count': len(COLOUR_STYLE_CONSTANTS.colour.cycle)
        })
    settings.update(kwargs)

    samples = np.linspace(0, 1, settings.colour_cycle_count)
    if isinstance(settings.colour_cycle_map, LinearSegmentedColormap):
        cycle = settings.colour_cycle_map(samples)
    else:
        cycle = getattr(plt.cm, settings.colour_cycle_map)(samples)

    return itertools.cycle(cycle)
Exemple #15
0
def colour_cycle(**kwargs):
    """
    Returns a colour cycle iterator using given colour map.

    Other Parameters
    ----------------
    colour_cycle_map : unicode or LinearSegmentedColormap, optional
        Matplotlib colourmap name.
    colour_cycle_count : int, optional
        Colours count to pick in the colourmap.

    Returns
    -------
    cycle
        Colour cycle iterator.
    """

    settings = Structure(
        **{
            'colour_cycle_map': COLOUR_STYLE_CONSTANTS.colour.map,
            'colour_cycle_count': len(COLOUR_STYLE_CONSTANTS.colour.cycle)
        })
    settings.update(kwargs)

    samples = np.linspace(0, 1, settings.colour_cycle_count)
    if isinstance(settings.colour_cycle_map, LinearSegmentedColormap):
        cycle = settings.colour_cycle_map(samples)
    else:
        cycle = getattr(plt.cm, settings.colour_cycle_map)(samples)

    return itertools.cycle(cycle)
Exemple #16
0
def display(**kwargs):
    """
    Sets the figure display.

    Other Parameters
    ----------------
    standalone : bool, optional
        Whether to show the figure.
    filename : unicode, optional
        Figure will be saved using given `filename` argument.

    Returns
    -------
    Figure
        Current figure or None.
    """

    settings = Structure(**{'standalone': True, 'filename': None})
    settings.update(kwargs)

    figure = matplotlib.pyplot.gcf()
    if settings.standalone:
        if settings.filename is not None:
            pylab.savefig(**kwargs)
        else:
            pylab.show()
        pylab.close()

        return None
    else:
        return figure
Exemple #17
0
def display(**kwargs):
    """
    Sets the figure display.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'standalone', 'filename'}**
        Keywords arguments such as ``{'standalone': bool (figure is shown),
        'filename': unicode (figure is saved as `filename`)}``

    Returns
    -------
    bool
        Definition success.
    """

    settings = Structure(**{'standalone': True, 'filename': None})
    settings.update(kwargs)

    if settings.standalone:
        if settings.filename is not None:
            pylab.savefig(**kwargs)
        else:
            pylab.show()
        pylab.close()

    return True
Exemple #18
0
def canvas(**kwargs):
    """
    Sets the figure size and aspect.

    Parameters
    ----------
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure.
    """

    settings = Structure(
        **{'figure_size': DEFAULT_FIGURE_SIZE})
    settings.update(kwargs)

    figure = matplotlib.pyplot.gcf()
    if figure is None:
        figure = matplotlib.pyplot.figure(figsize=settings.figure_size)
    else:
        figure.set_size_inches(settings.figure_size)

    return figure
Exemple #19
0
def canvas(**kwargs):
    """
    Sets the figure size.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'figure_size', }**
        Keywords arguments such as ``{'figure_size': array_like
        (width, height), }``

    Returns
    -------
    Figure
        Current figure.
    """

    settings = Structure(**{'figure_size': DEFAULT_FIGURE_SIZE})
    settings.update(kwargs)

    figure = matplotlib.pyplot.gcf()
    if figure is None:
        figure = matplotlib.pyplot.figure(figsize=settings.figure_size)
    else:
        figure.set_size_inches(settings.figure_size)

    return figure
Exemple #20
0
def camera(**kwargs):
    """
    Sets the camera settings.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'camera_aspect', 'elevation', 'azimuth'}**
        Keywords arguments such as ``{'camera_aspect': unicode
        (Matplotlib axes aspect), 'elevation' : numeric, 'azimuth' : numeric}``

    Returns
    -------
    bool
        Definition success.
    """

    settings = Structure(**{
        'camera_aspect': 'equal',
        'elevation': None,
        'azimuth': None
    })
    settings.update(kwargs)

    axes = matplotlib.pyplot.gca()
    if settings.camera_aspect == 'equal':
        equal_axes3d(axes)

    axes.view_init(elev=settings.elevation, azim=settings.azimuth)

    return True
Exemple #21
0
def colour_cycle(**kwargs):
    """
    Returns a colour cycle iterator using given colour map.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'colour_cycle_map', 'colour_cycle_count'}**
        Keywords arguments such as ``{'colour_cycle_map': unicode
        (Matplotlib colormap name), 'colour_cycle_count': int}``

    Returns
    -------
    cycle
        Colour cycle iterator.
    """

    settings = Structure(**{
        'colour_cycle_map': 'hsv',
        'colour_cycle_count': len(DEFAULT_COLOUR_CYCLE)
    })
    settings.update(kwargs)

    if settings.colour_cycle_map is None:
        cycle = DEFAULT_COLOUR_CYCLE
    else:
        cycle = getattr(matplotlib.pyplot.cm,
                        settings.colour_cycle_map)(np.linspace(
                            0, 1, settings.colour_cycle_count))

    return itertools.cycle(cycle)
Exemple #22
0
def display(**kwargs):
    """
    Sets the figure display.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'standalone', 'filename'}**
        Keywords arguments such as ``{'standalone': bool (figure is shown),
        'filename': unicode (figure is saved as `filename`)}``

    Returns
    -------
    Figure
        Current figure or None.
    """

    settings = Structure(**{'standalone': True, 'filename': None})
    settings.update(kwargs)

    figure = matplotlib.pyplot.gcf()
    if settings.standalone:
        if settings.filename is not None:
            pylab.savefig(**kwargs)
        else:
            pylab.show()
        pylab.close()

        return None
    else:
        return figure
Exemple #23
0
def camera(**kwargs):
    """
    Sets the camera settings.

    Other Parameters
    ----------------
    azimuth : numeric, optional
        Camera azimuth.
    camera_aspect : unicode, optional
        Matplotlib axes aspect. Default is *equal*.
    elevation : numeric, optional
        Camera elevation.

    Returns
    -------
    Axes
        Current axes.
    """

    axes = kwargs.get('axes', plt.gca())

    settings = Structure(**{
        'camera_aspect': 'equal',
        'elevation': None,
        'azimuth': None
    })
    settings.update(kwargs)

    if settings.camera_aspect == 'equal':
        uniform_axes3d(axes)

    axes.view_init(elev=settings.elevation, azim=settings.azimuth)

    return axes
Exemple #24
0
def canvas(**kwargs):
    """
    Sets the figure size.

    Other Parameters
    ----------------
    figure_size : array_like, optional
        Array defining figure `width` and `height` such as
        `figure_size = (width, height)`.

    Returns
    -------
    Figure
        Current figure.
    """

    settings = Structure(**{'figure_size': DEFAULT_FIGURE_SIZE})
    settings.update(kwargs)

    figure = matplotlib.pyplot.gcf()
    if figure is None:
        figure = matplotlib.pyplot.figure(figsize=settings.figure_size)
    else:
        figure.set_size_inches(settings.figure_size)

    return figure
Exemple #25
0
def colour_cycle(**kwargs):
    """
    Returns a colour cycle iterator using given colour map.

    Other Parameters
    ----------------
    colour_cycle_map : unicode, optional
        Matplotlib colourmap name.
    colour_cycle_count : int, optional
        Colours count to pick in the colourmap.

    Returns
    -------
    cycle
        Colour cycle iterator.
    """

    settings = Structure(**{
        'colour_cycle_map': 'hsv',
        'colour_cycle_count': len(DEFAULT_COLOUR_CYCLE)
    })
    settings.update(kwargs)

    if settings.colour_cycle_map is None:
        cycle = DEFAULT_COLOUR_CYCLE
    else:
        cycle = getattr(matplotlib.pyplot.cm,
                        settings.colour_cycle_map)(np.linspace(
                            0, 1, settings.colour_cycle_count))

    return itertools.cycle(cycle)
Exemple #26
0
def boundaries(**kwargs):
    """
    Sets the plot boundaries.

    Other Parameters
    ----------------
    bounding_box : array_like, optional
        Array defining current axes limits such
        `bounding_box = (x min, x max, y min, y max)`.
    x_tighten : bool, optional
        Whether to tighten the *X* axis limit. Default is `False`.
    y_tighten : bool, optional
        Whether to tighten the *Y* axis limit. Default is `False`.
    limits : array_like, optional
        Array defining current axes limits such as
        `limits = (x limit min, x limit max, y limit min, y limit max)`.
        `limits` argument values are added to the `margins` argument values to
        define the final bounding box for the current axes.
    margins : array_like, optional
        Array defining current axes margins such as
        `margins = (x margin min, x margin max, y margin min, y margin max)`.
        `margins` argument values are added to the `limits` argument values to
        define the final bounding box for the current axes.

    Returns
    -------
    Axes
        Current axes.
    """

    settings = Structure(
        **{
            'bounding_box': None,
            'x_tighten': False,
            'y_tighten': False,
            'limits': (0, 1, 0, 1),
            'margins': (0, 0, 0, 0)
        })
    settings.update(kwargs)

    axes = matplotlib.pyplot.gca()
    if settings.bounding_box is None:
        x_limit_min, x_limit_max, y_limit_min, y_limit_max = (settings.limits)
        x_margin_min, x_margin_max, y_margin_min, y_margin_max = (
            settings.margins)
        if settings.x_tighten:
            pylab.xlim(x_limit_min + x_margin_min, x_limit_max + x_margin_max)
        if settings.y_tighten:
            pylab.ylim(y_limit_min + y_margin_min, y_limit_max + y_margin_max)
    else:
        pylab.xlim(settings.bounding_box[0], settings.bounding_box[1])
        pylab.ylim(settings.bounding_box[2], settings.bounding_box[3])

    return axes
Exemple #27
0
def boundaries(**kwargs):
    """
    Sets the plot boundaries.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'bounding_box', 'x_tighten', 'y_tighten', 'limits', 'margins'}**
        Keywords arguments such as ``{'bounding_box': array_like
        (x min, x max, y min, y max), 'x_tighten': bool, 'y_tighten': bool,
        'limits': array_like (x min, x max, y min, y max), 'limits': array_like
        (x min, x max, y min, y max)}``

    Returns
    -------
    Axes
        Current axes.
    """

    settings = Structure(
        **{
            'bounding_box': None,
            'x_tighten': False,
            'y_tighten': False,
            'limits': (0, 1, 0, 1),
            'margins': (0, 0, 0, 0)
        })
    settings.update(kwargs)

    axes = matplotlib.pyplot.gca()
    if settings.bounding_box is None:
        x_limit_min, x_limit_max, y_limit_min, y_limit_max = (settings.limits)
        x_margin_min, x_margin_max, y_margin_min, y_margin_max = (
            settings.margins)
        if settings.x_tighten:
            pylab.xlim(x_limit_min + x_margin_min, x_limit_max + x_margin_max)
        if settings.y_tighten:
            pylab.ylim(y_limit_min + y_margin_min, y_limit_max + y_margin_max)
    else:
        pylab.xlim(settings.bounding_box[0], settings.bounding_box[1])
        pylab.ylim(settings.bounding_box[2], settings.bounding_box[3])

    return axes
Exemple #28
0
def boundaries(**kwargs):
    """
    Sets the plot boundaries.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'bounding_box', 'x_tighten', 'y_tighten', 'limits', 'margins'}**
        Keywords arguments such as ``{'bounding_box': array_like
        (x min, x max, y min, y max), 'x_tighten': bool, 'y_tighten': bool,
        'limits': array_like (x min, x max, y min, y max), 'limits': array_like
        (x min, x max, y min, y max)}``

    Returns
    -------
    Axes
        Current axes.
    """

    settings = Structure(
        **{'bounding_box': None,
           'x_tighten': False,
           'y_tighten': False,
           'limits': (0, 1, 0, 1),
           'margins': (0, 0, 0, 0)})
    settings.update(kwargs)

    axes = matplotlib.pyplot.gca()
    if settings.bounding_box is None:
        x_limit_min, x_limit_max, y_limit_min, y_limit_max = (
            settings.limits)
        x_margin_min, x_margin_max, y_margin_min, y_margin_max = (
            settings.margins)
        if settings.x_tighten:
            pylab.xlim(x_limit_min + x_margin_min, x_limit_max + x_margin_max)
        if settings.y_tighten:
            pylab.ylim(y_limit_min + y_margin_min, y_limit_max + y_margin_max)
    else:
        pylab.xlim(settings.bounding_box[0], settings.bounding_box[1])
        pylab.ylim(settings.bounding_box[2], settings.bounding_box[3])

    return axes
Exemple #29
0
def camera(**kwargs):
    """
    Sets the camera settings.

    Other Parameters
    ----------------
    figure : Figure, optional
        Figure to apply the render elements onto.
    axes : Axes, optional
        Axes to apply the render elements onto.
    azimuth : numeric, optional
        Camera azimuth.
    camera_aspect : unicode, optional
        Matplotlib axes aspect. Default is *equal*.
    elevation : numeric, optional
        Camera elevation.

    Returns
    -------
    tuple
        Current figure and axes.
    """

    figure = kwargs.get('figure', plt.gcf())
    axes = kwargs.get('axes', plt.gca())

    settings = Structure(**{
        'camera_aspect': 'equal',
        'elevation': None,
        'azimuth': None
    })
    settings.update(kwargs)

    if settings.camera_aspect == 'equal':
        uniform_axes3d(axes=axes)

    axes.view_init(elev=settings.elevation, azim=settings.azimuth)

    return figure, axes
Exemple #30
0
def boundaries(**kwargs):
    """
    Sets the plot boundaries.

    Parameters
    ----------
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.
    """

    settings = Structure(
        **{'bounding_box': None,
           'x_tighten': False,
           'y_tighten': False,
           'limits': [0, 1, 0, 1],
           'margins': [0, 0, 0, 0]})
    settings.update(kwargs)

    if settings.bounding_box is None:
        x_limit_min, x_limit_max, y_limit_min, y_limit_max = (
            settings.limits)
        x_margin_min, x_margin_max, y_margin_min, y_margin_max = (
            settings.margins)
        if settings.x_tighten:
            pylab.xlim(x_limit_min + x_margin_min, x_limit_max + x_margin_max)
        if settings.y_tighten:
            pylab.ylim(y_limit_min + y_margin_min, y_limit_max + y_margin_max)
    else:
        pylab.xlim(settings.bounding_box[0], settings.bounding_box[1])
        pylab.ylim(settings.bounding_box[2], settings.bounding_box[3])

    return True
Exemple #31
0
__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = '*****@*****.**'
__status__ = 'Production'

__all__ = [
    'JZAZBZ_CONSTANTS', 'JZAZBZ_XYZ_TO_LMS_MATRIX', 'JZAZBZ_LMS_TO_XYZ_MATRIX',
    'JZAZBZ_LMS_P_TO_IZAZBZ_MATRIX', 'JZAZBZ_IZAZBZ_TO_LMS_P_MATRIX',
    'XYZ_to_JzAzBz', 'JzAzBz_to_XYZ'
]

JZAZBZ_CONSTANTS = Structure(b=1.15,
                             g=0.66,
                             d=-0.56,
                             d_0=1.6295499532821566 * 10**-11)
JZAZBZ_CONSTANTS.update(ST2084_CONSTANTS)
JZAZBZ_CONSTANTS.m_2 = 1.7 * 2523 / 2**5
"""
Constants for :math:`J_zA_zB_z` colourspace and its variant of the perceptual
quantizer (PQ) from Dolby Laboratories.

Notes
-----
-   The :math:`m2` constant, i.e. the power factor has been re-optimized during
    the development of the :math:`J_zA_zB_z` colourspace.

JZAZBZ_CONSTANTS : Structure
"""

JZAZBZ_XYZ_TO_LMS_MATRIX = np.array([
    [0.41478972, 0.579999, 0.0146480],
Exemple #32
0
def render(**kwargs):
    """
    Renders the current figure while adjusting various settings such as the
    bounding box, the title or background transparency.

    Other Parameters
    ----------------
    figure : Figure, optional
        Figure to apply the render elements onto.
    axes : Axes, optional
        Axes to apply the render elements onto.
    filename : unicode, optional
        Figure will be saved using given ``filename`` argument.
    standalone : bool, optional
        Whether to show the figure and call :func:`plt.show` definition.
    aspect : unicode, optional
        Matplotlib axes aspect.
    axes_visible : bool, optional
        Whether the axes are visible. Default is *True*.
    bounding_box : array_like, optional
        Array defining current axes limits such
        `bounding_box = (x min, x max, y min, y max)`.
    tight_layout : bool, optional
        Whether to invoke the :func:`plt.tight_layout` definition.
    legend : bool, optional
        Whether to display the legend. Default is *False*.
    legend_columns : int, optional
        Number of columns in the legend. Default is *1*.
    transparent_background : bool, optional
        Whether to turn off the background patch. Default is *False*.
    title : unicode, optional
        Figure title.
    wrap_title : unicode, optional
        Whether to wrap the figure title, the default is to wrap at a number
        of characters equal to the width of the figure multiplied by 10.
    x_label : unicode, optional
        *X* axis label.
    y_label : unicode, optional
        *Y* axis label.
    x_ticker : bool, optional
        Whether to display the *X* axis ticker. Default is *True*.
    y_ticker : bool, optional
        Whether to display the *Y* axis ticker. Default is *True*.

    Returns
    -------
    tuple
        Current figure and axes.
    """

    figure = kwargs.get('figure')
    if figure is None:
        figure = plt.gcf()

    axes = kwargs.get('axes')
    if axes is None:
        axes = plt.gca()

    settings = Structure(
        **{
            'filename': None,
            'standalone': True,
            'aspect': None,
            'axes_visible': True,
            'bounding_box': None,
            'tight_layout': True,
            'legend': False,
            'legend_columns': 1,
            'transparent_background': True,
            'title': None,
            'wrap_title': True,
            'x_label': None,
            'y_label': None,
            'x_ticker': True,
            'y_ticker': True,
        })
    settings.update(kwargs)

    if settings.aspect:
        axes.set_aspect(settings.aspect)
    if not settings.axes_visible:
        axes.set_axis_off()
    if settings.bounding_box:
        axes.set_xlim(settings.bounding_box[0], settings.bounding_box[1])
        axes.set_ylim(settings.bounding_box[2], settings.bounding_box[3])

    if settings.title:
        title = settings.title
        if settings.wrap_title:
            title = wrap_label(settings.title,
                               int(plt.rcParams['figure.figsize'][0] * 10))
        axes.set_title(title)
    if settings.x_label:
        axes.set_xlabel(settings.x_label)
    if settings.y_label:
        axes.set_ylabel(settings.y_label)
    if not settings.x_ticker:
        axes.set_xticks([])
    if not settings.y_ticker:
        axes.set_yticks([])
    if settings.legend:
        axes.legend(ncol=settings.legend_columns)

    if settings.tight_layout:
        figure.tight_layout()

    if settings.transparent_background:
        figure.patch.set_alpha(0)
    if settings.standalone:
        if settings.filename is not None:
            figure.savefig(settings.filename)
        else:
            plt.show()

    return figure, axes
Exemple #33
0
def RGB_scatter_plot(RGB,
                     colourspace,
                     reference_colourspace='CIE xyY',
                     colourspaces=None,
                     segments=8,
                     display_grid=True,
                     grid_segments=10,
                     spectral_locus=False,
                     spectral_locus_colour=None,
                     points_size=12,
                     cmfs='CIE 1931 2 Degree Standard Observer',
                     **kwargs):
    """
    Plots given *RGB* colourspace array in a scatter plot.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    colourspace : RGB_Colourspace
        *RGB* colourspace of the *RGB* array.
    reference_colourspace : unicode, optional
        **{'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW',
        'IPT'}**,
        Reference colourspace for colour conversion.
    colourspaces : array_like, optional
        *RGB* colourspaces to plot the gamuts.
    segments : int, optional
        Edge segments count for each *RGB* colourspace cubes.
    display_grid : bool, optional
        Display a grid at the bottom of the *RGB* colourspace cubes.
    grid_segments : bool, optional
        Edge segments count for the grid.
    spectral_locus : bool, optional
        Is spectral locus line plotted.
    spectral_locus_colour : array_like, optional
        Spectral locus line colour.
    points_size : numeric, optional
        Scatter points size.
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectral locus.
    \**kwargs : dict, optional
        **{'face_colours', 'edge_colours', 'edge_alpha', 'face_alpha'}**,
        Arguments for each given colourspace where each key has an array_like
        value such as: ``{ 'face_colours': (None, (0.5, 0.5, 1.0)),
        'edge_colours': (None, (0.5, 0.5, 1.0)), 'edge_alpha': (0.5, 1.0),
        'face_alpha': (0.0, 1.0)}``

        **{'grid_face_colours', 'grid_edge_colours', 'grid_face_alpha',
        'grid_edge_alpha', 'x_axis_colour', 'y_axis_colour', 'x_ticks_colour',
        'y_ticks_colour', 'x_label_colour', 'y_label_colour',
        'ticks_and_label_location'}**,
        Arguments for the nadir grid such as ``{'grid_face_colours':
        (0.25, 0.25, 0.25), 'grid_edge_colours': (0.50, 0.50, 0.50),
        'grid_face_alpha': 0.1, 'grid_edge_alpha': 0.5, 'x_axis_colour':
        (0.0, 0.0, 0.0, 1.0), 'y_axis_colour': (0.0, 0.0, 0.0, 1.0),
        'x_ticks_colour': (0.0, 0.0, 0.0, 0.85), 'y_ticks_colour':
        (0.0, 0.0, 0.0, 0.85), 'x_label_colour': (0.0, 0.0, 0.0, 0.85),
        'y_label_colour': (0.0, 0.0, 0.0, 0.85), 'ticks_and_label_location':
        ('-x', '-y')}``

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> c = 'Rec. 709'
    >>> RGB_scatter_plot(c)  # doctest: +SKIP
    True
    """

    colourspace = get_RGB_colourspace(colourspace)

    if colourspaces is None:
        colourspaces = (colourspace.name,)

    count_c = len(colourspaces)
    settings = Structure(
        **{'face_colours': [None] * count_c,
           'edge_colours': [(0.25, 0.25, 0.25)] * count_c,
           'face_alpha': [0.0] * count_c,
           'edge_alpha': [0.1] * count_c,
           'standalone': False})
    settings.update(kwargs)

    RGB_colourspaces_gamuts_plot(
        colourspaces=colourspaces,
        reference_colourspace=reference_colourspace,
        segments=segments,
        display_grid=display_grid,
        grid_segments=grid_segments,
        spectral_locus=spectral_locus,
        spectral_locus_colour=spectral_locus_colour,
        cmfs=cmfs,
        **settings)

    XYZ = RGB_to_XYZ(
        RGB,
        colourspace.whitepoint,
        colourspace.whitepoint,
        colourspace.RGB_to_XYZ_matrix)

    points = XYZ_to_reference_colourspace(XYZ,
                                          colourspace.whitepoint,
                                          reference_colourspace)

    axes = matplotlib.pyplot.gca()
    axes.scatter(points[..., 0],
                 points[..., 1],
                 points[..., 2],
                 color=np.reshape(RGB, (-1, 3)),
                 s=points_size)

    settings.update({'standalone': True})
    settings.update(kwargs)

    camera(**settings)
    decorate(**settings)

    return display(**settings)
Exemple #34
0
def nadir_grid(limits=None, segments=10, labels=None, axes=None, **kwargs):
    """
    Returns a grid on *xy* plane made of quad geometric elements and its
    associated faces and edges colours. Ticks and labels are added to the
    given axes accordingly to the extended grid settings.

    Parameters
    ----------
    limits : array_like, optional
        Extended grid limits.
    segments : int, optional
        Edge segments count for the extended grid.
    labels : array_like, optional
        Axis labels.
    axes : matplotlib.axes.Axes, optional
        Axes to add the grid.
    \**kwargs : dict, optional
        **{'grid_face_colours', 'grid_edge_colours', 'grid_face_alpha',
        'grid_edge_alpha', 'x_axis_colour', 'y_axis_colour', 'x_ticks_colour',
        'y_ticks_colour', 'x_label_colour', 'y_label_colour',
        'ticks_and_label_location'}**,
        Arguments for the nadir grid such as ``{'grid_face_colours':
        (0.25, 0.25, 0.25), 'grid_edge_colours': (0.50, 0.50, 0.50),
        'grid_face_alpha': 0.1, 'grid_edge_alpha': 0.5, 'x_axis_colour':
        (0.0, 0.0, 0.0, 1.0), 'y_axis_colour': (0.0, 0.0, 0.0, 1.0),
        'x_ticks_colour': (0.0, 0.0, 0.0, 0.85), 'y_ticks_colour':
        (0.0, 0.0, 0.0, 0.85), 'x_label_colour': (0.0, 0.0, 0.0, 0.85),
        'y_label_colour': (0.0, 0.0, 0.0, 0.85), 'ticks_and_label_location':
        ('-x', '-y')}``

    Returns
    -------
    tuple
        Grid quads, faces colours, edges colours.

    Examples
    --------
    >>> c = 'Rec. 709'
    >>> RGB_scatter_plot(c)  # doctest: +SKIP
    True
    """

    if limits is None:
        limits = np.array([[-1, 1], [-1, 1]])

    if labels is None:
        labels = ('x', 'y')

    extent = np.max(np.abs(limits[..., 1] - limits[..., 0]))

    settings = Structure(
        **{'grid_face_colours': (0.25, 0.25, 0.25),
           'grid_edge_colours': (0.50, 0.50, 0.50),
           'grid_face_alpha': 0.1,
           'grid_edge_alpha': 0.5,
           'x_axis_colour': (0.0, 0.0, 0.0, 1.0),
           'y_axis_colour': (0.0, 0.0, 0.0, 1.0),
           'x_ticks_colour': (0.0, 0.0, 0.0, 0.85),
           'y_ticks_colour': (0.0, 0.0, 0.0, 0.85),
           'x_label_colour': (0.0, 0.0, 0.0, 0.85),
           'y_label_colour': (0.0, 0.0, 0.0, 0.85),
           'ticks_and_label_location': ('-x', '-y')})
    settings.update(**kwargs)

    # Outer grid.
    quads_g = grid(origin=(-extent / 2, -extent / 2),
                   width=extent,
                   height=extent,
                   height_segments=segments,
                   width_segments=segments)

    RGB_g = np.ones((quads_g.shape[0], quads_g.shape[-1]))
    RGB_gf = RGB_g * settings.grid_face_colours
    RGB_gf = np.hstack((RGB_gf,
                        np.full((RGB_gf.shape[0], 1),
                                settings.grid_face_alpha,
                                np.float_)))
    RGB_ge = RGB_g * settings.grid_edge_colours
    RGB_ge = np.hstack((RGB_ge,
                        np.full((RGB_ge.shape[0], 1),
                                settings.grid_edge_alpha,
                                np.float_)))

    # Inner grid.
    quads_gs = grid(origin=(-extent / 2, -extent / 2),
                    width=extent,
                    height=extent,
                    height_segments=segments * 2,
                    width_segments=segments * 2)

    RGB_gs = np.ones((quads_gs.shape[0], quads_gs.shape[-1]))
    RGB_gsf = RGB_gs * 0
    RGB_gsf = np.hstack((RGB_gsf,
                         np.full((RGB_gsf.shape[0], 1, np.float_), 0)))
    RGB_gse = np.clip(RGB_gs *
                      settings.grid_edge_colours * 1.5, 0, 1)
    RGB_gse = np.hstack((RGB_gse,
                         np.full((RGB_gse.shape[0], 1),
                                 settings.grid_edge_alpha / 2,
                                 np.float_)))

    # Axis.
    thickness = extent / 1000
    quad_x = grid(origin=(limits[0, 0], -thickness / 2),
                  width=extent,
                  height=thickness)
    RGB_x = np.ones((quad_x.shape[0], quad_x.shape[-1] + 1))
    RGB_x = RGB_x * settings.x_axis_colour

    quad_y = grid(origin=(-thickness / 2, limits[1, 0]),
                  width=thickness,
                  height=extent)
    RGB_y = np.ones((quad_y.shape[0], quad_y.shape[-1] + 1))
    RGB_y = RGB_y * settings.y_axis_colour

    # Ticks.
    x_s = 1 if '+x' in settings.ticks_and_label_location else -1
    y_s = 1 if '+y' in settings.ticks_and_label_location else -1
    for i, axis in enumerate('xy'):
        h_a = 'center' if axis == 'x' else 'left' if x_s == 1 else 'right'
        v_a = 'center'

        ticks = list(sorted(set(quads_g[..., 0, i])))
        ticks += [ticks[-1] + ticks[-1] - ticks[-2]]
        for tick in ticks:
            x = (limits[1, 1 if x_s == 1 else 0] + (x_s * extent / 25)
                 if i else tick)
            y = (tick if i else
                 limits[0, 1 if y_s == 1 else 0] + (y_s * extent / 25))

            tick = int(tick) if float(tick).is_integer() else tick
            c = settings['{0}_ticks_colour'.format(axis)]

            axes.text(x, y, 0, tick, 'x',
                      horizontalalignment=h_a,
                      verticalalignment=v_a,
                      color=c,
                      clip_on=True)

    # Labels.
    for i, axis in enumerate('xy'):
        h_a = 'center' if axis == 'x' else 'left' if x_s == 1 else 'right'
        v_a = 'center'

        x = (limits[1, 1 if x_s == 1 else 0] + (x_s * extent / 10)
             if i else 0)
        y = (0 if i else
             limits[0, 1 if y_s == 1 else 0] + (y_s * extent / 10))

        c = settings['{0}_label_colour'.format(axis)]

        axes.text(x, y, 0, labels[i], 'x',
                  horizontalalignment=h_a,
                  verticalalignment=v_a,
                  color=c,
                  size=20,
                  clip_on=True)

    quads = np.vstack((quads_g, quads_gs, quad_x, quad_y))
    RGB_f = np.vstack((RGB_gf, RGB_gsf, RGB_x, RGB_y))
    RGB_e = np.vstack((RGB_ge, RGB_gse, RGB_x, RGB_y))

    return quads, RGB_f, RGB_e
Exemple #35
0
def nadir_grid(
    limits: Optional[ArrayLike] = None,
    segments: Integer = 10,
    labels: Optional[Sequence[str]] = None,
    axes: Optional[plt.Axes] = None,
    **kwargs: Any,
) -> Tuple[NDArray, NDArray, NDArray]:
    """
    Return a grid on *CIE xy* plane made of quad geometric elements and its
    associated faces and edges colours. Ticks and labels are added to the
    given axes according to the extended grid settings.

    Parameters
    ----------
    limits
        Extended grid limits.
    segments
        Edge segments count for the extended grid.
    labels
        Axis labels.
    axes
        Axes to add the grid.

    Other Parameters
    ----------------
    grid_edge_alpha
        Grid edge opacity value such as `grid_edge_alpha = 0.5`.
    grid_edge_colours
        Grid edge colours array such as
        `grid_edge_colours = (0.25, 0.25, 0.25)`.
    grid_face_alpha
        Grid face opacity value such as `grid_face_alpha = 0.1`.
    grid_face_colours
        Grid face colours array such as
        `grid_face_colours = (0.25, 0.25, 0.25)`.
    ticks_and_label_location
        Location of the *X* and *Y* axis ticks and labels such as
        `ticks_and_label_location = ('-x', '-y')`.
    x_axis_colour
        *X* axis colour array such as `x_axis_colour = (0.0, 0.0, 0.0, 1.0)`.
    x_label_colour
        *X* axis label colour array such as
        `x_label_colour = (0.0, 0.0, 0.0, 0.85)`.
    x_ticks_colour
        *X* axis ticks colour array such as
        `x_ticks_colour = (0.0, 0.0, 0.0, 0.85)`.
    y_axis_colour
        *Y* axis colour array such as `y_axis_colour = (0.0, 0.0, 0.0, 1.0)`.
    y_label_colour
        *Y* axis label colour array such as
        `y_label_colour = (0.0, 0.0, 0.0, 0.85)`.
    y_ticks_colour
        *Y* axis ticks colour array such as
        `y_ticks_colour = (0.0, 0.0, 0.0, 0.85)`.

    Returns
    -------
    :class:`tuple`
        Grid quads, faces colours, edges colours.

    Examples
    --------
    >>> nadir_grid(segments=1)
    (array([[[-1.   , -1.   ,  0.   ],
            [ 1.   , -1.   ,  0.   ],
            [ 1.   ,  1.   ,  0.   ],
            [-1.   ,  1.   ,  0.   ]],
    <BLANKLINE>
           [[-1.   , -1.   ,  0.   ],
            [ 0.   , -1.   ,  0.   ],
            [ 0.   ,  0.   ,  0.   ],
            [-1.   ,  0.   ,  0.   ]],
    <BLANKLINE>
           [[-1.   ,  0.   ,  0.   ],
            [ 0.   ,  0.   ,  0.   ],
            [ 0.   ,  1.   ,  0.   ],
            [-1.   ,  1.   ,  0.   ]],
    <BLANKLINE>
           [[ 0.   , -1.   ,  0.   ],
            [ 1.   , -1.   ,  0.   ],
            [ 1.   ,  0.   ,  0.   ],
            [ 0.   ,  0.   ,  0.   ]],
    <BLANKLINE>
           [[ 0.   ,  0.   ,  0.   ],
            [ 1.   ,  0.   ,  0.   ],
            [ 1.   ,  1.   ,  0.   ],
            [ 0.   ,  1.   ,  0.   ]],
    <BLANKLINE>
           [[-1.   , -0.001,  0.   ],
            [ 1.   , -0.001,  0.   ],
            [ 1.   ,  0.001,  0.   ],
            [-1.   ,  0.001,  0.   ]],
    <BLANKLINE>
           [[-0.001, -1.   ,  0.   ],
            [ 0.001, -1.   ,  0.   ],
            [ 0.001,  1.   ,  0.   ],
            [-0.001,  1.   ,  0.   ]]]), array([[ 0.25,  0.25,  0.25,  0.1 ],
           [ 0.  ,  0.  ,  0.  ,  0.  ],
           [ 0.  ,  0.  ,  0.  ,  0.  ],
           [ 0.  ,  0.  ,  0.  ,  0.  ],
           [ 0.  ,  0.  ,  0.  ,  0.  ],
           [ 0.  ,  0.  ,  0.  ,  1.  ],
           [ 0.  ,  0.  ,  0.  ,  1.  ]]), array([[ 0.5 ,  0.5 ,  0.5 ,  0.5 ],
           [ 0.75,  0.75,  0.75,  0.25],
           [ 0.75,  0.75,  0.75,  0.25],
           [ 0.75,  0.75,  0.75,  0.25],
           [ 0.75,  0.75,  0.75,  0.25],
           [ 0.  ,  0.  ,  0.  ,  1.  ],
           [ 0.  ,  0.  ,  0.  ,  1.  ]]))
    """

    limits = as_float_array(
        cast(ArrayLike, optional(limits, np.array([[-1, 1], [-1, 1]]))))
    labels = cast(Sequence, optional(labels, ("x", "y")))

    extent = np.max(np.abs(limits[..., 1] - limits[..., 0]))

    settings = Structure(
        **{
            "grid_face_colours": (0.25, 0.25, 0.25),
            "grid_edge_colours": (0.50, 0.50, 0.50),
            "grid_face_alpha": 0.1,
            "grid_edge_alpha": 0.5,
            "x_axis_colour": (0.0, 0.0, 0.0, 1.0),
            "y_axis_colour": (0.0, 0.0, 0.0, 1.0),
            "x_ticks_colour": (0.0, 0.0, 0.0, 0.85),
            "y_ticks_colour": (0.0, 0.0, 0.0, 0.85),
            "x_label_colour": (0.0, 0.0, 0.0, 0.85),
            "y_label_colour": (0.0, 0.0, 0.0, 0.85),
            "ticks_and_label_location": ("-x", "-y"),
        })
    settings.update(**kwargs)

    # Outer grid.
    quads_g = primitive_vertices_grid_mpl(
        origin=(-extent / 2, -extent / 2),
        width=extent,
        height=extent,
        height_segments=segments,
        width_segments=segments,
    )

    RGB_g = ones((quads_g.shape[0], quads_g.shape[-1]))
    RGB_gf = RGB_g * settings.grid_face_colours
    RGB_gf = np.hstack(
        [RGB_gf, full((RGB_gf.shape[0], 1), settings.grid_face_alpha)])
    RGB_ge = RGB_g * settings.grid_edge_colours
    RGB_ge = np.hstack(
        [RGB_ge, full((RGB_ge.shape[0], 1), settings.grid_edge_alpha)])

    # Inner grid.
    quads_gs = primitive_vertices_grid_mpl(
        origin=(-extent / 2, -extent / 2),
        width=extent,
        height=extent,
        height_segments=segments * 2,
        width_segments=segments * 2,
    )

    RGB_gs = ones((quads_gs.shape[0], quads_gs.shape[-1]))
    RGB_gsf = RGB_gs * 0
    RGB_gsf = np.hstack([RGB_gsf, full((RGB_gsf.shape[0], 1), 0)])
    RGB_gse = np.clip(RGB_gs * settings.grid_edge_colours * 1.5, 0, 1)
    RGB_gse = np.hstack(
        (RGB_gse, full((RGB_gse.shape[0], 1), settings.grid_edge_alpha / 2)))

    # Axis.
    thickness = extent / 1000
    quad_x = primitive_vertices_grid_mpl(origin=(limits[0, 0], -thickness / 2),
                                         width=extent,
                                         height=thickness)
    RGB_x = ones((quad_x.shape[0], quad_x.shape[-1] + 1))
    RGB_x = RGB_x * settings.x_axis_colour

    quad_y = primitive_vertices_grid_mpl(origin=(-thickness / 2, limits[1, 0]),
                                         width=thickness,
                                         height=extent)
    RGB_y = ones((quad_y.shape[0], quad_y.shape[-1] + 1))
    RGB_y = RGB_y * settings.y_axis_colour

    if axes is not None:
        # Ticks.
        x_s = 1 if "+x" in settings.ticks_and_label_location else -1
        y_s = 1 if "+y" in settings.ticks_and_label_location else -1
        for i, axis in enumerate("xy"):
            h_a = "center" if axis == "x" else "left" if x_s == 1 else "right"
            v_a = "center"

            ticks = list(sorted(set(quads_g[..., 0, i])))
            ticks += [ticks[-1] + ticks[-1] - ticks[-2]]
            for tick in ticks:
                x = (limits[1, 1 if x_s == 1 else 0] +
                     (x_s * extent / 25) if i else tick)
                y = (tick if i else limits[0, 1 if y_s == 1 else 0] +
                     (y_s * extent / 25))

                tick = as_int_scalar(tick) if is_integer(tick) else tick
                c = settings[f"{axis}_ticks_colour"]

                axes.text(
                    x,
                    y,
                    0,
                    tick,
                    "x",
                    horizontalalignment=h_a,
                    verticalalignment=v_a,
                    color=c,
                    clip_on=True,
                )

        # Labels.
        for i, axis in enumerate("xy"):
            h_a = "center" if axis == "x" else "left" if x_s == 1 else "right"
            v_a = "center"

            x = (limits[1, 1 if x_s == 1 else 0] +
                 (x_s * extent / 10) if i else 0)
            y = (0 if i else limits[0, 1 if y_s == 1 else 0] +
                 (y_s * extent / 10))

            c = settings[f"{axis}_label_colour"]

            axes.text(
                x,
                y,
                0,
                labels[i],
                "x",
                horizontalalignment=h_a,
                verticalalignment=v_a,
                color=c,
                size=20,
                clip_on=True,
            )

    quads = np.vstack([quads_g, quads_gs, quad_x, quad_y])
    RGB_f = np.vstack([RGB_gf, RGB_gsf, RGB_x, RGB_y])
    RGB_e = np.vstack([RGB_ge, RGB_gse, RGB_x, RGB_y])

    return quads, RGB_f, RGB_e
Exemple #36
0
def RGB_colourspaces_gamuts_plot(colourspaces=None,
                                 reference_colourspace='CIE xyY',
                                 segments=8,
                                 display_grid=True,
                                 grid_segments=10,
                                 spectral_locus=False,
                                 spectral_locus_colour=None,
                                 cmfs='CIE 1931 2 Degree Standard Observer',
                                 **kwargs):
    """
    Plots given *RGB* colourspaces gamuts in given reference colourspace.

    Parameters
    ----------
    colourspaces : array_like, optional
        *RGB* colourspaces to plot the gamuts.
    reference_colourspace : unicode, optional
        **{'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW',
        'IPT'}**,
        Reference colourspace to plot the gamuts into.
    segments : int, optional
        Edge segments count for each *RGB* colourspace cubes.
    display_grid : bool, optional
        Display a grid at the bottom of the *RGB* colourspace cubes.
    grid_segments : bool, optional
        Edge segments count for the grid.
    spectral_locus : bool, optional
        Is spectral locus line plotted.
    spectral_locus_colour : array_like, optional
        Spectral locus line colour.
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectral locus.
    \**kwargs : dict, optional
        **{'face_colours', 'edge_colours', 'edge_alpha', 'face_alpha'}**,
        Arguments for each given colourspace where each key has an array_like
        value such as: ``{ 'face_colours': (None, (0.5, 0.5, 1.0)),
        'edge_colours': (None, (0.5, 0.5, 1.0)), 'edge_alpha': (0.5, 1.0),
        'face_alpha': (0.0, 1.0)}``

        **{'grid_face_colours', 'grid_edge_colours', 'grid_face_alpha',
        'grid_edge_alpha', 'x_axis_colour', 'y_axis_colour', 'x_ticks_colour',
        'y_ticks_colour', 'x_label_colour', 'y_label_colour',
        'ticks_and_label_location'}**,
        Arguments for the nadir grid such as ``{'grid_face_colours':
        (0.25, 0.25, 0.25), 'grid_edge_colours': (0.50, 0.50, 0.50),
        'grid_face_alpha': 0.1, 'grid_edge_alpha': 0.5, 'x_axis_colour':
        (0.0, 0.0, 0.0, 1.0), 'y_axis_colour': (0.0, 0.0, 0.0, 1.0),
        'x_ticks_colour': (0.0, 0.0, 0.0, 0.85), 'y_ticks_colour':
        (0.0, 0.0, 0.0, 0.85), 'x_label_colour': (0.0, 0.0, 0.0, 0.85),
        'y_label_colour': (0.0, 0.0, 0.0, 0.85), 'ticks_and_label_location':
        ('-x', '-y')}``

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut']
    >>> RGB_colourspaces_gamuts_plot(c)  # doctest: +SKIP
    True
    """

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'ACEScg')

    count_c = len(colourspaces)
    settings = Structure(
        **{'face_colours': [None] * count_c,
           'edge_colours': [None] * count_c,
           'face_alpha': [1] * count_c,
           'edge_alpha': [1] * count_c,
           'title': '{0} - {1} Reference Colourspace'.format(
               ', '.join(colourspaces), reference_colourspace)})
    settings.update(kwargs)

    figure = matplotlib.pyplot.figure()
    axes = figure.add_subplot(111, projection='3d')

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    points = np.zeros((4, 3))
    if spectral_locus:
        cmfs = get_cmfs(cmfs)
        XYZ = cmfs.values

        points = XYZ_to_reference_colourspace(XYZ,
                                              illuminant,
                                              reference_colourspace)

        points[np.isnan(points)] = 0

        c = ((0.0, 0.0, 0.0, 0.5)
             if spectral_locus_colour is None else
             spectral_locus_colour)

        pylab.plot(points[..., 0],
                   points[..., 1],
                   points[..., 2],
                   color=c,
                   linewidth=2,
                   zorder=1)
        pylab.plot((points[-1][0], points[0][0]),
                   (points[-1][1], points[0][1]),
                   (points[-1][2], points[0][2]),
                   color=c,
                   linewidth=2,
                   zorder=1)

    quads, RGB_f, RGB_e = [], [], []
    for i, colourspace in enumerate(colourspaces):
        colourspace = get_RGB_colourspace(colourspace)
        quads_c, RGB = RGB_identity_cube(width_segments=segments,
                                         height_segments=segments,
                                         depth_segments=segments)

        XYZ = RGB_to_XYZ(
            quads_c,
            colourspace.whitepoint,
            colourspace.whitepoint,
            colourspace.RGB_to_XYZ_matrix)

        quads.extend(XYZ_to_reference_colourspace(XYZ,
                                                  colourspace.whitepoint,
                                                  reference_colourspace))

        if settings.face_colours[i] is not None:
            RGB = np.ones(RGB.shape) * settings.face_colours[i]

        RGB_f.extend(np.hstack(
            (RGB, np.full((RGB.shape[0], 1, np.float_),
                          settings.face_alpha[i]))))

        if settings.edge_colours[i] is not None:
            RGB = np.ones(RGB.shape) * settings.edge_colours[i]

        RGB_e.extend(np.hstack(
            (RGB, np.full((RGB.shape[0], 1, np.float_),
                          settings.edge_alpha[i]))))

    quads = np.asarray(quads)
    quads[np.isnan(quads)] = 0

    if quads.size != 0:
        for i, axis in enumerate('xyz'):
            min_a = np.min(np.vstack((quads[..., i], points[..., i])))
            max_a = np.max(np.vstack((quads[..., i], points[..., i])))
            getattr(axes, 'set_{}lim'.format(axis))((min_a, max_a))

    labels = REFERENCE_COLOURSPACES_TO_LABELS[reference_colourspace]
    for i, axis in enumerate('xyz'):
        getattr(axes, 'set_{}label'.format(axis))(labels[i])

    if display_grid:
        if reference_colourspace == 'CIE Lab':
            limits = np.array([[-450, 450], [-450, 450]])
        elif reference_colourspace == 'CIE Luv':
            limits = np.array([[-650, 650], [-650, 650]])
        elif reference_colourspace == 'CIE UVW':
            limits = np.array([[-850, 850], [-850, 850]])
        else:
            limits = np.array([[-1.5, 1.5], [-1.5, 1.5]])

        quads_g, RGB_gf, RGB_ge = nadir_grid(
            limits, grid_segments, labels, axes, **settings)
        quads = np.vstack((quads_g, quads))
        RGB_f = np.vstack((RGB_gf, RGB_f))
        RGB_e = np.vstack((RGB_ge, RGB_e))

    collection = Poly3DCollection(quads)
    collection.set_facecolors(RGB_f)
    collection.set_edgecolors(RGB_e)

    axes.add_collection3d(collection)

    settings.update({
        'camera_aspect': 'equal',
        'no_axes3d': True})
    settings.update(kwargs)

    camera(**settings)
    decorate(**settings)

    return display(**settings)
Exemple #37
0
def plot_RGB_colourspaces_gamuts(
    colourspaces: Union[RGB_Colourspace, str, Sequence[Union[RGB_Colourspace,
                                                             str]]],
    reference_colourspace: Union[Literal["CAM02LCD", "CAM02SCD", "CAM02UCS",
                                         "CAM16LCD", "CAM16SCD", "CAM16UCS",
                                         "CIE XYZ", "CIE xyY", "CIE Lab",
                                         "CIE Luv", "CIE UCS", "CIE UVW",
                                         "DIN99", "Hunter Lab", "Hunter Rdab",
                                         "ICaCb", "ICtCp", "IPT", "IgPgTg",
                                         "Jzazbz", "OSA UCS", "Oklab",
                                         "hdr-CIELAB", "hdr-IPT", ],
                                 str, ] = "CIE xyY",
    segments: Integer = 8,
    show_grid: Boolean = True,
    grid_segments: Integer = 10,
    show_spectral_locus: Boolean = False,
    spectral_locus_colour: Optional[Union[ArrayLike, str]] = None,
    cmfs: Union[MultiSpectralDistributions, str, Sequence[Union[
        MultiSpectralDistributions,
        str]], ] = "CIE 1931 2 Degree Standard Observer",
    chromatically_adapt: Boolean = False,
    convert_kwargs: Optional[Dict] = None,
    **kwargs: Any,
) -> Tuple[plt.Figure, plt.Axes]:
    """
    Plot given *RGB* colourspaces gamuts in given reference colourspace.

    Parameters
    ----------
    colourspaces
        *RGB* colourspaces to plot the gamuts. ``colourspaces`` elements
        can be of any type or form supported by the
        :func:`colour.plotting.filter_RGB_colourspaces` definition.
    reference_colourspace
        Reference colourspace model to plot the gamuts into, see
        :attr:`colour.COLOURSPACE_MODELS` attribute for the list of supported
        colourspace models.
    segments
        Edge segments count for each *RGB* colourspace cubes.
    show_grid
        Whether to show a grid at the bottom of the *RGB* colourspace cubes.
    grid_segments
        Edge segments count for the grid.
    show_spectral_locus
        Whether to show the spectral locus.
    spectral_locus_colour
        Spectral locus colour.
    cmfs
        Standard observer colour matching functions used for computing the
        spectral locus boundaries. ``cmfs`` can be of any type or form
        supported by the :func:`colour.plotting.filter_cmfs` definition.
    chromatically_adapt
        Whether to chromatically adapt the *RGB* colourspaces given in
        ``colourspaces`` to the whitepoint of the default plotting colourspace.
    convert_kwargs
        Keyword arguments for the :func:`colour.convert` definition.

    Other Parameters
    ----------------
    edge_colours
        Edge colours array such as `edge_colours = (None, (0.5, 0.5, 1.0))`.
    edge_alpha
        Edge opacity value such as `edge_alpha = (0.0, 1.0)`.
    face_alpha
        Face opacity value such as `face_alpha = (0.5, 1.0)`.
    face_colours
        Face colours array such as `face_colours = (None, (0.5, 0.5, 1.0))`.
    kwargs
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.volume.nadir_grid`},
        See the documentation of the previously listed definitions.

    Returns
    -------
    :class:`tuple`
        Current figure and axes.

    Examples
    --------
    >>> plot_RGB_colourspaces_gamuts(['ITU-R BT.709', 'ACEScg', 'S-Gamut'])
    ... # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...Axes3DSubplot...>)

    .. image:: ../_static/Plotting_Plot_RGB_Colourspaces_Gamuts.png
        :align: center
        :alt: plot_RGB_colourspaces_gamuts
    """

    colourspaces = cast(
        List[RGB_Colourspace],
        list(filter_RGB_colourspaces(colourspaces).values()),
    )

    convert_kwargs = optional(convert_kwargs, {})

    count_c = len(colourspaces)

    title = (
        f"{', '.join([colourspace.name for colourspace in colourspaces])} "
        f"- {reference_colourspace} Reference Colourspace")

    illuminant = CONSTANTS_COLOUR_STYLE.colour.colourspace.whitepoint

    convert_settings = {"illuminant": illuminant}
    convert_settings.update(convert_kwargs)

    settings = Structure(
        **{
            "face_colours": [None] * count_c,
            "edge_colours": [None] * count_c,
            "face_alpha": [1] * count_c,
            "edge_alpha": [1] * count_c,
            "title": title,
        })
    settings.update(kwargs)

    figure = plt.figure()
    axes = figure.add_subplot(111, projection="3d")

    points = zeros((4, 3))
    if show_spectral_locus:
        cmfs = cast(MultiSpectralDistributions,
                    first_item(filter_cmfs(cmfs).values()))
        XYZ = cmfs.values

        points = colourspace_model_axis_reorder(
            convert(XYZ, "CIE XYZ", reference_colourspace, **convert_settings),
            reference_colourspace,
        )

        points[np.isnan(points)] = 0

        c = ((0.0, 0.0, 0.0,
              0.5) if spectral_locus_colour is None else spectral_locus_colour)

        axes.plot(
            points[..., 0],
            points[..., 1],
            points[..., 2],
            color=c,
            zorder=CONSTANTS_COLOUR_STYLE.zorder.midground_line,
        )
        axes.plot(
            (points[-1][0], points[0][0]),
            (points[-1][1], points[0][1]),
            (points[-1][2], points[0][2]),
            color=c,
            zorder=CONSTANTS_COLOUR_STYLE.zorder.midground_line,
        )

    plotting_colourspace = CONSTANTS_COLOUR_STYLE.colour.colourspace

    quads_c: List = []
    RGB_cf: List = []
    RGB_ce: List = []
    for i, colourspace in enumerate(colourspaces):

        if chromatically_adapt and not np.array_equal(
                colourspace.whitepoint, plotting_colourspace.whitepoint):
            colourspace = colourspace.chromatically_adapt(
                plotting_colourspace.whitepoint,
                plotting_colourspace.whitepoint_name,
            )

        quads_cb, RGB = RGB_identity_cube(
            width_segments=segments,
            height_segments=segments,
            depth_segments=segments,
        )

        XYZ = RGB_to_XYZ(
            quads_cb,
            colourspace.whitepoint,
            colourspace.whitepoint,
            colourspace.matrix_RGB_to_XYZ,
        )

        convert_settings = {"illuminant": colourspace.whitepoint}
        convert_settings.update(convert_kwargs)

        quads_c.extend(
            colourspace_model_axis_reorder(
                convert(XYZ, "CIE XYZ", reference_colourspace,
                        **convert_settings),
                reference_colourspace,
            ))

        if settings.face_colours[i] is not None:
            RGB = ones(RGB.shape) * settings.face_colours[i]

        RGB_cf.extend(
            np.hstack([RGB,
                       full((RGB.shape[0], 1), settings.face_alpha[i])]))

        if settings.edge_colours[i] is not None:
            RGB = ones(RGB.shape) * settings.edge_colours[i]

        RGB_ce.extend(
            np.hstack([RGB,
                       full((RGB.shape[0], 1), settings.edge_alpha[i])]))

    quads = as_float_array(quads_c)
    RGB_f = as_float_array(RGB_cf)
    RGB_e = as_float_array(RGB_ce)

    quads[np.isnan(quads)] = 0

    if quads.size != 0:
        for i, axis in enumerate("xyz"):
            min_a = np.minimum(np.min(quads[..., i]), np.min(points[..., i]))
            max_a = np.maximum(np.max(quads[..., i]), np.max(points[..., i]))
            getattr(axes, f"set_{axis}lim")((min_a, max_a))

    labels = np.array(
        COLOURSPACE_MODELS_AXIS_LABELS[reference_colourspace])[as_int_array(
            colourspace_model_axis_reorder([0, 1, 2], reference_colourspace))]
    for i, axis in enumerate("xyz"):
        getattr(axes, f"set_{axis}label")(labels[i])

    if show_grid:
        limits = np.array([[-1.5, 1.5], [-1.5, 1.5]])

        quads_g, RGB_gf, RGB_ge = nadir_grid(limits, grid_segments, labels,
                                             axes, **settings)
        quads = np.vstack([quads_g, quads])
        RGB_f = np.vstack([RGB_gf, RGB_f])
        RGB_e = np.vstack([RGB_ge, RGB_e])

    collection = Poly3DCollection(quads)
    collection.set_facecolors(RGB_f)
    collection.set_edgecolors(RGB_e)

    axes.add_collection3d(collection)

    settings.update({
        "axes": axes,
        "axes_visible": False,
        "camera_aspect": "equal"
    })
    settings.update(kwargs)

    return render(**settings)
Exemple #38
0
def plot_RGB_scatter(
    RGB: ArrayLike,
    colourspace: Union[RGB_Colourspace, str, Sequence[Union[RGB_Colourspace,
                                                            str]]],
    reference_colourspace: Union[Literal["CAM02LCD", "CAM02SCD", "CAM02UCS",
                                         "CAM16LCD", "CAM16SCD", "CAM16UCS",
                                         "CIE XYZ", "CIE xyY", "CIE Lab",
                                         "CIE Luv", "CIE UCS", "CIE UVW",
                                         "DIN99", "Hunter Lab", "Hunter Rdab",
                                         "ICaCb", "ICtCp", "IPT", "IgPgTg",
                                         "Jzazbz", "OSA UCS", "Oklab",
                                         "hdr-CIELAB", "hdr-IPT", ],
                                 str, ] = "CIE xyY",
    colourspaces: Optional[Union[RGB_Colourspace, str,
                                 Sequence[Union[RGB_Colourspace,
                                                str]]]] = None,
    segments: Integer = 8,
    show_grid: Boolean = True,
    grid_segments: Integer = 10,
    show_spectral_locus: Boolean = False,
    spectral_locus_colour: Optional[Union[ArrayLike, str]] = None,
    points_size: Floating = 12,
    cmfs: Union[MultiSpectralDistributions, str, Sequence[Union[
        MultiSpectralDistributions,
        str]], ] = "CIE 1931 2 Degree Standard Observer",
    chromatically_adapt: Boolean = False,
    convert_kwargs: Optional[Dict] = None,
    **kwargs: Any,
) -> Tuple[plt.Figure, plt.Axes]:
    """
    Plot given *RGB* colourspace array in a scatter plot.

    Parameters
    ----------
    RGB
        *RGB* colourspace array.
    colourspace
        *RGB* colourspace of the *RGB* array. ``colourspace`` can be of any
        type or form supported by the
        :func:`colour.plotting.filter_RGB_colourspaces` definition.
    reference_colourspace
        Reference colourspace model to plot the gamuts into, see
        :attr:`colour.COLOURSPACE_MODELS` attribute for the list of supported
        colourspace models.
    colourspaces
        *RGB* colourspaces to plot the gamuts. ``colourspaces`` elements
        can be of any type or form supported by the
        :func:`colour.plotting.filter_RGB_colourspaces` definition.
    segments
        Edge segments count for each *RGB* colourspace cubes.
    show_grid
        Whether to show a grid at the bottom of the *RGB* colourspace cubes.
    grid_segments
        Edge segments count for the grid.
    show_spectral_locus
        Whether to show the spectral locus.
    spectral_locus_colour
        Spectral locus colour.
    points_size
        Scatter points size.
    cmfs
        Standard observer colour matching functions used for computing the
        spectral locus boundaries. ``cmfs`` can be of any type or form
        supported by the :func:`colour.plotting.filter_cmfs` definition.
    chromatically_adapt
        Whether to chromatically adapt the *RGB* colourspaces given in
        ``colourspaces`` to the whitepoint of the default plotting colourspace.
    convert_kwargs
        Keyword arguments for the :func:`colour.convert` definition.

    Other Parameters
    ----------------
    kwargs
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.plot_RGB_colourspaces_gamuts`},
        See the documentation of the previously listed definitions.

    Returns
    -------
    :class:`tuple`
        Current figure and axes.

    Examples
    --------
    >>> RGB = np.random.random((128, 128, 3))
    >>> plot_RGB_scatter(RGB, 'ITU-R BT.709')  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...Axes3DSubplot...>)

    .. image:: ../_static/Plotting_Plot_RGB_Scatter.png
        :align: center
        :alt: plot_RGB_scatter
    """

    colourspace = cast(
        RGB_Colourspace,
        first_item(filter_RGB_colourspaces(colourspace).values()),
    )
    colourspaces = cast(List[str], optional(colourspaces, [colourspace.name]))

    convert_kwargs = optional(convert_kwargs, {})

    count_c = len(colourspaces)
    settings = Structure(
        **{
            "face_colours": [None] * count_c,
            "edge_colours": [(0.25, 0.25, 0.25)] * count_c,
            "face_alpha": [0.0] * count_c,
            "edge_alpha": [0.1] * count_c,
        })
    settings.update(kwargs)
    settings["standalone"] = False

    plot_RGB_colourspaces_gamuts(
        colourspaces=colourspaces,
        reference_colourspace=reference_colourspace,
        segments=segments,
        show_grid=show_grid,
        grid_segments=grid_segments,
        show_spectral_locus=show_spectral_locus,
        spectral_locus_colour=spectral_locus_colour,
        cmfs=cmfs,
        chromatically_adapt=chromatically_adapt,
        **settings,
    )

    XYZ = RGB_to_XYZ(
        RGB,
        colourspace.whitepoint,
        colourspace.whitepoint,
        colourspace.matrix_RGB_to_XYZ,
    )

    convert_settings = {"illuminant": colourspace.whitepoint}
    convert_settings.update(convert_kwargs)

    points = colourspace_model_axis_reorder(
        convert(XYZ, "CIE XYZ", reference_colourspace, **convert_settings),
        reference_colourspace,
    )

    axes = plt.gca()
    axes.scatter(
        points[..., 0],
        points[..., 1],
        points[..., 2],
        color=np.reshape(RGB, (-1, 3)),
        s=points_size,
        zorder=CONSTANTS_COLOUR_STYLE.zorder.midground_scatter,
    )

    settings.update({"axes": axes, "standalone": True})
    settings.update(kwargs)

    return render(**settings)
Exemple #39
0
def plot_RGB_colourspaces_gamuts(colourspaces=None,
                                 reference_colourspace='CIE xyY',
                                 segments=8,
                                 show_grid=True,
                                 grid_segments=10,
                                 show_spectral_locus=False,
                                 spectral_locus_colour=None,
                                 cmfs='CIE 1931 2 Degree Standard Observer',
                                 **kwargs):
    """
    Plots given *RGB* colourspaces gamuts in given reference colourspace.

    Parameters
    ----------
    colourspaces : array_like, optional
        *RGB* colourspaces to plot the gamuts.
    reference_colourspace : unicode, optional
        **{'CIE XYZ', 'CIE xyY', 'CIE xy', 'CIE Lab', 'CIE LCHab', 'CIE Luv',
        'CIE Luv uv', 'CIE LCHuv', 'CIE UCS', 'CIE UCS uv', 'CIE UVW',
        'DIN 99', 'Hunter Lab', 'Hunter Rdab', 'IPT', 'JzAzBz', 'OSA UCS',
        'hdr-CIELAB', 'hdr-IPT'}**,
        Reference colourspace to plot the gamuts into.
    segments : int, optional
        Edge segments count for each *RGB* colourspace cubes.
    show_grid : bool, optional
        Whether to show a grid at the bottom of the *RGB* colourspace cubes.
    grid_segments : bool, optional
        Edge segments count for the grid.
    show_spectral_locus : bool, optional
        Whether to show the spectral locus.
    spectral_locus_colour : array_like, optional
        Spectral locus colour.
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectral locus.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.volume.nadir_grid`},
        Please refer to the documentation of the previously listed definitions.
    face_colours : array_like, optional
        Face colours array such as `face_colours = (None, (0.5, 0.5, 1.0))`.
    edge_colours : array_like, optional
        Edge colours array such as `edge_colours = (None, (0.5, 0.5, 1.0))`.
    face_alpha : numeric, optional
        Face opacity value such as `face_alpha = (0.5, 1.0)`.
    edge_alpha : numeric, optional
        Edge opacity value such as `edge_alpha = (0.0, 1.0)`.

    Returns
    -------
    tuple
        Current figure and axes.

    Examples
    --------
    >>> plot_RGB_colourspaces_gamuts(['ITU-R BT.709', 'ACEScg', 'S-Gamut'])
    ... # doctest: +SKIP

    .. image:: ../_static/Plotting_Plot_RGB_Colourspaces_Gamuts.png
        :align: center
        :alt: plot_RGB_colourspaces_gamuts
    """

    if colourspaces is None:
        colourspaces = ('ITU-R BT.709', 'ACEScg')

    colourspaces = filter_RGB_colourspaces(colourspaces).values()

    count_c = len(colourspaces)

    title = '{0} - {1} Reference Colourspace'.format(
        ', '.join([colourspace.name for colourspace in colourspaces]),
        reference_colourspace,
    )

    settings = Structure(
        **{
            'face_colours': [None] * count_c,
            'edge_colours': [None] * count_c,
            'face_alpha': [1] * count_c,
            'edge_alpha': [1] * count_c,
            'title': title,
        })
    settings.update(kwargs)

    figure = plt.figure()
    axes = figure.add_subplot(111, projection='3d')

    illuminant = COLOUR_STYLE_CONSTANTS.colour.colourspace.whitepoint

    points = np.zeros((4, 3))
    if show_spectral_locus:
        cmfs = first_item(filter_cmfs(cmfs).values())
        XYZ = cmfs.values

        points = common_colourspace_model_axis_reorder(
            XYZ_to_colourspace_model(XYZ, illuminant, reference_colourspace),
            reference_colourspace)

        points[np.isnan(points)] = 0

        c = ((0.0, 0.0, 0.0, 0.5)
             if spectral_locus_colour is None else spectral_locus_colour)

        axes.plot(
            points[..., 0], points[..., 1], points[..., 2], color=c, zorder=1)
        axes.plot(
            (points[-1][0], points[0][0]), (points[-1][1], points[0][1]),
            (points[-1][2], points[0][2]),
            color=c,
            zorder=1)

    quads, RGB_f, RGB_e = [], [], []
    for i, colourspace in enumerate(colourspaces):
        quads_c, RGB = RGB_identity_cube(
            width_segments=segments,
            height_segments=segments,
            depth_segments=segments)

        XYZ = RGB_to_XYZ(
            quads_c,
            colourspace.whitepoint,
            colourspace.whitepoint,
            colourspace.RGB_to_XYZ_matrix,
        )

        quads.extend(
            common_colourspace_model_axis_reorder(
                XYZ_to_colourspace_model(
                    XYZ,
                    colourspace.whitepoint,
                    reference_colourspace,
                ), reference_colourspace))

        if settings.face_colours[i] is not None:
            RGB = np.ones(RGB.shape) * settings.face_colours[i]

        RGB_f.extend(
            np.hstack([
                RGB,
                np.full((RGB.shape[0], 1), settings.face_alpha[i],
                        DEFAULT_FLOAT_DTYPE)
            ]))

        if settings.edge_colours[i] is not None:
            RGB = np.ones(RGB.shape) * settings.edge_colours[i]

        RGB_e.extend(
            np.hstack([
                RGB,
                np.full((RGB.shape[0], 1), settings.edge_alpha[i],
                        DEFAULT_FLOAT_DTYPE)
            ]))

    quads = as_float_array(quads)
    quads[np.isnan(quads)] = 0

    if quads.size != 0:
        for i, axis in enumerate('xyz'):
            min_a = min(np.min(quads[..., i]), np.min(points[..., i]))
            max_a = max(np.max(quads[..., i]), np.max(points[..., i]))
            getattr(axes, 'set_{}lim'.format(axis))((min_a, max_a))

    labels = COLOURSPACE_MODELS_LABELS[reference_colourspace]
    for i, axis in enumerate('xyz'):
        getattr(axes, 'set_{}label'.format(axis))(labels[i])

    if show_grid:
        if reference_colourspace == 'CIE Lab':
            limits = np.array([[-450, 450], [-450, 450]])
        elif reference_colourspace == 'CIE Luv':
            limits = np.array([[-650, 650], [-650, 650]])
        elif reference_colourspace == 'CIE UVW':
            limits = np.array([[-850, 850], [-850, 850]])
        elif reference_colourspace in ('Hunter Lab', 'Hunter Rdab'):
            limits = np.array([[-250, 250], [-250, 250]])
        else:
            limits = np.array([[-1.5, 1.5], [-1.5, 1.5]])

        quads_g, RGB_gf, RGB_ge = nadir_grid(limits, grid_segments, labels,
                                             axes, **settings)
        quads = np.vstack([quads_g, quads])
        RGB_f = np.vstack([RGB_gf, RGB_f])
        RGB_e = np.vstack([RGB_ge, RGB_e])

    collection = Poly3DCollection(quads)
    collection.set_facecolors(RGB_f)
    collection.set_edgecolors(RGB_e)

    axes.add_collection3d(collection)

    settings.update({
        'axes': axes,
        'axes_visible': False,
        'camera_aspect': 'equal'
    })
    settings.update(kwargs)

    return render(**settings)
Exemple #40
0
def colour_checkers_coordinates_segmentation(
        image: ArrayLike,
        additional_data: Boolean = False,
        **kwargs: Any
) -> Union[ColourCheckersDetectionData, Tuple[NDArray, ...]]:
    """
    Detect the colour checkers coordinates in given image :math:`image` using
    segmentation.

    This is the core detection definition. The process is a follows:

    -   Input image :math:`image` is converted to a grayscale image
        :math:`image_g`.
    -   Image :math:`image_g` is denoised.
    -   Image :math:`image_g` is thresholded/segmented to image
        :math:`image_s`.
    -   Image :math:`image_s` is eroded and dilated to cleanup remaining noise.
    -   Contours are detected on image :math:`image_s`.
    -   Contours are filtered to only keep squares/swatches above and below
        defined surface area.
    -   Squares/swatches are clustered to isolate region-of-interest that are
        potentially colour checkers: Contours are scaled by a third so that
        colour checkers swatches are expected to be joined, creating a large
        rectangular cluster. Rectangles are fitted to the clusters.
    -   Clusters with an aspect ratio different to the expected one are
        rejected, a side-effect is that the complementary pane of the
        *X-Rite* *ColorChecker Passport* is omitted.
    -   Clusters with a number of swatches close to the expected one are
        kept.

    Parameters
    ----------
    image
        Image to detect the colour checkers in.
    additional_data
        Whether to output additional data.

    Other Parameters
    ----------------
    aspect_ratio
        Colour checker aspect ratio, e.g. 1.5.
    aspect_ratio_minimum
        Minimum colour checker aspect ratio for detection: projective geometry
        might reduce the colour checker aspect ratio.
    aspect_ratio_maximum
        Maximum colour checker aspect ratio for detection: projective geometry
        might increase the colour checker aspect ratio.
    swatches
        Colour checker swatches total count.
    swatches_horizontal
        Colour checker swatches horizontal columns count.
    swatches_vertical
        Colour checker swatches vertical row count.
    swatches_count_minimum
        Minimum swatches count to be considered for the detection.
    swatches_count_maximum
        Maximum swatches count to be considered for the detection.
    swatches_chromatic_slice
        A `slice` instance defining chromatic swatches used to detect if the
        colour checker is upside down.
    swatches_achromatic_slice
        A `slice` instance defining achromatic swatches used to detect if the
        colour checker is upside down.
    swatch_minimum_area_factor
        Swatch minimum area factor :math:`f` with the minimum area :math:`m_a`
        expressed as follows: :math:`m_a = image_w * image_h / s_c / f` where
        :math:`image_w`, :math:`image_h` and :math:`s_c` are respectively the
        image width, height and the swatches count.
    swatch_contour_scale
        As the image is filtered, the swatches area will tend to shrink, the
        generated contours can thus be scaled.
    cluster_contour_scale
        As the swatches are clustered, it might be necessary to adjust the
        cluster scale so that the masks are centred better on the swatches.
    working_width
        Size the input image is resized to for detection.
    fast_non_local_means_denoising_kwargs
        Keyword arguments for :func:`cv2.fastNlMeansDenoising` definition.
    adaptive_threshold_kwargs
        Keyword arguments for :func:`cv2.adaptiveThreshold` definition.
    interpolation_method
        Interpolation method used when resizing the images, `cv2.INTER_CUBIC`
        and `cv2.INTER_LINEAR` methods are recommended.

    Returns
    -------
    :class:`colour_checker_detection.detection.segmentation.\
ColourCheckersDetectionData` or :class:`tuple`
        Tuple of colour checkers coordinates or
        :class:`ColourCheckersDetectionData` class instance with additional
        data.

    Notes
    -----
    -   Multiple colour checkers can be detected if presented in ``image``.

    Examples
    --------
    >>> import os
    >>> from colour import read_image
    >>> from colour_checker_detection import TESTS_RESOURCES_DIRECTORY
    >>> path = os.path.join(TESTS_RESOURCES_DIRECTORY,
    ...                     'colour_checker_detection', 'detection',
    ...                     'IMG_1967.png')
    >>> image = read_image(path)
    >>> colour_checkers_coordinates_segmentation(image)  # doctest: +ELLIPSIS
    (array([[ 369,  688],
           [ 382,  226],
           [1078,  246],
           [1065,  707]]...)
    """

    image = as_float_array(image, FLOAT_DTYPE_DEFAULT)[..., :3]

    settings = Structure(**SETTINGS_SEGMENTATION_COLORCHECKER_CLASSIC)
    settings.update(**kwargs)

    image = as_8_bit_BGR_image(
        adjust_image(image, settings.working_width,
                     settings.interpolation_method))

    width, height = image.shape[1], image.shape[0]
    maximum_area = width * height / settings.swatches
    minimum_area = (width * height / settings.swatches /
                    settings.swatch_minimum_area_factor)

    # Thresholding/Segmentation.
    image_g = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    image_g = cv2.fastNlMeansDenoising(
        image_g, None, **settings.fast_non_local_means_denoising_kwargs)
    image_s = cv2.adaptiveThreshold(image_g,
                                    **settings.adaptive_threshold_kwargs)
    # Cleanup.
    kernel = np.ones([3, 3], np.uint8)
    image_c = cv2.erode(image_s, kernel, iterations=1)
    image_c = cv2.dilate(image_c, kernel, iterations=1)

    # Detecting contours.
    contours, _hierarchy = cv2.findContours(image_c, cv2.RETR_TREE,
                                            cv2.CHAIN_APPROX_NONE)

    # Filtering squares/swatches contours.
    swatches = []
    for contour in contours:
        curve = cv2.approxPolyDP(contour, 0.01 * cv2.arcLength(contour, True),
                                 True)
        if minimum_area < cv2.contourArea(curve) < maximum_area and is_square(
                curve):
            swatches.append(as_int_array(cv2.boxPoints(
                cv2.minAreaRect(curve))))

    # Clustering squares/swatches.
    contours = np.zeros(image.shape, dtype=np.uint8)
    for swatch in [
            as_int_array(scale_contour(swatch, settings.swatch_contour_scale))
            for swatch in swatches
    ]:
        cv2.drawContours(contours, [swatch], -1, [255] * 3, -1)
    contours = cv2.cvtColor(contours, cv2.COLOR_RGB2GRAY)
    contours, _hierarchy = cv2.findContours(contours, cv2.RETR_EXTERNAL,
                                            cv2.CHAIN_APPROX_NONE)
    clusters = [
        as_int_array(
            scale_contour(
                cv2.boxPoints(cv2.minAreaRect(cluster)),
                settings.cluster_contour_scale,
            )) for cluster in contours
    ]

    # Filtering clusters using their aspect ratio.
    filtered_clusters = []
    for cluster in clusters[:]:
        rectangle = cv2.minAreaRect(cluster)
        width = max(rectangle[1][0], rectangle[1][1])
        height = min(rectangle[1][0], rectangle[1][1])
        ratio = width / height
        if (settings.aspect_ratio_minimum < ratio <
                settings.aspect_ratio_maximum):
            filtered_clusters.append(as_int_array(cluster))
    clusters = filtered_clusters

    # Filtering swatches within cluster.
    counts = []
    for cluster in clusters:
        count = 0
        for swatch in swatches:
            if (cv2.pointPolygonTest(cluster, contour_centroid(swatch),
                                     False) == 1):
                count += 1
        counts.append(count)

    indexes = np.where(
        np.logical_and(
            as_int_array(counts) >= settings.swatches_count_minimum,
            as_int_array(counts) <= settings.swatches_count_maximum,
        ))[0]

    colour_checkers = tuple(clusters[i] for i in indexes)

    if additional_data:
        return ColourCheckersDetectionData(tuple(colour_checkers),
                                           tuple(clusters), tuple(swatches),
                                           image_c)
    else:
        return colour_checkers
Exemple #41
0
def decorate(**kwargs):
    """
    Sets the figure decorations.

    Parameters
    ----------
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.
    """

    settings = Structure(
        **{'title': None,
           'x_label': None,
           'y_label': None,
           'legend': False,
           'legend_location': 'upper right',
           'x_ticker': False,
           'y_ticker': False,
           'x_ticker_locator': matplotlib.ticker.AutoMinorLocator(2),
           'y_ticker_locator': matplotlib.ticker.AutoMinorLocator(2),
           'no_ticks': False,
           'no_x_ticks': False,
           'no_y_ticks': False,
           'grid': False,
           'grid_which': 'both',
           'grid_axis': 'both',
           'x_axis_line': False,
           'y_axis_line': False,
           'aspect': None})
    settings.update(kwargs)

    if settings.title:
        pylab.title(settings.title)
    if settings.x_label:
        pylab.xlabel(settings.x_label)
    if settings.y_label:
        pylab.ylabel(settings.y_label)
    if settings.legend:
        pylab.legend(loc=settings.legend_location)
    if settings.x_ticker:
        matplotlib.pyplot.gca().xaxis.set_minor_locator(
            settings.x_ticker_locator)
    if settings.y_ticker:
        matplotlib.pyplot.gca().yaxis.set_minor_locator(
            settings.y_ticker_locator)
    if settings.no_ticks:
        matplotlib.pyplot.gca().set_xticks([])
        matplotlib.pyplot.gca().set_yticks([])
    if settings.no_x_ticks:
        matplotlib.pyplot.gca().set_xticks([])
    if settings.no_y_ticks:
        matplotlib.pyplot.gca().set_yticks([])
    if settings.grid:
        pylab.grid(which=settings.grid_which, axis=settings.grid_axis)
    if settings.x_axis_line:
        pylab.axvline(color='black', linestyle='--')
    if settings.y_axis_line:
        pylab.axhline(color='black', linestyle='--')
    if settings.aspect:
        matplotlib.pyplot.axes().set_aspect(settings.aspect)

    return True
Exemple #42
0
def RGB_scatter_plot(RGB,
                     colourspace,
                     reference_colourspace='CIE xyY',
                     colourspaces=None,
                     segments=8,
                     display_grid=True,
                     grid_segments=10,
                     spectral_locus=False,
                     spectral_locus_colour=None,
                     points_size=12,
                     cmfs='CIE 1931 2 Degree Standard Observer',
                     **kwargs):
    """
    Plots given *RGB* colourspace array in a scatter plot.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    colourspace : RGB_Colourspace
        *RGB* colourspace of the *RGB* array.
    reference_colourspace : unicode, optional
        **{'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW',
        'IPT', 'Hunter Lab', 'Hunter Rdab'}**,
        Reference colourspace for colour conversion.
    colourspaces : array_like, optional
        *RGB* colourspaces to plot the gamuts.
    segments : int, optional
        Edge segments count for each *RGB* colourspace cubes.
    display_grid : bool, optional
        Display a grid at the bottom of the *RGB* colourspace cubes.
    grid_segments : bool, optional
        Edge segments count for the grid.
    spectral_locus : bool, optional
        Is spectral locus line plotted.
    spectral_locus_colour : array_like, optional
        Spectral locus line colour.
    points_size : numeric, optional
        Scatter points size.
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectral locus.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`RGB_colourspaces_gamuts_plot`},
        Please refer to the documentation of the previously listed definitions.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> c = 'Rec. 709'
    >>> RGB_scatter_plot(c)  # doctest: +SKIP
    """

    colourspace = get_RGB_colourspace(colourspace)

    if colourspaces is None:
        colourspaces = (colourspace.name, )

    count_c = len(colourspaces)
    settings = Structure(
        **{
            'face_colours': [None] * count_c,
            'edge_colours': [(0.25, 0.25, 0.25)] * count_c,
            'face_alpha': [0.0] * count_c,
            'edge_alpha': [0.1] * count_c,
            'standalone': False
        })
    settings.update(kwargs)

    RGB_colourspaces_gamuts_plot(colourspaces=colourspaces,
                                 reference_colourspace=reference_colourspace,
                                 segments=segments,
                                 display_grid=display_grid,
                                 grid_segments=grid_segments,
                                 spectral_locus=spectral_locus,
                                 spectral_locus_colour=spectral_locus_colour,
                                 cmfs=cmfs,
                                 **settings)

    XYZ = RGB_to_XYZ(RGB, colourspace.whitepoint, colourspace.whitepoint,
                     colourspace.RGB_to_XYZ_matrix)

    points = common_colourspace_model_axis_reorder(
        XYZ_to_colourspace_model(XYZ, colourspace.whitepoint,
                                 reference_colourspace), reference_colourspace)

    axes = matplotlib.pyplot.gca()
    axes.scatter(points[..., 0],
                 points[..., 1],
                 points[..., 2],
                 color=np.reshape(RGB, (-1, 3)),
                 s=points_size)

    settings.update({'standalone': True})
    settings.update(kwargs)

    camera(**settings)
    decorate(**settings)

    return display(**settings)
Exemple #43
0
def RGB_colourspaces_gamuts_plot(colourspaces=None,
                                 reference_colourspace='CIE xyY',
                                 segments=8,
                                 display_grid=True,
                                 grid_segments=10,
                                 spectral_locus=False,
                                 spectral_locus_colour=None,
                                 cmfs='CIE 1931 2 Degree Standard Observer',
                                 **kwargs):
    """
    Plots given *RGB* colourspaces gamuts in given reference colourspace.

    Parameters
    ----------
    colourspaces : array_like, optional
        *RGB* colourspaces to plot the gamuts.
    reference_colourspace : unicode, optional
        **{'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW',
        'IPT', 'Hunter Lab', 'Hunter Rdab'}**,
        Reference colourspace to plot the gamuts into.
    segments : int, optional
        Edge segments count for each *RGB* colourspace cubes.
    display_grid : bool, optional
        Display a grid at the bottom of the *RGB* colourspace cubes.
    grid_segments : bool, optional
        Edge segments count for the grid.
    spectral_locus : bool, optional
        Is spectral locus line plotted.
    spectral_locus_colour : array_like, optional
        Spectral locus line colour.
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectral locus.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`nadir_grid`},
        Please refer to the documentation of the previously listed definitions.
    face_colours : array_like, optional
        Face colours array such as `face_colours = (None, (0.5, 0.5, 1.0))`.
    edge_colours : array_like, optional
        Edge colours array such as `edge_colours = (None, (0.5, 0.5, 1.0))`.
    face_alpha : numeric, optional
        Face opacity value such as `face_alpha = (0.5, 1.0)`.
    edge_alpha : numeric, optional
        Edge opacity value such as `edge_alpha = (0.0, 1.0)`.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut']
    >>> RGB_colourspaces_gamuts_plot(c)  # doctest: +SKIP
    """

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'ACEScg')

    count_c = len(colourspaces)
    settings = Structure(
        **{
            'face_colours': [None] * count_c,
            'edge_colours': [None] * count_c,
            'face_alpha': [1] * count_c,
            'edge_alpha': [1] * count_c,
            'title':
            '{0} - {1} Reference Colourspace'.format(', '.join(colourspaces),
                                                     reference_colourspace)
        })
    settings.update(kwargs)

    figure = matplotlib.pyplot.figure()
    axes = figure.add_subplot(111, projection='3d')

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    points = np.zeros((4, 3))
    if spectral_locus:
        cmfs = get_cmfs(cmfs)
        XYZ = cmfs.values

        points = common_colourspace_model_axis_reorder(
            XYZ_to_colourspace_model(XYZ, illuminant, reference_colourspace),
            reference_colourspace)

        points[np.isnan(points)] = 0

        c = ((0.0, 0.0, 0.0,
              0.5) if spectral_locus_colour is None else spectral_locus_colour)

        pylab.plot(points[..., 0],
                   points[..., 1],
                   points[..., 2],
                   color=c,
                   linewidth=2,
                   zorder=1)
        pylab.plot((points[-1][0], points[0][0]),
                   (points[-1][1], points[0][1]),
                   (points[-1][2], points[0][2]),
                   color=c,
                   linewidth=2,
                   zorder=1)

    quads, RGB_f, RGB_e = [], [], []
    for i, colourspace in enumerate(colourspaces):
        colourspace = get_RGB_colourspace(colourspace)
        quads_c, RGB = RGB_identity_cube(width_segments=segments,
                                         height_segments=segments,
                                         depth_segments=segments)

        XYZ = RGB_to_XYZ(quads_c, colourspace.whitepoint,
                         colourspace.whitepoint, colourspace.RGB_to_XYZ_matrix)

        quads.extend(
            common_colourspace_model_axis_reorder(
                XYZ_to_colourspace_model(XYZ, colourspace.whitepoint,
                                         reference_colourspace),
                reference_colourspace))

        if settings.face_colours[i] is not None:
            RGB = np.ones(RGB.shape) * settings.face_colours[i]

        RGB_f.extend(
            np.hstack((RGB,
                       np.full((RGB.shape[0], 1), settings.face_alpha[i],
                               np.float_))))

        if settings.edge_colours[i] is not None:
            RGB = np.ones(RGB.shape) * settings.edge_colours[i]

        RGB_e.extend(
            np.hstack((RGB,
                       np.full((RGB.shape[0], 1), settings.edge_alpha[i],
                               np.float_))))

    quads = np.asarray(quads)
    quads[np.isnan(quads)] = 0

    if quads.size != 0:
        for i, axis in enumerate('xyz'):
            min_a = np.min(np.vstack((quads[..., i], points[..., i])))
            max_a = np.max(np.vstack((quads[..., i], points[..., i])))
            getattr(axes, 'set_{}lim'.format(axis))((min_a, max_a))

    labels = COLOURSPACE_MODELS_LABELS[reference_colourspace]
    for i, axis in enumerate('xyz'):
        getattr(axes, 'set_{}label'.format(axis))(labels[i])

    if display_grid:
        if reference_colourspace == 'CIE Lab':
            limits = np.array([[-450, 450], [-450, 450]])
        elif reference_colourspace == 'CIE Luv':
            limits = np.array([[-650, 650], [-650, 650]])
        elif reference_colourspace == 'CIE UVW':
            limits = np.array([[-850, 850], [-850, 850]])
        elif reference_colourspace in ('Hunter Lab', 'Hunter Rdab'):
            limits = np.array([[-250, 250], [-250, 250]])
        else:
            limits = np.array([[-1.5, 1.5], [-1.5, 1.5]])

        quads_g, RGB_gf, RGB_ge = nadir_grid(limits, grid_segments, labels,
                                             axes, **settings)
        quads = np.vstack((quads_g, quads))
        RGB_f = np.vstack((RGB_gf, RGB_f))
        RGB_e = np.vstack((RGB_ge, RGB_e))

    collection = Poly3DCollection(quads)
    collection.set_facecolors(RGB_f)
    collection.set_edgecolors(RGB_e)

    axes.add_collection3d(collection)

    settings.update({'camera_aspect': 'equal', 'no_axes': True})
    settings.update(kwargs)

    camera(**settings)
    decorate(**settings)

    return display(**settings)
Exemple #44
0
def detect_colour_checkers_segmentation(
    image: ArrayLike,
    samples: Integer = 16,
    additional_data: Boolean = False,
    **kwargs: Any,
) -> Union[Tuple[ColourCheckerSwatchesData, ...], Tuple[NDArray, ...]]:
    """
    Detect the colour checkers swatches in given image using segmentation.

    Parameters
    ----------
    image : array_like
        Image to detect the colour checkers swatches in.
    samples : int
        Samples count to use to compute the swatches colours. The effective
        samples count is :math:`samples^2`.
    additional_data : bool, optional
        Whether to output additional data.

    Other Parameters
    ----------------
    aspect_ratio
        Colour checker aspect ratio, e.g. 1.5.
    aspect_ratio_minimum
        Minimum colour checker aspect ratio for detection: projective geometry
        might reduce the colour checker aspect ratio.
    aspect_ratio_maximum
        Maximum colour checker aspect ratio for detection: projective geometry
        might increase the colour checker aspect ratio.
    swatches
        Colour checker swatches total count.
    swatches_horizontal
        Colour checker swatches horizontal columns count.
    swatches_vertical
        Colour checker swatches vertical row count.
    swatches_count_minimum
        Minimum swatches count to be considered for the detection.
    swatches_count_maximum
        Maximum swatches count to be considered for the detection.
    swatches_chromatic_slice
        A `slice` instance defining chromatic swatches used to detect if the
        colour checker is upside down.
    swatches_achromatic_slice
        A `slice` instance defining achromatic swatches used to detect if the
        colour checker is upside down.
    swatch_minimum_area_factor
        Swatch minimum area factor :math:`f` with the minimum area :math:`m_a`
        expressed as follows: :math:`m_a = image_w * image_h / s_c / f` where
        :math:`image_w`, :math:`image_h` and :math:`s_c` are respectively the
        image width, height and the swatches count.
    swatch_contour_scale
        As the image is filtered, the swatches area will tend to shrink, the
        generated contours can thus be scaled.
    cluster_contour_scale
        As the swatches are clustered, it might be necessary to adjust the
        cluster scale so that the masks are centred better on the swatches.
    working_width
        Size the input image is resized to for detection.
    fast_non_local_means_denoising_kwargs
        Keyword arguments for :func:`cv2.fastNlMeansDenoising` definition.
    adaptive_threshold_kwargs
        Keyword arguments for :func:`cv2.adaptiveThreshold` definition.
    interpolation_method
        Interpolation method used when resizing the images, `cv2.INTER_CUBIC`
        and `cv2.INTER_LINEAR` methods are recommended.

    Returns
    -------
    :class`tuple`
        Tuple of :class:`ColourCheckerSwatchesData` class instances or
        colour checkers swatches.

    Examples
    --------
    >>> import os
    >>> from colour import read_image
    >>> from colour_checker_detection import TESTS_RESOURCES_DIRECTORY
    >>> path = os.path.join(TESTS_RESOURCES_DIRECTORY,
    ...                     'colour_checker_detection', 'detection',
    ...                     'IMG_1967.png')
    >>> image = read_image(path)
    >>> detect_colour_checkers_segmentation(image)  # doctest: +SKIP
    (array([[ 0.361626... ,  0.2241066...,  0.1187837...],
           [ 0.6280594...,  0.3950883...,  0.2434766...],
           [ 0.3326232...,  0.3156182...,  0.2891038...],
           [ 0.3048414...,  0.2738973...,  0.1069985...],
           [ 0.4174869...,  0.3199669...,  0.3081552...],
           [ 0.347873 ...,  0.4413193...,  0.2931614...],
           [ 0.6816301...,  0.3539050...,  0.0753397...],
           [ 0.2731050...,  0.2528467...,  0.3312920...],
           [ 0.6192335...,  0.2703833...,  0.1866387...],
           [ 0.3068567...,  0.1803366...,  0.1919807...],
           [ 0.4866354...,  0.4594004...,  0.0374186...],
           [ 0.6518523...,  0.4010608...,  0.0171886...],
           [ 0.1941571...,  0.1855801...,  0.2750632...],
           [ 0.2799946...,  0.3854609...,  0.1241038...],
           [ 0.5537481...,  0.2139004...,  0.1267332...],
           [ 0.7208045...,  0.5152904...,  0.0061946...],
           [ 0.5778360...,  0.2578533...,  0.2687992...],
           [ 0.1809450...,  0.3174742...,  0.2959902...],
           [ 0.7427522...,  0.6107554...,  0.4398439...],
           [ 0.6296108...,  0.5177606...,  0.3728032...],
           [ 0.5139589...,  0.4216307...,  0.2992694...],
           [ 0.3704401...,  0.3033927...,  0.2093089...],
           [ 0.2641854...,  0.2154007...,  0.1441267...],
           [ 0.1650098...,  0.1345239...,  0.0817437...]], dtype=float32),)
    """

    image = as_float_array(image, FLOAT_DTYPE_DEFAULT)[..., :3]

    settings = Structure(**SETTINGS_SEGMENTATION_COLORCHECKER_CLASSIC)
    settings.update(**kwargs)

    image = adjust_image(image, settings.working_width,
                         settings.interpolation_method)

    swatches_h, swatches_v = (
        settings.swatches_horizontal,
        settings.swatches_vertical,
    )

    colour_checkers_colours = []
    colour_checkers_data = []
    for colour_checker in extract_colour_checkers_segmentation(
            image, **settings):
        width, height = colour_checker.shape[1], colour_checker.shape[0]
        masks = swatch_masks(width, height, swatches_h, swatches_v, samples)

        swatch_colours = []
        for mask in masks:
            swatch_colours.append(
                np.mean(
                    colour_checker[mask[0]:mask[1], mask[2]:mask[3], ...],
                    axis=(0, 1),
                ))

        # The colour checker might be flipped: The mean standard deviation
        # of some expected normalised chromatic and achromatic neutral
        # swatches is computed. If the chromatic mean is lesser than the
        # achromatic mean, it means that the colour checker is flipped.
        std_means = []
        for slice_ in [
                settings.swatches_chromatic_slice,
                settings.swatches_achromatic_slice,
        ]:
            swatch_std_mean = as_float_array(swatch_colours[slice_])
            swatch_std_mean /= swatch_std_mean[..., 1][..., np.newaxis]
            std_means.append(np.mean(np.std(swatch_std_mean, 0)))
        if std_means[0] < std_means[1]:
            usage_warning("Colour checker was seemingly flipped,"
                          " reversing the samples!")
            swatch_colours = swatch_colours[::-1]

        colour_checkers_colours.append(np.asarray(swatch_colours))
        colour_checkers_data.append((colour_checker, masks))

    if additional_data:
        return tuple(
            ColourCheckerSwatchesData(tuple(colour_checkers_colours[i]), *
                                      colour_checkers_data[i]) for i,
            colour_checker_colours in enumerate(colour_checkers_colours))
    else:
        return tuple(colour_checkers_colours)
Exemple #45
0
def extract_colour_checkers_segmentation(image: ArrayLike,
                                         **kwargs: Any) -> Tuple[NDArray, ...]:
    """
    Extract the colour checkers sub-images in given image using segmentation.

    Parameters
    ----------
    image
        Image to extract the colours checkers sub-images from.

    Other Parameters
    ----------------
    aspect_ratio
        Colour checker aspect ratio, e.g. 1.5.
    aspect_ratio_minimum
        Minimum colour checker aspect ratio for detection: projective geometry
        might reduce the colour checker aspect ratio.
    aspect_ratio_maximum
        Maximum colour checker aspect ratio for detection: projective geometry
        might increase the colour checker aspect ratio.
    swatches
        Colour checker swatches total count.
    swatches_horizontal
        Colour checker swatches horizontal columns count.
    swatches_vertical
        Colour checker swatches vertical row count.
    swatches_count_minimum
        Minimum swatches count to be considered for the detection.
    swatches_count_maximum
        Maximum swatches count to be considered for the detection.
    swatches_chromatic_slice
        A `slice` instance defining chromatic swatches used to detect if the
        colour checker is upside down.
    swatches_achromatic_slice
        A `slice` instance defining achromatic swatches used to detect if the
        colour checker is upside down.
    swatch_minimum_area_factor
        Swatch minimum area factor :math:`f` with the minimum area :math:`m_a`
        expressed as follows: :math:`m_a = image_w * image_h / s_c / f` where
        :math:`image_w`, :math:`image_h` and :math:`s_c` are respectively the
        image width, height and the swatches count.
    swatch_contour_scale
        As the image is filtered, the swatches area will tend to shrink, the
        generated contours can thus be scaled.
    cluster_contour_scale
        As the swatches are clustered, it might be necessary to adjust the
        cluster scale so that the masks are centred better on the swatches.
    working_width
        Size the input image is resized to for detection.
    fast_non_local_means_denoising_kwargs
        Keyword arguments for :func:`cv2.fastNlMeansDenoising` definition.
    adaptive_threshold_kwargs
        Keyword arguments for :func:`cv2.adaptiveThreshold` definition.
    interpolation_method
        Interpolation method used when resizing the images, `cv2.INTER_CUBIC`
        and `cv2.INTER_LINEAR` methods are recommended.

    Returns
    -------
    :class:`tuple`
        Tuple of colour checkers sub-images.

    Examples
    --------
    >>> import os
    >>> from colour import read_image
    >>> from colour_checker_detection import TESTS_RESOURCES_DIRECTORY
    >>> path = os.path.join(TESTS_RESOURCES_DIRECTORY,
    ...                     'colour_checker_detection', 'detection',
    ...                     'IMG_1967.png')
    >>> image = read_image(path)
    >>> extract_colour_checkers_segmentation(image)
    ... # doctest: +SKIP
    (array([[[ 0.17908671,  0.14010708,  0.09243158],
            [ 0.17805016,  0.13058874,  0.09513047],
            [ 0.17175764,  0.13128328,  0.08811688],
            ...,
            [ 0.15934898,  0.13436384,  0.07479276],
            [ 0.17178158,  0.13138185,  0.07703256],
            [ 0.15082785,  0.11866678,  0.07680314]],
    <BLANKLINE>
           [[ 0.16597673,  0.13563241,  0.08780421],
            [ 0.16490564,  0.13110894,  0.08601525],
            [ 0.16939694,  0.12963502,  0.08783565],
            ...,
            [ 0.14708202,  0.12856133,  0.0814603 ],
            [ 0.16883563,  0.12862256,  0.08452422],
            [ 0.16781917,  0.12363558,  0.07361614]],
    <BLANKLINE>
           [[ 0.16326806,  0.13720085,  0.08925959],
            [ 0.16014062,  0.13585283,  0.08104862],
            [ 0.16657823,  0.12889633,  0.08870038],
            ...,
            [ 0.14619341,  0.13086307,  0.07367594],
            [ 0.16302426,  0.13062705,  0.07938427],
            [ 0.16618022,  0.1266259 ,  0.07200021]],
    <BLANKLINE>
           ...,
           [[ 0.1928642 ,  0.14578913,  0.11224515],
            [ 0.18931177,  0.14416392,  0.10288388],
            [ 0.17707473,  0.1436448 ,  0.09188452],
            ...,
            [ 0.16879168,  0.12867133,  0.09001681],
            [ 0.1699731 ,  0.1287041 ,  0.07616285],
            [ 0.17137891,  0.129711  ,  0.07517841]],
    <BLANKLINE>
           [[ 0.19514292,  0.1532704 ,  0.10375113],
            [ 0.18217109,  0.14982903,  0.10452617],
            [ 0.18830594,  0.1469499 ,  0.10896181],
            ...,
            [ 0.18234864,  0.12642328,  0.08047272],
            [ 0.17617388,  0.13000189,  0.06874527],
            [ 0.17108543,  0.13264084,  0.06309374]],
    <BLANKLINE>
           [[ 0.16243187,  0.14983535,  0.08954653],
            [ 0.155507  ,  0.14899652,  0.10273992],
            [ 0.17993385,  0.1498394 ,  0.1099571 ],
            ...,
            [ 0.18079454,  0.1253967 ,  0.07739887],
            [ 0.17239226,  0.13181566,  0.07806754],
            [ 0.17422497,  0.13277327,  0.07513551]]], dtype=float32),)
    """

    image = as_float_array(image, FLOAT_DTYPE_DEFAULT)[..., :3]

    settings = Structure(**SETTINGS_SEGMENTATION_COLORCHECKER_CLASSIC)
    settings.update(**kwargs)

    image = adjust_image(image, settings.working_width,
                         settings.interpolation_method)

    colour_checkers = []
    for rectangle in cast(
            List[NDArray],
            colour_checkers_coordinates_segmentation(image, **settings),
    ):
        colour_checker = crop_and_level_image_with_rectangle(
            image, cv2.minAreaRect(rectangle), settings.interpolation_method)
        width, height = (colour_checker.shape[1], colour_checker.shape[0])

        if width < height:
            colour_checker = cv2.rotate(colour_checker,
                                        cv2.ROTATE_90_CLOCKWISE)

        colour_checkers.append(colour_checker)

    return tuple(colour_checkers)
Exemple #46
0
def nadir_grid(limits=None, segments=10, labels=None, axes=None, **kwargs):
    """
    Returns a grid on *xy* plane made of quad geometric elements and its
    associated faces and edges colours. Ticks and labels are added to the
    given axes according to the extended grid settings.

    Parameters
    ----------
    limits : array_like, optional
        Extended grid limits.
    segments : int, optional
        Edge segments count for the extended grid.
    labels : array_like, optional
        Axis labels.
    axes : matplotlib.axes.Axes, optional
        Axes to add the grid.

    Other Parameters
    ----------------
    grid_face_colours : array_like, optional
        Grid face colours array such as
        `grid_face_colours = (0.25, 0.25, 0.25)`.
    grid_edge_colours : array_like, optional
        Grid edge colours array such as
        `grid_edge_colours = (0.25, 0.25, 0.25)`.
    grid_face_alpha : numeric, optional
        Grid face opacity value such as `grid_face_alpha = 0.1`.
    grid_edge_alpha : numeric, optional
        Grid edge opacity value such as `grid_edge_alpha = 0.5`.
    x_axis_colour : array_like, optional
        *X* axis colour array such as `x_axis_colour = (0.0, 0.0, 0.0, 1.0)`.
    y_axis_colour : array_like, optional
        *Y* axis colour array such as `y_axis_colour = (0.0, 0.0, 0.0, 1.0)`.
    x_ticks_colour : array_like, optional
        *X* axis ticks colour array such as
        `x_ticks_colour = (0.0, 0.0, 0.0, 0.85)`.
    y_ticks_colour : array_like, optional
        *Y* axis ticks colour array such as
        `y_ticks_colour = (0.0, 0.0, 0.0, 0.85)`.
    x_label_colour : array_like, optional
        *X* axis label colour array such as
        `x_label_colour = (0.0, 0.0, 0.0, 0.85)`.
    y_label_colour : array_like, optional
        *Y* axis label colour array such as
        `y_label_colour = (0.0, 0.0, 0.0, 0.85)`.
    ticks_and_label_location : array_like, optional
        Location of the *X* and *Y* axis ticks and labels such as
        `ticks_and_label_location = ('-x', '-y')`.

    Returns
    -------
    tuple
        Grid quads, faces colours, edges colours.

    Examples
    --------
    >>> nadir_grid(segments=1)
    (array([[[-1.   , -1.   ,  0.   ],
            [ 1.   , -1.   ,  0.   ],
            [ 1.   ,  1.   ,  0.   ],
            [-1.   ,  1.   ,  0.   ]],
    <BLANKLINE>
           [[-1.   , -1.   ,  0.   ],
            [ 0.   , -1.   ,  0.   ],
            [ 0.   ,  0.   ,  0.   ],
            [-1.   ,  0.   ,  0.   ]],
    <BLANKLINE>
           [[-1.   ,  0.   ,  0.   ],
            [ 0.   ,  0.   ,  0.   ],
            [ 0.   ,  1.   ,  0.   ],
            [-1.   ,  1.   ,  0.   ]],
    <BLANKLINE>
           [[ 0.   , -1.   ,  0.   ],
            [ 1.   , -1.   ,  0.   ],
            [ 1.   ,  0.   ,  0.   ],
            [ 0.   ,  0.   ,  0.   ]],
    <BLANKLINE>
           [[ 0.   ,  0.   ,  0.   ],
            [ 1.   ,  0.   ,  0.   ],
            [ 1.   ,  1.   ,  0.   ],
            [ 0.   ,  1.   ,  0.   ]],
    <BLANKLINE>
           [[-1.   , -0.001,  0.   ],
            [ 1.   , -0.001,  0.   ],
            [ 1.   ,  0.001,  0.   ],
            [-1.   ,  0.001,  0.   ]],
    <BLANKLINE>
           [[-0.001, -1.   ,  0.   ],
            [ 0.001, -1.   ,  0.   ],
            [ 0.001,  1.   ,  0.   ],
            [-0.001,  1.   ,  0.   ]]]), array([[ 0.25,  0.25,  0.25,  0.1 ],
           [ 0.  ,  0.  ,  0.  ,  0.  ],
           [ 0.  ,  0.  ,  0.  ,  0.  ],
           [ 0.  ,  0.  ,  0.  ,  0.  ],
           [ 0.  ,  0.  ,  0.  ,  0.  ],
           [ 0.  ,  0.  ,  0.  ,  1.  ],
           [ 0.  ,  0.  ,  0.  ,  1.  ]]), array([[ 0.5 ,  0.5 ,  0.5 ,  0.5 ],
           [ 0.75,  0.75,  0.75,  0.25],
           [ 0.75,  0.75,  0.75,  0.25],
           [ 0.75,  0.75,  0.75,  0.25],
           [ 0.75,  0.75,  0.75,  0.25],
           [ 0.  ,  0.  ,  0.  ,  1.  ],
           [ 0.  ,  0.  ,  0.  ,  1.  ]]))
    """

    if limits is None:
        limits = np.array([[-1, 1], [-1, 1]])

    if labels is None:
        labels = ('x', 'y')

    extent = np.max(np.abs(limits[..., 1] - limits[..., 0]))

    settings = Structure(
        **{
            'grid_face_colours': (0.25, 0.25, 0.25),
            'grid_edge_colours': (0.50, 0.50, 0.50),
            'grid_face_alpha': 0.1,
            'grid_edge_alpha': 0.5,
            'x_axis_colour': (0.0, 0.0, 0.0, 1.0),
            'y_axis_colour': (0.0, 0.0, 0.0, 1.0),
            'x_ticks_colour': (0.0, 0.0, 0.0, 0.85),
            'y_ticks_colour': (0.0, 0.0, 0.0, 0.85),
            'x_label_colour': (0.0, 0.0, 0.0, 0.85),
            'y_label_colour': (0.0, 0.0, 0.0, 0.85),
            'ticks_and_label_location': ('-x', '-y')
        })
    settings.update(**kwargs)

    # Outer grid.
    quads_g = grid(
        origin=(-extent / 2, -extent / 2),
        width=extent,
        height=extent,
        height_segments=segments,
        width_segments=segments)

    RGB_g = np.ones((quads_g.shape[0], quads_g.shape[-1]))
    RGB_gf = RGB_g * settings.grid_face_colours
    RGB_gf = np.hstack([
        RGB_gf,
        np.full((RGB_gf.shape[0], 1), settings.grid_face_alpha,
                DEFAULT_FLOAT_DTYPE)
    ])
    RGB_ge = RGB_g * settings.grid_edge_colours
    RGB_ge = np.hstack([
        RGB_ge,
        np.full((RGB_ge.shape[0], 1), settings.grid_edge_alpha,
                DEFAULT_FLOAT_DTYPE)
    ])

    # Inner grid.
    quads_gs = grid(
        origin=(-extent / 2, -extent / 2),
        width=extent,
        height=extent,
        height_segments=segments * 2,
        width_segments=segments * 2)

    RGB_gs = np.ones((quads_gs.shape[0], quads_gs.shape[-1]))
    RGB_gsf = RGB_gs * 0
    RGB_gsf = np.hstack(
        [RGB_gsf,
         np.full((RGB_gsf.shape[0], 1), 0, DEFAULT_FLOAT_DTYPE)])
    RGB_gse = np.clip(RGB_gs * settings.grid_edge_colours * 1.5, 0, 1)
    RGB_gse = np.hstack(
        (RGB_gse,
         np.full((RGB_gse.shape[0], 1), settings.grid_edge_alpha / 2,
                 DEFAULT_FLOAT_DTYPE)))

    # Axis.
    thickness = extent / 1000
    quad_x = grid(
        origin=(limits[0, 0], -thickness / 2), width=extent, height=thickness)
    RGB_x = np.ones((quad_x.shape[0], quad_x.shape[-1] + 1))
    RGB_x = RGB_x * settings.x_axis_colour

    quad_y = grid(
        origin=(-thickness / 2, limits[1, 0]), width=thickness, height=extent)
    RGB_y = np.ones((quad_y.shape[0], quad_y.shape[-1] + 1))
    RGB_y = RGB_y * settings.y_axis_colour

    if axes is not None:
        # Ticks.
        x_s = 1 if '+x' in settings.ticks_and_label_location else -1
        y_s = 1 if '+y' in settings.ticks_and_label_location else -1
        for i, axis in enumerate('xy'):
            h_a = 'center' if axis == 'x' else 'left' if x_s == 1 else 'right'
            v_a = 'center'

            ticks = list(sorted(set(quads_g[..., 0, i])))
            ticks += [ticks[-1] + ticks[-1] - ticks[-2]]
            for tick in ticks:
                x = (limits[1, 1 if x_s == 1 else 0] + (x_s * extent / 25)
                     if i else tick)
                y = (tick if i else
                     limits[0, 1 if y_s == 1 else 0] + (y_s * extent / 25))

                tick = DEFAULT_INT_DTYPE(tick) if DEFAULT_FLOAT_DTYPE(
                    tick).is_integer() else tick
                c = settings['{0}_ticks_colour'.format(axis)]

                axes.text(
                    x,
                    y,
                    0,
                    tick,
                    'x',
                    horizontalalignment=h_a,
                    verticalalignment=v_a,
                    color=c,
                    clip_on=True)

        # Labels.
        for i, axis in enumerate('xy'):
            h_a = 'center' if axis == 'x' else 'left' if x_s == 1 else 'right'
            v_a = 'center'

            x = (limits[1, 1 if x_s == 1 else 0] + (x_s * extent / 10)
                 if i else 0)
            y = (0 if i else
                 limits[0, 1 if y_s == 1 else 0] + (y_s * extent / 10))

            c = settings['{0}_label_colour'.format(axis)]

            axes.text(
                x,
                y,
                0,
                labels[i],
                'x',
                horizontalalignment=h_a,
                verticalalignment=v_a,
                color=c,
                size=20,
                clip_on=True)

    quads = np.vstack([quads_g, quads_gs, quad_x, quad_y])
    RGB_f = np.vstack([RGB_gf, RGB_gsf, RGB_x, RGB_y])
    RGB_e = np.vstack([RGB_ge, RGB_gse, RGB_x, RGB_y])

    return quads, RGB_f, RGB_e
Exemple #47
0
def decorate(**kwargs):
    """
    Sets the figure decorations.

    Parameters
    ----------
    \**kwargs : dict, optional
        **{'title', 'x_label', 'y_label', 'legend', 'legend_columns',
        'legend_location', 'x_ticker', 'y_ticker', 'x_ticker_locator',
        'y_ticker_locator', 'grid', 'grid_which', 'grid_axis', 'x_axis_line',
        'y_axis_line', 'aspect', 'no_axes'}**
        Keywords arguments such as ``{'title': unicode (figure title),
        'x_label': unicode (X axis label), 'y_label': unicode (Y axis label),
        'legend': bool, 'legend_columns': int, 'legend_location': unicode
        (Matplotlib legend location), 'x_ticker': bool, 'y_ticker': bool,
        'x_ticker_locator': Locator, 'y_ticker_locator': Locator, 'grid': bool,
        'grid_which': unicode, 'grid_axis': unicode, 'x_axis_line': bool,
        'y_axis_line': bool, 'aspect': unicode (Matplotlib axes aspect),
        'no_axes': bool}``

    Returns
    -------
    Axes
        Current axes.
    """

    settings = Structure(
        **{'title': None,
           'x_label': None,
           'y_label': None,
           'legend': False,
           'legend_columns': 1,
           'legend_location': 'upper right',
           'x_ticker': True,
           'y_ticker': True,
           'x_ticker_locator': matplotlib.ticker.AutoMinorLocator(2),
           'y_ticker_locator': matplotlib.ticker.AutoMinorLocator(2),
           'grid': False,
           'grid_which': 'both',
           'grid_axis': 'both',
           'x_axis_line': False,
           'y_axis_line': False,
           'aspect': None,
           'no_axes': False})
    settings.update(kwargs)

    axes = matplotlib.pyplot.gca()
    if settings.title:
        pylab.title(settings.title)
    if settings.x_label:
        pylab.xlabel(settings.x_label)
    if settings.y_label:
        pylab.ylabel(settings.y_label)
    if settings.legend:
        pylab.legend(loc=settings.legend_location,
                     ncol=settings.legend_columns)
    if settings.x_ticker:
        axes.xaxis.set_minor_locator(
            settings.x_ticker_locator)
    else:
        axes.set_xticks([])
    if settings.y_ticker:
        axes.yaxis.set_minor_locator(
            settings.y_ticker_locator)
    else:
        axes.set_yticks([])
    if settings.grid:
        pylab.grid(which=settings.grid_which, axis=settings.grid_axis)
    if settings.x_axis_line:
        pylab.axvline(color='black', linestyle='--')
    if settings.y_axis_line:
        pylab.axhline(color='black', linestyle='--')
    if settings.aspect:
        matplotlib.pyplot.axes().set_aspect(settings.aspect)
    if settings.no_axes:
        axes.set_axis_off()

    return axes
Exemple #48
0
def plot_RGB_scatter(RGB,
                     colourspace,
                     reference_colourspace='CIE xyY',
                     colourspaces=None,
                     segments=8,
                     show_grid=True,
                     grid_segments=10,
                     show_spectral_locus=False,
                     spectral_locus_colour=None,
                     points_size=12,
                     cmfs='CIE 1931 2 Degree Standard Observer',
                     **kwargs):
    """
    Plots given *RGB* colourspace array in a scatter plot.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    colourspace : RGB_Colourspace
        *RGB* colourspace of the *RGB* array.
    reference_colourspace : unicode, optional
        **{'CIE XYZ', 'CIE xyY', 'CIE xy', 'CIE Lab', 'CIE LCHab', 'CIE Luv',
        'CIE Luv uv', 'CIE LCHuv', 'CIE UCS', 'CIE UCS uv', 'CIE UVW',
        'DIN 99', 'Hunter Lab', 'Hunter Rdab', 'IPT', 'JzAzBz', 'OSA UCS',
        'hdr-CIELAB', 'hdr-IPT'}**,
        Reference colourspace for colour conversion.
    colourspaces : array_like, optional
        *RGB* colourspaces to plot the gamuts.
    segments : int, optional
        Edge segments count for each *RGB* colourspace cubes.
    show_grid : bool, optional
        Whether to show a grid at the bottom of the *RGB* colourspace cubes.
    grid_segments : bool, optional
        Edge segments count for the grid.
    show_spectral_locus : bool, optional
        Whether to show the spectral locus.
    spectral_locus_colour : array_like, optional
        Spectral locus colour.
    points_size : numeric, optional
        Scatter points size.
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectral locus.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.plot_RGB_colourspaces_gamuts`},
        Please refer to the documentation of the previously listed definitions.

    Returns
    -------
    tuple
        Current figure and axes.

    Examples
    --------
    >>> RGB = np.random.random((128, 128, 3))
    >>> plot_RGB_scatter(RGB, 'ITU-R BT.709')  # doctest: +SKIP

    .. image:: ../_static/Plotting_Plot_RGB_Scatter.png
        :align: center
        :alt: plot_RGB_scatter
    """

    colourspace = first_item(filter_RGB_colourspaces(colourspace).values())

    if colourspaces is None:
        colourspaces = (colourspace.name, )

    count_c = len(colourspaces)
    settings = Structure(
        **{
            'face_colours': [None] * count_c,
            'edge_colours': [(0.25, 0.25, 0.25)] * count_c,
            'face_alpha': [0.0] * count_c,
            'edge_alpha': [0.1] * count_c,
        })
    settings.update(kwargs)
    settings['standalone'] = False

    plot_RGB_colourspaces_gamuts(
        colourspaces=colourspaces,
        reference_colourspace=reference_colourspace,
        segments=segments,
        show_grid=show_grid,
        grid_segments=grid_segments,
        show_spectral_locus=show_spectral_locus,
        spectral_locus_colour=spectral_locus_colour,
        cmfs=cmfs,
        **settings)

    XYZ = RGB_to_XYZ(RGB, colourspace.whitepoint, colourspace.whitepoint,
                     colourspace.RGB_to_XYZ_matrix)

    points = common_colourspace_model_axis_reorder(
        XYZ_to_colourspace_model(XYZ, colourspace.whitepoint,
                                 reference_colourspace), reference_colourspace)

    axes = plt.gca()
    axes.scatter(
        points[..., 0],
        points[..., 1],
        points[..., 2],
        color=np.reshape(RGB, (-1, 3)),
        s=points_size)

    settings.update({'axes': axes, 'standalone': True})
    settings.update(kwargs)

    return render(**settings)
Exemple #49
0
def render(**kwargs):
    """
    Renders the current figure while adjusting various settings such as the
    bounding box, the title or background transparency.

    Other Parameters
    ----------------
    figure : Figure, optional
        Figure to apply the render elements onto.
    axes : Axes, optional
        Axes to apply the render elements onto.
    filename : unicode, optional
        Figure will be saved using given ``filename`` argument.
    standalone : bool, optional
        Whether to show the figure and call :func:`plt.show` definition.
    aspect : unicode, optional
        Matplotlib axes aspect.
    axes_visible : bool, optional
        Whether the axes are visible. Default is *True*.
    bounding_box : array_like, optional
        Array defining current axes limits such
        `bounding_box = (x min, x max, y min, y max)`.
    tight_layout : bool, optional
        Whether to invoke the :func:`plt.tight_layout` definition.
    legend : bool, optional
        Whether to display the legend. Default is *False*.
    legend_columns : int, optional
        Number of columns in the legend. Default is *1*.
    transparent_background : bool, optional
        Whether to turn off the background patch. Default is *False*.
    title : unicode, optional
        Figure title.
    wrap_title : unicode, optional
        Whether to wrap the figure title, the default is to wrap at a number
        of characters equal to the width of the figure multiplied by 10.
    x_label : unicode, optional
        *X* axis label.
    y_label : unicode, optional
        *Y* axis label.
    x_ticker : bool, optional
        Whether to display the *X* axis ticker. Default is *True*.
    y_ticker : bool, optional
        Whether to display the *Y* axis ticker. Default is *True*.

    Returns
    -------
    tuple
        Current figure and axes.
    """

    figure = kwargs.get('figure')
    if figure is None:
        figure = plt.gcf()

    axes = kwargs.get('axes')
    if axes is None:
        axes = plt.gca()

    settings = Structure(
        **{
            'filename': None,
            'standalone': True,
            'aspect': None,
            'axes_visible': True,
            'bounding_box': None,
            'tight_layout': True,
            'legend': False,
            'legend_columns': 1,
            'transparent_background': True,
            'title': None,
            'wrap_title': True,
            'x_label': None,
            'y_label': None,
            'x_ticker': True,
            'y_ticker': True,
        })
    settings.update(kwargs)

    if settings.aspect:
        axes.set_aspect(settings.aspect)
    if not settings.axes_visible:
        axes.set_axis_off()
    if settings.bounding_box:
        axes.set_xlim(settings.bounding_box[0], settings.bounding_box[1])
        axes.set_ylim(settings.bounding_box[2], settings.bounding_box[3])

    if settings.title:
        title = settings.title
        if settings.wrap_title:
            title = wrap_label(settings.title,
                               int(plt.rcParams['figure.figsize'][0] * 10))
        axes.set_title(title)
    if settings.x_label:
        axes.set_xlabel(settings.x_label)
    if settings.y_label:
        axes.set_ylabel(settings.y_label)
    if not settings.x_ticker:
        axes.set_xticks([])
    if not settings.y_ticker:
        axes.set_yticks([])
    if settings.legend:
        axes.legend(ncol=settings.legend_columns)

    if settings.tight_layout:
        figure.tight_layout()

    if settings.transparent_background:
        figure.patch.set_alpha(0)
    if settings.standalone:
        if settings.filename is not None:
            figure.savefig(settings.filename)
        else:
            plt.show()

    return figure, axes