Exemple #1
0
	def draw(self, data, wordspacing=0.005, lineheight=1.25,
			 align='left', with_legend=True, lpad=0, rpad=0, tpad=0, *args, **kwargs):
		"""
		Draw the text annotation visualization.
		The method receives text as a list of tokens and draws them as text.

		The text can be provided either as a string, a list of strings or as dictionaries.
		If strings are provided, the function converts them into dictionaries.
		Dictionaries should have the following format:

		.. code-block:: python

			{
			  'label': None,
			  'style': { 'facecolor': 'None' },
			  'text': 'token',
			}

		Of these keys, only `text` is required.
		The correct styling options are those accepted by the :class:`matplotlib.text.Text` class.
		Anything not given uses default values.

		Any other styling options, common to all tokens, should be provided as keyword arguments.

		:param data: The text data.
					 The visualization expects a string, a `list` of tokens, or a `list` of `dict` instances as shown above.
		:type data: str or list of str or list of dict
		:param wordspacing: The space between words.
		:type wordspacing: float
		:param lineheight: The space between lines.
		:type lineheight: float
		:param align: The text's alignment.
					  Possible values:

					    - left
					    - center
					    - right
					    - justify
					    - justify-start (or justify-left)
					    - justify-center
					    - justify-end or (justify-right)
		:type align: str
		:param with_legend: A boolean indicating whether labels should create a legend.
		:type with_legend: bool
		:param lpad: The left padding as a percentage of the plot.
					 The range is expected to be between 0 and 1.
		:type lpad: float
		:param rpad: The right padding as a percentage of the plot.
					 The range is expected to be between 0 and 1.
		:type rpad: float
		:param tpad: The top padding as a percentage of the plot.
					 The range is expected to be between 0 and 1.
		:type tpad: float

		:return: The drawn lines.
				 Each line is made up of tuples of lists.
				 The first list in each tuple is the list of legend labels.
				 The second list in each tuple is the list of actual tokens.
		:rtype: list of tuple

		:raises: ValueError
		"""

		figure = self.drawable.figure
		axis = self.drawable.axis

		"""
		Validate the arguments.
		All padding arguments should be non-negative.
		The left-padding and the right-padding should not overlap.
		"""
		if lpad < 0:
			raise ValueError("The left padding should be between 0 and 1, received %d" % lpad)

		if rpad < 0:
			raise ValueError("The right padding should be between 0 and 1, received %d" % rpad)

		if lpad + rpad >= 1:
			raise ValueError("The left and right padding should not overlap, received %d left padding and %d right padding" % (lpad, rpad))

		"""
		Gradually convert text inputs to dictionary inputs: from `str` to `list`, and from `list` to `dict`.
		"""
		tokens = data.split() if type(data) is str else data
		tokens = [ { 'text': token } if type(token) is str else token for token in tokens ]

		"""
		Draw the text as an annotation first.
		"""
		annotation = Annotation(self.drawable)
		lines = annotation.draw(tokens, (lpad, axis.get_xlim()[1] - rpad), 0,
								 wordspacing=wordspacing, lineheight=lineheight,
								 align=align, va='top', *args, **kwargs)

		"""
		Draw a legend if it is requested.
		"""
		linespacing = util.get_linespacing(figure, axis, wordspacing, *args, **kwargs)
		labels = self._draw_legend(tokens, lines, wordspacing, linespacing,
								   *args, **kwargs) if with_legend else [ [] ] * len(lines)

		"""
		The entire visualization is shifted so that the legends start at x-coordinate 0.
		This way, the title is aligned with the visualization.
		This process is meant to tighten the layout.
		The axis is turned off since it has no purpose, and the y-limit is re-calculated.
		"""
		drawn_lines = list(zip(labels, lines))
		self._tighten(drawn_lines)
		axis.axis('off')
		axis.set_ylim(- len(lines) * linespacing, tpad + linespacing)

		return drawn_lines
Exemple #2
0
    def draw(self, annotation, wordspacing=0.005, lineheight=1.25,
             align='left', with_legend=True, lpad=0, rpad=0, tpad=0, *args, **kwargs):
        """
        Draw the text annotation visualization.

        The method expects, at least, the text annotation.
        You can pass on the text as a string, or segment the text into tokens yourself and pass them on as a ``list``.

        You can also split the text into words and pass them on as ``dict`` instances to style them individually.
        Dictionaries should have the following format:

        .. code-block:: python

            {
              'text': 'token',
              'style': { 'facecolor': 'None' },
              'label': None
            }

        Of these keys, only the ``text`` is required.

        You can use the ``style`` to override the general styling options, which you can specify as ``kwargs``.
        Once again, the accepted styling options are those supported by the `matplotlib.text.Text <https://matplotlib.org/3.2.2/api/text_api.html#matplotlib.text.Text>`_ class.

        Use the ``kwargs`` as a general style, and the dictionary's ``style`` as a specific style for each word.
        If you specify a ``kwargs`` styling option, but it is missing from the dictionary's ``style``, the general style is used.

        .. note::

            For example, imagine you specify the text ``color`` to be ``blue`` and the ``fontsize`` to be ``12`` in the ``**kwargs``.
            If in the dictionary's ``style`` of a particular word you set the ``color`` to be ``red``, its color will be ``red``.
            However, since the ``fontsize`` is not specified, it will use the general font size: ``12``.

        The last key is the ``label``.
        If you set a ``label``, Multiplex automatically creates a legend for you.

        :param annotation: The text annotation.
                     The visualization expects a string, a `list` of tokens, or a `list` of `dict` instances as shown above.
        :type annotation: str or list of str or list of dict
        :param wordspacing: The space between words.
        :type wordspacing: float
        :param lineheight: The space between lines.
        :type lineheight: float
        :param align: The text's alignment.
                      Possible values:

                          - ``left``
                          - ``center``
                          - ``right``
                          - ``justify``
                          - ``justify-start`` (or ``justify-left``)
                          - ``justify-center``
                          - ``justify-end`` or (``justify-right``)
        :type align: str
        :param with_legend: A boolean indicating whether the visualization should create a legend when it finds labels.
        :type with_legend: bool
        :param lpad: The left padding as a fraction of the plot.
                     The range is expected to be between 0 and 1.
        :type lpad: float
        :param rpad: The right padding as a fraction of the plot.
                     The range is expected to be between 0 and 1.
        :type rpad: float
        :param tpad: The top padding as a percentage of the plot.
        :type tpad: float

        :return: The drawn lines.
                 Each line is made up of tuples, and each tuple is made up of:

                     1. The list of legend labels in the line, and
                     2. The list of tokens drawn in the line.
        :rtype: list of tuple

        :raises ValueError: When the left padding is not between 0 and 1.
        :raises ValueError: When the right padding is not between 0 and 1.
        :raises ValueError: When the left padding and the right padding combined are larger than 1.
        """

        figure = self.drawable.figure
        axes = self.drawable.axes

        """
        Validate the arguments.
        All padding arguments should be non-negative.
        The left-padding and the right-padding should not overlap.
        """
        if not 0 <= lpad <= 1:
            raise ValueError("The left padding should be between 0 and 1, received %d" % lpad)

        if not 0 <= rpad <= 1:
            raise ValueError("The right padding should be between 0 and 1, received %d" % rpad)

        if lpad + rpad >= 1:
            raise ValueError("The left and right padding should not overlap, received %d left padding and %d right padding" % (lpad, rpad))

        """
        Gradually convert text inputs to dictionary inputs: from `str` to `list`, and from `list` to `dict`.
        """
        tokens = annotation.split() if type(annotation) is str else annotation
        tokens = [ { 'text': token } if type(token) is str else token for token in tokens ]

        """
        Draw the text as an annotation first.
        """
        annotation = Annotation(self.drawable, tokens, (lpad, axes.get_xlim()[1] - rpad), 0,
                                wordspacing=wordspacing, lineheight=lineheight,
                                align=align, va='top', *args, **kwargs)
        lines = annotation.draw()

        """
        Draw a legend if it is requested.
        """
        linespacing = text_util.get_linespacing(figure, axes, wordspacing, *args, **kwargs)
        labels = self._draw_legend(tokens, lines, wordspacing, linespacing,
                                   *args, **kwargs) if with_legend else [ [] ] * len(lines)

        """
        The entire visualization is shifted so that the legends start at x-coordinate 0.
        This way, the title is aligned with the visualization.
        This process is meant to tighten the layout.
        The axes is turned off since it has no purpose, and the y-limit is re-calculated.
        """
        drawn_lines = list(zip(labels, lines))
        self._tighten(drawn_lines)
        axes.axis('off')
        axes.set_ylim(- len(lines) * linespacing, tpad + linespacing)

        return drawn_lines