Exemplo n.º 1
0
    def draw_annotation(self, label, x, y, va='bottom', *args, **kwargs):
        """
		Get the annotation for the legend.
		The arguments and keyword arguments are passed on to the :meth:`~text.annotation.Annotation.draw` function.

		:param label: The text of the legend label.
		:type label: str
		:param x: The starting x-coordinate of the annotation.
		:type x: float
		:param y: The y-coordinate of the annotation.
		:type y: float
		:param va: The vertical alignment, can be one of `top`, `center` or `bottom`.
				   If the vertical alignment is `top`, the given y-coordinate becomes the highest point of the annotation.
				   If the vertical alignment is `center`, the given y-coordinate becomes the center point of the annotation.
				   If the vertical alignment is `bottom`, the given y-coordinate becomes the lowest point of the annotation.
		:type va: str

		:return: The drawn annotation.
		:rtype: :class:`~text.annotation.Annotation`
		"""

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

        annotation = Annotation(self.drawable)
        annotation.draw(label, (x, 1),
                        y,
                        va=va,
                        transform=axis.transAxes,
                        **kwargs)
        return annotation
Exemplo n.º 2
0
    def draw_annotation(self, label, x, y, va='bottom', *args, **kwargs):
        """
        Draw a text annotation.
        This function is called by the :func:`~legend.Legend.draw` function after drawing the visual part of the legend annotation.

        The text annotation is based on the :class:`~text.annotation.Annotation` class.
        The arguments and keyword arguments are passed on to the :func:`~text.annotation.Annotation.draw` function.

        :param label: The text of the legend label.
        :type label: str
        :param x: The starting x-coordinate of the annotation.
        :type x: float
        :param y: The y-coordinate of the annotation.
        :type y: float
        :param va: The vertical alignment, can be one of `top`, `center` or `bottom`.
                   If the vertical alignment is `top`, the given y-coordinate becomes the highest point of the annotation.
                   If the vertical alignment is `center`, the given y-coordinate becomes the center point of the annotation.
                   If the vertical alignment is `bottom`, the given y-coordinate becomes the lowest point of the annotation.
        :type va: str

        :return: The drawn annotation.
        :rtype: :class:`~text.annotation.Annotation`
        """

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

        annotation = Annotation(self.drawable,
                                label, (x, 1),
                                y,
                                va=va,
                                transform=axes.transAxes,
                                **kwargs)
        annotation.draw()
        return annotation
Exemplo n.º 3
0
	def test_set_position_invalid_horizontal_alignment(self):
		"""
		Test that when setting the position of an annotation with an invalid horizontal alignment, a ValueError is raised.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		annotation.draw(text, (0, 1), 0)
		self.assertRaises(ValueError, annotation.set_position, (0, 2), ha='invalid')
Exemplo n.º 4
0
	def test_x_pad_justify_end(self):
		"""
		Test that when padding is applied with `justify-end` alignment, the block moves to the left.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		annotation.draw(text, (0, 1), 0, pad=0.2, align='justify-end')
		bb = annotation.get_virtual_bb()
		self.assertGreaterEqual(0.8, round(bb.x1, 10))
Exemplo n.º 5
0
	def test_y_pad_bottom(self):
		"""
		Test that when applying padding with `bottom` vertical alignment, the block moves up.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		annotation.draw(text, (0, 1), 0, pad=0.2, va='bottom')
		bb = annotation.get_virtual_bb()
		self.assertEqual(0.2, round(bb.y0, 10))
Exemplo n.º 6
0
	def test_set_position_bottom(self):
		"""
		Test that when moving an annotation with a `bottom` vertical alignment, the bottom of the last line is the given position.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		annotation.draw(text, (0, 1), 0, va='bottom')
		annotation.set_position((0, 2), va='bottom')
		for token in annotation.lines[-1]:
			self.assertEqual(2, util.get_bb(viz.figure, viz.axis, token).y0)
Exemplo n.º 7
0
	def test_set_position_left(self):
		"""
		Test that when moving an annotation with a `left` horizontal alignment, all lines start at the given position.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		annotation.draw(text, (0, 1), 0, align='left')
		annotation.set_position((2, 0), ha='left')
		for tokens in annotation.lines:
			self.assertEqual(2, round(util.get_bb(viz.figure, viz.axis, tokens[0]).x0, 10))
Exemplo n.º 8
0
	def test_set_position_horizontal_center(self):
		"""
		Test that when moving an annotation with a `center` horizontal alignment, the block is centered around the given point.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		annotation.draw(text, (0, 1), 0, align='center')
		annotation.set_position((2, 0), ha='center')
		bb = annotation.get_virtual_bb()
		self.assertEqual(2, (bb.x0 + bb.x1)/2.)
Exemplo n.º 9
0
    def test_draw_x_float(self):
        """
		Test that when drawing an annotation with a float as the x-bounds, the limit of the plot is used.
		"""

        text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
        viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
        annotation = Annotation(viz)
        annotation.draw(text, np.float64(0.2), 0)
        bb = annotation.get_virtual_bb()
        self.assertEqual(round(0.2, 10), round(bb.x0, 10))
        self.assertLessEqual(0.95, bb.x1)
        self.assertGreaterEqual(1, bb.x1)
Exemplo n.º 10
0
	def test_set_position_vertical_center_multiple_even_lines(self):
		"""
		Test that when centering multiple even lines vertically, the block is centered around the given point.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground. Depay began his professional career with PSV Eindhoven.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		annotation.draw(text, (0, 1), 0, va='center')
		annotation.set_position((0, 2), va='center')
		lines = annotation.lines
		self.assertGreater(len(lines), 1)
		self.assertFalse(len(lines) % 2)
		tokens = [ tokens[0] for tokens in lines ]
		bb1 = util.get_bb(viz.figure, viz.axis, tokens[0])
		bb2 = util.get_bb(viz.figure, viz.axis, tokens[-1])
		self.assertEqual(2, round((bb1.y1 + bb2.y0) / 2., 10))
Exemplo n.º 11
0
	def test_align_left(self):
		"""
		Test that when aligning text left, all lines start at the same x-coordinate.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 2), 0, align='left', va='top')
Exemplo n.º 12
0
	def test_text(self):
		"""
		Test that the text is written correctly.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 2), 0, align='left', va='top')

		drawn_text = self._reconstruct_text(lines)
		self.assertEqual(text, drawn_text)
Exemplo n.º 13
0
	def test_align_bottom_order(self):
		"""
		Test that when the vertical alignment is bottom, the order of lines is still correct.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0, va='bottom')

		self.assertEqual('Memphis', lines[0][0].get_text())
		self.assertEqual('ground.', lines[-1][-1].get_text())
Exemplo n.º 14
0
	def test_align_justify_right(self):
		"""
		Test that when justifying text with the last line being right-aligned, the last line ends at the farthest right.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 2), 0, align='justify-end', va='top')

		bb = util.get_bb(viz.figure, viz.axis, lines[0][-1])
		self.assertEqual(2, round(bb.x1, 5))
Exemplo n.º 15
0
	def test_center_one_line(self):
		"""
		Test that when centering a single line, each token in that line is centered.
		"""

		text = 'Memphis Depay  plays for Olympique Lyonnais'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0, va='center')
		for token in lines[0]:
			bb = util.get_bb(viz.figure, viz.axis, lines[0][0])
			self.assertEqual(0, (bb.y1 + bb.y0) / 2.)
Exemplo n.º 16
0
	def test_center_one_token(self):
		"""
		Test that when centering a single token, the middle of the annotation is equivalent to the middle coordinate of the token.
		"""

		text = 'Memphis'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0, va='center')
		bb = util.get_bb(viz.figure, viz.axis, lines[0][0])
		self.assertEqual(0, (bb.y1 + bb.y0) / 2.)
		virtual_bb = annotation.get_virtual_bb()
		self.assertEqual(0, (virtual_bb.y1 + virtual_bb.y0) / 2.)
Exemplo n.º 17
0
	def test_align_bottom(self):
		"""
		Test that when the alignment is top, all lines are above the provided y-coordinate.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0, va='bottom')

		bb = util.get_bb(viz.figure, viz.axis, lines[-1][-1])
		self.assertEqual(0, bb.y0)

		for line in lines:
			self.assertGreaterEqual(0, bb.y0)
Exemplo n.º 18
0
	def test_align_bottom_lines_do_not_overlap(self):
		"""
		Test that when annotations are vertically aligned to the bottom, the lines do not overlap.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0, va='bottom')

		for i in range(0, len(lines) - 1):
			bb0 = util.get_bb(viz.figure, viz.axis, lines[i][0])
			bb1 = util.get_bb(viz.figure, viz.axis, lines[i + 1][0])

			self.assertGreaterEqual(bb0.y0, bb1.y1)
Exemplo n.º 19
0
	def test_get_virtual_bb_single_token(self):
		"""
		Test that the virtual bounding box of an annotation with one token is equivalent to the bounding box of a single token.
		"""

		text = 'Memphis'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0)
		bb = util.get_bb(viz.figure, viz.axis, lines[0][0])
		virtual_bb = annotation.get_virtual_bb()
		self.assertEqual(bb.x0, virtual_bb.x0)
		self.assertEqual(bb.y0, virtual_bb.y0)
		self.assertEqual(bb.x1, virtual_bb.x1)
		self.assertEqual(bb.y1, virtual_bb.y1)
Exemplo n.º 20
0
	def test_get_virtual_bb_line(self):
		"""
		Test that the virtual bounding box of an annotation with one line spans the entire line.
		"""

		text = 'Memphis Depay plays for Olympique Lyonnais'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0)
		self.assertEqual(1, len(lines))
		virtual_bb = annotation.get_virtual_bb()
		self.assertEqual(util.get_bb(viz.figure, viz.axis, lines[0][0]).x0, virtual_bb.x0)
		self.assertEqual(util.get_bb(viz.figure, viz.axis, lines[0][0]).y0, virtual_bb.y0)
		self.assertEqual(util.get_bb(viz.figure, viz.axis, lines[0][-1]).x1, virtual_bb.x1)
		self.assertEqual(util.get_bb(viz.figure, viz.axis, lines[0][-1]).y1, virtual_bb.y1)
Exemplo n.º 21
0
	def test_get_virtual_bb_multiple_lines(self):
		"""
		Test that the virtual bounding box of an annotation with multiple lines spans the entire block.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0)
		self.assertGreater(len(lines), 1)
		virtual_bb = annotation.get_virtual_bb()
		self.assertEqual(util.get_bb(viz.figure, viz.axis, lines[0][0]).x0, virtual_bb.x0)
		self.assertEqual(util.get_bb(viz.figure, viz.axis, lines[-1][-1]).y0, virtual_bb.y0)
		self.assertEqual(max(util.get_bb(viz.figure, viz.axis, lines[line][-1]).x1 for line in range(0, len(lines))), virtual_bb.x1)
		self.assertEqual(util.get_bb(viz.figure, viz.axis, lines[0][0]).y1, virtual_bb.y1)
Exemplo n.º 22
0
	def test_align_bottom_line_alignment(self):
		"""
		Test that the lines all have the same vertical position when they are aligned to the top.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0, va='bottom')

		for line in lines:
			bb = util.get_bb(viz.figure, viz.axis, line[0])
			y1 = bb.y1

			for token in line:
				bb = util.get_bb(viz.figure, viz.axis, token)
				self.assertEqual(y1, bb.y1)
Exemplo n.º 23
0
	def test_align_right(self):
		"""
		Test that when aligning text right, all lines end at the same x-coordinate.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 2), 0, align='right', va='top')

		x = 0
		for i, lines in enumerate(lines):
			bb = util.get_bb(viz.figure, viz.axis, lines[-1])
			if i == 0:
				x = bb.x1

			self.assertEqual(round(x, 5), round(bb.x1, 5))
Exemplo n.º 24
0
    def annotate(self, text, x, y, marker=None, pad=0.01, *args, **kwargs):
        """
        Add a text annotation to the plot.
        This function can be used to draw attention to certain or describe the visualization on the plot itself.

        Any additional arguments and keyword arguments are passed on to the :class:`~text.annotation.Annotation`'s :func:`~text.annotation.Annotation.draw` function.
        For example, the `va` can be provided to specify the text's vertical alignment, andthe `align` parameter can be used to specify the text's alignment.

        :param text: The text of the annotation to draw.
        :type text: str
        :param x: A tuple containing the start and end x-coordinates of the annotation.
        :type x: tuple
        :param y: The y-coordinate of the annotation.
        :type y: float
        :param marker: The marker style.
                       If it is not given, no marker is drawn.
        :type marker: None or dict
        :param pad: The amount of padding applied to the annotation.
        :type pad: float

        :return: The drawn annotation.
        :rtype: :class:`~text.annotation.Annotation`
        """

        annotation = Annotation(self)
        self.figure.canvas.draw()
        """
        Draw the marker if it is given.
        The color is obtained from the kwargs if a marker color is not given.
        The point of the marker is based on the alignment of the annotation.
        """
        if marker is not None:
            marker = dict(
                marker)  # make a copy to avoid overwriting dictionaries
            marker['color'] = marker.get('color', kwargs.get('color'))
            if kwargs.get('align', 'left') == 'left':
                self.axes.plot(x[0], y, *args, **marker)
            elif kwargs.get('align') == 'right':
                self.axes.plot(x[1], y, *args, **marker)
            elif kwargs.get('align') == 'center':
                self.axes.plot((x[0] + x[1]) / 2., y, *args, **marker)

        tokens = annotation.draw(text, x, y, pad=pad, *args, **kwargs)
        self.annotations.append(annotation)

        return annotation
Exemplo n.º 25
0
	def test_align_center(self):
		"""
		Test that when centering text, all of the lines' centers are the same.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 2), 0, align='center', va='top')

		x = 0
		for i, lines in enumerate(lines[:-1]):
			bb0 = util.get_bb(viz.figure, viz.axis, lines[0])
			bb1 = util.get_bb(viz.figure, viz.axis, lines[-1])
			center = (bb0.x0 + bb1.x1) / 2.
			if i == 0:
				x = center

			self.assertEqual(round(x, 5), round(center, 5))
Exemplo n.º 26
0
	def test_align_justify(self):
		"""
		Test that when justifying text, all lines start and end at the same x-coordinate.
		The calculation is made on the center since the bboxes of text do not start or end at the exact same coordinate.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 2), 0, align='justify', va='top')

		x = 0
		for i, lines in enumerate(lines[:-1]): # skip the last line as it is not justified
			bb0 = util.get_bb(viz.figure, viz.axis, lines[0])
			bb1 = util.get_bb(viz.figure, viz.axis, lines[-1])
			center = (bb0.x0 + bb1.x1) / 2.
			if i == 0:
				x = center

			self.assertEqual(round(x, 5), round(center, 5))
Exemplo n.º 27
0
	def test_center_multiple_odd_lines(self):
		"""
		Test that when centering multiple odd lines, the block is centered around the given point.
		"""

		text = 'Memphis Depay, commonly known simply as Memphis, is a Dutch professional footballer and music artist who plays as a forward and captains French club Lyon and plays for the Netherlands national team. He is known for his pace, ability to cut inside, dribbling, distance shooting and ability to play the ball off the ground.'
		viz = drawable.Drawable(plt.figure(figsize=(10, 10)))
		annotation = Annotation(viz)
		lines = annotation.draw(text, (0, 1), 0, va='center')
		self.assertGreater(len(lines), 1)
		self.assertTrue(len(lines) % 2)
		tokens = [ tokens[0] for tokens in lines ]
		bb1 = util.get_bb(viz.figure, viz.axis, tokens[0])
		bb2 = util.get_bb(viz.figure, viz.axis, tokens[-1])
		self.assertEqual(0, round((bb1.y1 + bb2.y0) / 2., 10))

		"""
		Check that the middle line is centered.
		"""
		bb = util.get_bb(viz.figure, viz.axis, lines[math.floor(len(lines) / 2)][0])
		self.assertEqual(0, round((bb.y1 + bb.y0) / 2., 10))
Exemplo n.º 28
0
    def annotate(self, text, x, y, marker=None, pad=0.01, *args, **kwargs):
        """
		Add an annotation to the plot.
		Any additional arguments and keyword arguments are passed on to the annotation's :meth:`~text.text.Annotation.draw` function.
		For example, the `va` can be provided to specify the vertical alignment.
		The `align` parameter can be used to specify the text's alignment.

		:param text: The text of the annotation to draw.
		:type text: str
		:param x: A tuple containing the start and end x-coordinates of the annotation.
		:type x: tuple
		:param y: The y-coordinate of the annotation.
		:type y: float
		:param marker: The marker style.
					   If it is not given, no marker is drawn.
		:type marker: None or dict
		:param pad: The amount of padding applied to the annotation.
		:type pad: float
		"""

        annotation = Annotation(self)
        """
		Draw the marker if it is given.
		The color is obtained from the kwargs if a marker color is not given.
		The point of the marker is based on the alignment of the annotation.
		"""
        if marker is not None:
            marker['color'] = marker.get('color', kwargs.get('color'))
            if kwargs.get('align', 'left') == 'left':
                self.axis.plot(x[0], y, *args, **marker)
            elif kwargs.get('align') == 'right':
                self.axis.plot(x[1], y, *args, **marker)
            elif kwargs.get('align') == 'center':
                self.axis.plot((x[0] + x[1]) / 2., y, *args, **marker)

        tokens = annotation.draw(text, x, y, pad=pad, *args, **kwargs)
        self.annotations.append(annotation)

        return tokens
Exemplo n.º 29
0
class Drawable():
    """
	The :class:`~Drawable` class wraps a matplotlib figure and axis to provide additional functionality.
	If no axis is given, the default plot axis (:code:`plt.gca()`) is used.
	The :class:`~Drawable` class can be used as a normal :class:`matplotlib.axis.Axis` object with additional functionality.
	The axis functionality can be called on the :class:`~Drawable` class.
	The :class:`~Drawable` instance re-routes method and attribute calls to the :class:`matplotlib.axis.Axis` instance.

	To create a :class:`~Drawable` instance from a normal plot:

	.. code-block:: python

	  viz = drawable.Drawable(plt.figure(figsize=(10, 5)))

	To create a :class:`~Drawable` instance from an axis, or a subplot:

	.. code-block:: python

	  figure, axis = plt.subplots(2, 1, figsize=(10, 10))
	  viz = drawable.Drawable(figure, axis[0])

	:ivar figure: The figure that the :class:`~Drawable` class wraps.
	:vartype figure: :class:`matplotlib.figure.Figure`
	:ivar axis: The axis where the drawable will draw.
	:vartype axis: :class:`matplotlib.axis.Axis`
	:var caption: The caption, displayed under the title.
	:vartype caption: :class:`~text.annotation.Annotation`

	:ivar timeseries: The time series object that is being used.
	:vartype timeseries: :class:`~timeseries.timeseries.TimeSeries`
	:ivar legend: The figure's legend.
	:vartype legend: :class:`~legend.Legend`
	:ivar annotations: The annotations in the visualization.
	:vartype annotations: list of :class:`~text.annotation.Annotation`
	"""
    def __init__(self, figure, axis=None):
        """
		Create the drawable with the figure.

		:param figure: The figure that the :class:`~Drawable` class wraps.
					   This is mainly used to get the figure renderer.
		:type figure: :class:`matplotlib.figure.Figure`
		:param axis: The axis (or subplot) where to plot visualizations.
					 If `None` is not given, the plot's main subplot is used instead.
		:type axis: `None` or :class:`matplotlib.axis.Axis`
		"""

        self.figure = figure
        self.axis = plt.gca() if axis is None else axis
        self.caption = Annotation(self)

        self.annotations = []
        self.legend = Legend(self)
        self.timeseries = None

    def set_caption(self,
                    caption,
                    alpha=0.8,
                    lineheight=1.25,
                    *args,
                    **kwargs):
        """
		Add a caption to the subplot.
		The caption is added just beneath the title.
		The method re-draws the title to make space for the caption.

		The caption is a :class:`~text.text.Annotation` object.
		Any arguments that the constructor accepts can be provided to this method.

		:param caption: The caption to add to the axis.
		:type caption: str
		:param alpha: The opacity of the caption between 0 and 1.
		:type alpha: float
		:param lineheight: The space between lines.
		:type lineheight: float

		:return: The drawn caption.
		:rtype: :class:`~text.annotation.Annotation`
		"""

        self.caption = Annotation(self)
        self.caption.draw(caption, (0, 1),
                          1,
                          va='bottom',
                          alpha=alpha,
                          lineheight=lineheight,
                          *args,
                          **kwargs,
                          transform=self.axis.transAxes)
        self.redraw()
        return self.caption

    def redraw(self):
        """
		Re-create the title with the necessary padding to fit the caption and the legend.
		"""
        """
		Move the caption up to make space for the legend.
		"""
        legend_bb = self.legend.get_virtual_bb(transform=self.axis.transAxes)
        self.caption.set_position((0, 1 + 0.01 + legend_bb.height),
                                  ha='left',
                                  va='bottom',
                                  transform=self.axis.transAxes)
        """
		Get the height of the caption and the height of the legend.
		The title should allow enough padding to make space for both.
		"""
        title = self.axis.get_title(loc='left')
        caption_bb = self.axis.transData.transform(
            self.caption.get_virtual_bb())
        height = abs(caption_bb[0][1] - caption_bb[1][1])
        legend_bb = self.axis.transData.transform(self.legend.get_virtual_bb())
        height += abs(legend_bb[0][1] - legend_bb[1][1])
        pad_px = self.axis.transAxes.transform(
            (0, 0.01))[1] - self.axis.transAxes.transform((0, 0))[1]
        self.axis.set_title(title, loc='left', pad=(5 + height + pad_px * 2))

    def __getattr__(self, name):
        """
		Get an attribute indicated by `name` from the class.
		If it gets to this point, then the attribute does not exist.
		Instead, it is retrieved from the :class:`~Drawable` axis.

		:param name: The name of the attribute.
		:type name: str

		:return: The function applied on the axis.
		:rtype: function
		"""
        def method(*args, **kwargs):
            """
			Try to get the attribute from the axis.
			If arguments were given, then the attribute is treated as a method call.
			Otherwise, it is treated as a normal attribute call.
			"""

            if callable(getattr(self.axis, name)):
                return getattr(self.axis, name)(*args, **kwargs)
            else:
                return getattr(self.axis, name)

        return method

    """
	Visualizations
	"""

    def draw_text_annotation(self, *args, **kwargs):
        """
		Draw a text annotation visualization on this :class:`~Drawable`.
		The arguments and keyword arguments are those supported by :meth:`~text.annotation.TextAnnotation.draw` method.

		:return: The drawn text annotation's 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
		"""

        text_annotation = TextAnnotation(self)
        return text_annotation.draw(*args, **kwargs)

    def draw_time_series(self, *args, **kwargs):
        """
		Draw a time series visualization on this :class:`~Drawable`.
		The arguments and keyword arguments are those supported by :meth:`~text.annotation.TextAnnotation.draw` method.

		:return: A tuple made up of the drawn plot and label.
		:rtype: tuple
		"""

        self.timeseries = self.timeseries if self.timeseries is not None else TimeSeries(
            self)
        return self.timeseries.draw(*args, **kwargs)

    def annotate(self, text, x, y, marker=None, pad=0.01, *args, **kwargs):
        """
		Add an annotation to the plot.
		Any additional arguments and keyword arguments are passed on to the annotation's :meth:`~text.text.Annotation.draw` function.
		For example, the `va` can be provided to specify the vertical alignment.
		The `align` parameter can be used to specify the text's alignment.

		:param text: The text of the annotation to draw.
		:type text: str
		:param x: A tuple containing the start and end x-coordinates of the annotation.
		:type x: tuple
		:param y: The y-coordinate of the annotation.
		:type y: float
		:param marker: The marker style.
					   If it is not given, no marker is drawn.
		:type marker: None or dict
		:param pad: The amount of padding applied to the annotation.
		:type pad: float
		"""

        annotation = Annotation(self)
        """
		Draw the marker if it is given.
		The color is obtained from the kwargs if a marker color is not given.
		The point of the marker is based on the alignment of the annotation.
		"""
        if marker is not None:
            marker['color'] = marker.get('color', kwargs.get('color'))
            if kwargs.get('align', 'left') == 'left':
                self.axis.plot(x[0], y, *args, **marker)
            elif kwargs.get('align') == 'right':
                self.axis.plot(x[1], y, *args, **marker)
            elif kwargs.get('align') == 'center':
                self.axis.plot((x[0] + x[1]) / 2., y, *args, **marker)

        tokens = annotation.draw(text, x, y, pad=pad, *args, **kwargs)
        self.annotations.append(annotation)

        return tokens
Exemplo n.º 30
0
    def _draw_edge_names(self, edges, nodes, positions, s, *args, **kwargs):
        """
        Draw names for the edges.
        Names are drawn if they have a `name` attribute.
        The `name_style` attribute, if given, is used to override the default name style.
        Names are written left-to-right.

        Any additional keyword arguments are considered to be styling options.

        :param edges: The list of edges for which to draw names.
        :type edges: :class:`networkx.classes.reportviews.NodeView`
        :param nodes: The list of nodes in the graph.
                      They are used when rendering names for looped edges.
        :type nodes: networkx.classes.reportviews.NodeView
        :param positions: The positions of the nodes as a dictionary.
                          The keys are the node names, and the values are the corresponding positions.
        :type positions: dict
        :param s: The default radius of the node.
                  It may be overwritten with the node's own radius.
        :type s: float

        :return: A dictionary of rendered edge names.
                 The keys are the edge names and the values are :class:`~text.annotation.Annotation`, representing the rendered annotations.
        :rtype: dict
        """

        annotations = {}

        for (source, target) in edges:
            """
            Nodes are drawn only if they have a name attribute.
            """
            name = edges[(source, target)].get('name')
            if name:
                """
                By default, edge names are aligned centrally.
                However, the style can be overriden by providing a `name_style` attribute.
                """
                default_style = {
                    'align': 'center',
                    'ha': 'left',
                    'va': 'center'
                }
                default_style.update(**kwargs)
                style = edges[(source, target)].get('name_style', {})
                default_style.update(style)
                """
                To draw the name from left to right, order the source and target nodes accordingly.
                """
                u, v = sorted([positions[source], positions[target]],
                              key=lambda node: node[0])
                """
                Draw the annotation to get an idea of its width and remove it immediately.
                """
                annotation = Annotation(self.drawable)
                annotation.draw([name], (u[0]), u[1], **default_style)
                bb = annotation.get_virtual_bb()
                annotation.remove()

                if source == target:
                    """
                    If the edge is a loop, draw the name at the apex.
                    """
                    radius = self._get_radius(nodes[source],
                                              s=nodes[source].get('style',
                                                                  {}).get(
                                                                      's', s))
                    annotation = Annotation(self.drawable)
                    x = (u[0] - bb.width / 2., u[0] + bb.width / 2.)
                    y = u[1] + radius[1] * 2 + bb.height
                    annotation.draw([name], x, y, **default_style)
                    continue
                """
                Re-draw the annotation, this time positionally centered along the edge.
                The rotation depends on the elevation from the source to the target node.
                """
                ratio = util.get_aspect(self.drawable.axes)
                distance = self._get_distance(u, v)
                direction = self._get_direction(u, v)
                angle = self._get_elevation(u, v)
                """
                The annotation's x-position is bound rigidly based on the width of the annotation.
                The y-position is based on the angle. This is because the horizontal alignment is always set to `left`.
                """
                annotation = Annotation(self.drawable)
                x = (u[0] + direction[0] * distance / 2. - bb.width / 2.,
                     u[0] + direction[0] * distance / 2. + bb.width / 2.)
                y = u[1] + direction[
                    1] * distance / 2. + bb.height / 2. * math.sin(angle) * (
                        math.degrees(angle) > 0)
                annotation.draw([name],
                                x,
                                y,
                                rotation=math.degrees(angle),
                                **default_style)
                annotations[(source, target)] = annotation

        return annotations