Esempio n. 1
0
    def _set_lim_and_transforms(self):
        """
        This is called once when the plot is created to set up all the
        transforms for the data, text and grids.
        """
        # This code is based off of matplotlib's example for a custom Hammer
        # projection. See: https://matplotlib.org/gallery/misc/custom_projection.html#sphx-glr-gallery-misc-custom-projection-py

        # This function makes heavy use of the Transform classes in
        # ``lib/matplotlib/transforms.py.`` For more information, see
        # the inline documentation there.

        # Affine2D.from_values(a, b, c, d, e, f) constructs an affine
        # transformation matrix of
        #    a c e
        #    b d f
        #    0 0 1

        # A useful reference for the different coordinate systems can be found
        # in a table in the matplotlib transforms tutorial:
        # https://matplotlib.org/tutorials/advanced/transforms_tutorial.html#transformations-tutorial

        # The goal of this transformation is to get from the data space to axes
        # space. We perform an affine transformation on the y-axis, i.e.
        # transforming the y-axis from (0, 1) to (0.5, sqrt(3)/2).
        self.transAffine = Affine2D.from_values(1., 0, 0.5,
                                                np.sqrt(3) / 2., 0, 0)
        # Affine transformation along the dependent axis
        self.transAffinedep = Affine2D.from_values(1., 0, -0.5,
                                                   np.sqrt(3) / 2., 0, 0)

        # This is the transformation from axes space to display space.
        self.transAxes = BboxTransformTo(self.bbox)

        # The data transformation is the application of the affine
        # transformation from data to axes space, then from axes to display
        # space. The '+' operator applies these in order.
        self.transData = self.transAffine + self.transAxes

        # The main data transformation is set up.  Now deal with gridlines and
        # tick labels. For these, we want the same trasnform as the, so we
        # apply transData directly.
        self._xaxis_transform = self.transData
        self._xaxis_text1_transform = self.transData
        self._xaxis_text2_transform = self.transData

        self._yaxis_transform = self.transData
        self._yaxis_text1_transform = self.transData
        self._yaxis_text2_transform = self.transData
Esempio n. 2
0
def getTransform(parentMap, node): # test, speed up by caching transform for node
   n = node
   transform = Affine2D()
   while True:
      tString = n.get("transform")
      if tString is not None:
         for m in reversed(list(finditer(r"(?P<method>\w+)\(\s*(?P<args>[^)]*)\)", tString))):
            args = m.group('args').replace(",", " ").split()
            method = m.group('method')
            if method == "matrix":
               transform = composite_transform_factory(transform, Affine2D.from_values(*args))
            elif method == "translate":
               transform.translate(args[0], 0 if len(args)<2 else args[1])
            elif method == "scale":
               transform.scale(*args)
            elif method == "rotate":
               if len(args) == 1:
                  transform.rotate_deg(args[0])
               else:
                  transform.rotate_deg_around(*args)
            elif method == "skewX":
               transform.skew_deg(args[0], 0)
            elif method == "skewY":
               transform.skew_deg(0, args[0])
      if n in parentMap:
         n = parentMap[n]
      else: break
   return transform
Esempio n. 3
0
def fit_affine_clip(xy1f, xy2f):
    sol = fit_affine(xy1f, xy2f)

    affine_tr = Affine2D.from_values(*sol)

    xy1f_tr = affine_tr.transform(xy1f) #[:,0], xy1f[:,1])

    # mask and refit
    dx_ = xy1f_tr[:,0] - xy2f[:,0]
    mystd = dx_.std()
    mm = [np.abs(dx_) < 3. * mystd]

    sol = fit_affine(xy1f[mm], xy2f[mm])

    affine_tr = Affine2D.from_values(*sol)

    return affine_tr, mm
Esempio n. 4
0
def fit_affine_clip(xy1f, xy2f):
    sol = fit_affine(xy1f, xy2f)

    affine_tr = Affine2D.from_values(*sol)

    xy1f_tr = affine_tr.transform(xy1f)  #[:,0], xy1f[:,1])

    # mask and refit
    dx_ = xy1f_tr[:, 0] - xy2f[:, 0]
    mystd = dx_.std()
    mm = [np.abs(dx_) < 3. * mystd]

    sol = fit_affine(xy1f[mm], xy2f[mm])

    affine_tr = Affine2D.from_values(*sol)

    return affine_tr, mm
Esempio n. 5
0
def triangular_axes(fig):
	# ternary projection
	tr = Affine2D.from_values(1., 0, 0.5, np.sqrt(3)/2., 0, 0)
	# negative ternary projection for dependent axis
	neg_tr = Affine2D.from_values(1., 0, -0.5, np.sqrt(3)/2., 0, 0)
	# identity transform
	identity_tr = Affine2D.from_values(1, 0, 0, 1, 0, 0)

	grid_helper = GridHelperTriangular(tr, 
				    extremes=(0,1,0,1), 
				    grid_type="independent")
	# use null_locator to kill extra horizontal gridlines from dependent axis
	null_locator = grid_finder.MaxNLocator(1)
	dep_grid_helper = GridHelperTriangular(neg_tr, 
					extremes=(0,1,0,1), 
					grid_type="dependent", 
					grid_locator2=null_locator)

	# Add independent axes with gridlines
	ax1 = floating_axes.FloatingSubplot(fig, 111, grid_helper=grid_helper)
	
	fig.add_subplot(ax1)

	ax1.axis[:].set_visible(False)
	ax1.axis["bottom"].set_visible(True)
	ax1.axis["left"].set_visible(True)

	# Add dependent axis with gridlines
	ax2 = ParasiteAxesAuxTrans(ax1, 
			    identity_tr, 
			    "equal", 
			    grid_helper=dep_grid_helper)
	ax2.axis["right"] = ax2.get_grid_helper().new_floating_axis(0,
							     1,
							     axes=ax1)
	ax2.axis["right"].toggle(ticklabels=False)
	ax1.parasites.append(ax2)
	ax1.grid(True)
	ax2.grid(True)
	ax1.plot([])
	ax1.set_aspect(1.)
	return ax1
Esempio n. 6
0
def test_Affine2D_from_values():
    points = [ [0,0],
               [10,20],
               [-1,0],
               ]

    t = Affine2D.from_values(1,0,0,0,0,0)
    actual = t.transform(points)
    expected = np.array( [[0,0],[10,0],[-1,0]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,2,0,0,0,0)
    actual = t.transform(points)
    expected = np.array( [[0,0],[0,20],[0,-2]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,0,3,0,0,0)
    actual = t.transform(points)
    expected = np.array( [[0,0],[60,0],[0,0]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,0,0,4,0,0)
    actual = t.transform(points)
    expected = np.array( [[0,0],[0,80],[0,0]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,0,0,0,5,0)
    actual = t.transform(points)
    expected = np.array( [[5,0],[5,0],[5,0]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,0,0,0,0,6)
    actual = t.transform(points)
    expected = np.array( [[0,6],[0,6],[0,6]] )
    assert_almost_equal(actual,expected)
Esempio n. 7
0
def test_Affine2D_from_values():
    points = [ [0,0],
               [10,20],
               [-1,0],
               ]

    t = Affine2D.from_values(1,0,0,0,0,0)
    actual = t.transform(points)
    expected = np.array( [[0,0],[10,0],[-1,0]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,2,0,0,0,0)
    actual = t.transform(points)
    expected = np.array( [[0,0],[0,20],[0,-2]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,0,3,0,0,0)
    actual = t.transform(points)
    expected = np.array( [[0,0],[60,0],[0,0]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,0,0,4,0,0)
    actual = t.transform(points)
    expected = np.array( [[0,0],[0,80],[0,0]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,0,0,0,5,0)
    actual = t.transform(points)
    expected = np.array( [[5,0],[5,0],[5,0]] )
    assert_almost_equal(actual,expected)

    t = Affine2D.from_values(0,0,0,0,0,6)
    actual = t.transform(points)
    expected = np.array( [[0,6],[0,6],[0,6]] )
    assert_almost_equal(actual,expected)
Esempio n. 8
0
 def device_fill_points(self, points, mode):
     if mode in (FILL, FILL_STROKE, EOF_FILL_STROKE, EOF_FILL):
         fill = tuple(self.state.fill_color)
     else:
         fill = None
     if mode in (STROKE, FILL_STROKE, EOF_FILL_STROKE):
         color = tuple(self.state.line_color)
     else:
         color = tuple(self.state.fill_color)
     path = Path(points)
     gc = self._backend.new_gc()
     gc.set_linewidth(self.state.line_width)
     if not (self.state.line_dash[1] == 0).all():
         gc.set_dashes(self.state.line_dash[0], list(self.state.line_dash[1]))
     if self.state.clipping_path:
         gc.set_clip_path(self._get_transformed_clip_path())
     gc.set_joinstyle(line_join_map[self.state.line_join])
     gc.set_capstyle(line_cap_map[self.state.line_cap])
     gc.set_foreground(color, isRGB=True)
     gc.set_alpha(self.state.alpha)
     transform = Affine2D.from_values(*affine.affine_params(self.get_ctm()))
     self._backend.draw_path(gc, path, transform, fill)
     gc.restore()
Esempio n. 9
0
 def device_fill_points(self, points, mode):
     if mode in (FILL, FILL_STROKE, EOF_FILL_STROKE, EOF_FILL):
         fill = tuple(self.state.fill_color)
     else:
         fill = None
     if mode in (STROKE, FILL_STROKE, EOF_FILL_STROKE):
         color = tuple(self.state.line_color)
     else:
         color = tuple(self.state.fill_color)
     path = Path(points)
     gc = self._backend.new_gc()
     gc.set_linewidth(self.state.line_width)
     if not (self.state.line_dash[1] == 0).all():
         gc.set_dashes(self.state.line_dash[0],
                       list(self.state.line_dash[1]))
     if self.state.clipping_path:
         gc.set_clip_path(self._get_transformed_clip_path())
     gc.set_joinstyle(line_join_map[self.state.line_join])
     gc.set_capstyle(line_cap_map[self.state.line_cap])
     gc.set_foreground(color, isRGB=True)
     gc.set_alpha(self.state.alpha)
     transform = Affine2D.from_values(*affine.affine_params(self.get_ctm()))
     self._backend.draw_path(gc, path, transform, fill)
     gc.restore()
Esempio n. 10
0
 def _get_transformed_clip_path(self):
     x, y, width, height = self.state.clipping_path
     rect = ((x, y), (x+width, y), (x+width, y+height), (x, y+height))
     transform = Affine2D.from_values(*affine.affine_params(self.get_ctm()))
     return TransformedPath(Path(rect), transform)
Esempio n. 11
0
    def device_draw_image(self, img, rect):
        """
        draw_image(img_gc, rect=(x,y,w,h))

        Draws another gc into this one.  If 'rect' is not provided, then
        the image gc is drawn into this one, rooted at (0,0) and at full
        pixel size.  If 'rect' is provided, then the image is resized
        into the (w,h) given and drawn into this GC at point (x,y).

        img_gc is either a Numeric array (WxHx3 or WxHx4) or a GC from Kiva's
        Agg backend (kiva.agg.GraphicsContextArray).

        Requires the Python Imaging Library (PIL).
        """
        from PIL import Image as PilImage
        from matplotlib import _image

        # We turn img into a PIL object, since that is what ReportLab
        # requires.  To do this, we first determine if the input image
        # GC needs to be converted to RGBA/RGB.  If so, we see if we can
        # do it nicely (using convert_pixel_format), and if not, we do
        # it brute-force using Agg.
        if type(img) == type(array([])):
            # Numeric array
            converted_img = agg.GraphicsContextArray(img, pix_format='rgba32')
            format = 'RGBA'
        elif isinstance(img, agg.GraphicsContextArray):
            if img.format().startswith('RGBA'):
                format = 'RGBA'
            elif img.format().startswith('RGB'):
                format = 'RGB'
            else:
                converted_img = img.convert_pixel_format('rgba32', inplace=0)
                format = 'RGBA'
            # Should probably take this into account
            # interp = img.get_image_interpolation()
        else:
            warnings.warn("Cannot render image of type %r into SVG context."
                          % type(img))
            return

        if rect == None:
            rect = (0, 0, img.width(), img.height())

        width, height = img.width(), img.height()

        # converted_img now holds an Agg graphics context with the image
        pil_img = PilImage.fromstring(format,
                                      (converted_img.width(),
                                       converted_img.height()),
                                      converted_img.bmp_array.tostring())

        left, top, width, height = rect
        if width != img.width() or height != img.height():
            # This is not strictly required.
            pil_img = pil_img.resize((int(width), int(height)), PilImage.NEAREST)
        pil_img = pil_img.transpose(PilImage.FLIP_TOP_BOTTOM)
        # Fix for the SVG backend, which seems to flip x when a transform is provided.
        if self._backend.flipy():
            pil_img = pil_img.transpose(PilImage.FLIP_LEFT_RIGHT)

        mpl_img = _image.frombuffer(pil_img.tostring(), width, height, True)
        mpl_img.is_grayscale = False

        gc = self._backend.new_gc()
        if self.state.clipping_path:
            gc.set_clip_path(self._get_transformed_clip_path())
        transform = Affine2D.from_values(*affine.affine_params(self.get_ctm()))
        self._backend.draw_image(gc, left, top, mpl_img,
                                 dx=width, dy=height, transform=transform)
        gc.restore()
Esempio n. 12
0
    def _set_lim_and_transforms(self):
        """
        This is called once when the plot is created to set up all the
        transforms for the data, text and grids.
        """
        # There are three important coordinate spaces going on here:
        #
        #    1. Data space: The space of the data itself
        #
        #    2. Axes space: The unit rectangle (0, 0) to (1, 1)
        #       covering the entire plot area.
        #
        #    3. Display space: The coordinates of the resulting image,
        #       often in pixels or dpi/inch.

        # This function makes heavy use of the Transform classes in
        # ``lib/matplotlib/transforms.py.`` For more information, see
        # the inline documentation there.

        # The goal of the first two transformations is to get from the
        # data space (in this case longitude and latitude) to axes
        # space.  It is separated into a non-affine and affine part so
        # that the non-affine part does not have to be recomputed when
        # a simple affine change to the figure has been made (such as
        # resizing the window or changing the dpi).

        # 1) The core transformation from data space into
        # rectilinear space defined in the HammerTransform class.
        self.transProjection = IdentityTransform()
        # 2) The above has an output range that is not in the unit
        # rectangle, so scale and translate it so it fits correctly
        # within the axes.  The peculiar calculations of xscale and
        # yscale are specific to a Aitoff-Hammer projection, so don't
        # worry about them too much.
        self.transAffine = Affine2D.from_values(
                1., 0, 0.5, np.sqrt(3)/2., 0, 0)
        self.transAffinedep = Affine2D.from_values(
                1., 0, -0.5, np.sqrt(3)/2., 0, 0)
        #self.transAffine = IdentityTransform()
        
        # 3) This is the transformation from axes space to display
        # space.
        self.transAxes = BboxTransformTo(self.bbox)

        # Now put these 3 transforms together -- from data all the way
        # to display coordinates.  Using the '+' operator, these
        # transforms will be applied "in order".  The transforms are
        # automatically simplified, if possible, by the underlying
        # transformation framework.
        self.transData = \
            self.transProjection + \
            self.transAffine + \
            self.transAxes

        # The main data transformation is set up.  Now deal with
        # gridlines and tick labels.

        # Longitude gridlines and ticklabels.  The input to these
        # transforms are in display space in x and axes space in y.
        # Therefore, the input values will be in range (-xmin, 0),
        # (xmax, 1).  The goal of these transforms is to go from that
        # space to display space.  The tick labels will be offset 4
        # pixels from the equator.

        self._xaxis_pretransform = IdentityTransform()
        self._xaxis_transform = \
            self._xaxis_pretransform + \
            self.transData
        self._xaxis_text1_transform = \
            Affine2D().scale(1.0, 0.0) + \
            self.transData + \
            Affine2D().translate(0.0, -20.0)
        self._xaxis_text2_transform = \
            Affine2D().scale(1.0, 0.0) + \
            self.transData + \
            Affine2D().translate(0.0, -4.0)

        # Now set up the transforms for the latitude ticks.  The input to
        # these transforms are in axes space in x and display space in
        # y.  Therefore, the input values will be in range (0, -ymin),
        # (1, ymax).  The goal of these transforms is to go from that
        # space to display space.  The tick labels will be offset 4
        # pixels from the edge of the axes ellipse.

        self._yaxis_transform = self.transData
        yaxis_text_base = \
            self.transProjection + \
            (self.transAffine + \
             self.transAxes)
        self._yaxis_text1_transform = \
            yaxis_text_base + \
            Affine2D().translate(-8.0, 0.0)
        self._yaxis_text2_transform = \
            yaxis_text_base + \
            Affine2D().translate(8.0, 0.0)
Esempio n. 13
0
def to_transform(mu, sigma):
    val, vec = np.linalg.eigh(sigma)
    trans = np.diag(np.sqrt(val)).dot(vec)
    return Affine2D.from_values(*trans.flatten(), e=mu[0], f=mu[1])
Esempio n. 14
0
 def _get_transformed_clip_path(self):
     x, y, width, height = self.state.clipping_path
     rect = ((x, y), (x + width, y), (x + width, y + height), (x,
                                                               y + height))
     transform = Affine2D.from_values(*affine.affine_params(self.get_ctm()))
     return TransformedPath(Path(rect), transform)
Esempio n. 15
0
    def device_draw_image(self, img, rect):
        """
        draw_image(img_gc, rect=(x,y,w,h))

        Draws another gc into this one.  If 'rect' is not provided, then
        the image gc is drawn into this one, rooted at (0,0) and at full
        pixel size.  If 'rect' is provided, then the image is resized
        into the (w,h) given and drawn into this GC at point (x,y).

        img_gc is either a Numeric array (WxHx3 or WxHx4) or a GC from Kiva's
        Agg backend (kiva.agg.GraphicsContextArray).

        Requires the Python Imaging Library (PIL).
        """
        from PIL import Image as PilImage
        from matplotlib import _image

        # We turn img into a PIL object, since that is what ReportLab
        # requires.  To do this, we first determine if the input image
        # GC needs to be converted to RGBA/RGB.  If so, we see if we can
        # do it nicely (using convert_pixel_format), and if not, we do
        # it brute-force using Agg.
        if type(img) == type(array([])):
            # Numeric array
            converted_img = agg.GraphicsContextArray(img, pix_format='rgba32')
            format = 'RGBA'
        elif isinstance(img, agg.GraphicsContextArray):
            if img.format().startswith('RGBA'):
                format = 'RGBA'
            elif img.format().startswith('RGB'):
                format = 'RGB'
            else:
                converted_img = img.convert_pixel_format('rgba32', inplace=0)
                format = 'RGBA'
            # Should probably take this into account
            # interp = img.get_image_interpolation()
        else:
            warnings.warn("Cannot render image of type %r into SVG context." %
                          type(img))
            return

        if rect == None:
            rect = (0, 0, img.width(), img.height())

        width, height = img.width(), img.height()

        # converted_img now holds an Agg graphics context with the image
        pil_img = PilImage.fromstring(
            format, (converted_img.width(), converted_img.height()),
            converted_img.bmp_array.tostring())

        left, top, width, height = rect
        if width != img.width() or height != img.height():
            # This is not strictly required.
            pil_img = pil_img.resize((int(width), int(height)),
                                     PilImage.NEAREST)
        pil_img = pil_img.transpose(PilImage.FLIP_TOP_BOTTOM)
        # Fix for the SVG backend, which seems to flip x when a transform is provided.
        if self._backend.flipy():
            pil_img = pil_img.transpose(PilImage.FLIP_LEFT_RIGHT)

        mpl_img = _image.frombuffer(pil_img.tostring(), width, height, True)
        mpl_img.is_grayscale = False

        gc = self._backend.new_gc()
        if self.state.clipping_path:
            gc.set_clip_path(self._get_transformed_clip_path())
        transform = Affine2D.from_values(*affine.affine_params(self.get_ctm()))
        self._backend.draw_image(gc,
                                 left,
                                 top,
                                 mpl_img,
                                 dx=width,
                                 dy=height,
                                 transform=transform)
        gc.restore()
Esempio n. 16
0
    def _set_lim_and_transforms(self):
        """
        This is called once when the plot is created to set up all the
        transforms for the data, text and grids.
        """
        # There are three important coordinate spaces going on here:
        #
        #    1. Data space: The space of the data itself
        #
        #    2. Axes space: The unit rectangle (0, 0) to (1, 1)
        #       covering the entire plot area.
        #
        #    3. Display space: The coordinates of the resulting image,
        #       often in pixels or dpi/inch.

        # This function makes heavy use of the Transform classes in
        # ``lib/matplotlib/transforms.py.`` For more information, see
        # the inline documentation there.

        # The goal of the first two transformations is to get from the
        # data space (in this case longitude and latitude) to axes
        # space.  It is separated into a non-affine and affine part so
        # that the non-affine part does not have to be recomputed when
        # a simple affine change to the figure has been made (such as
        # resizing the window or changing the dpi).

        # 1) The core transformation from data space into
        # rectilinear space defined in the HammerTransform class.
        self.transProjection = IdentityTransform()
        # 2) The above has an output range that is not in the unit
        # rectangle, so scale and translate it so it fits correctly
        # within the axes.  The peculiar calculations of xscale and
        # yscale are specific to a Aitoff-Hammer projection, so don't
        # worry about them too much.
        self.transAffine = Affine2D.from_values(1., 0, 0.5,
                                                np.sqrt(3) / 2., 0, 0)
        self.transAffinedep = Affine2D.from_values(1., 0, -0.5,
                                                   np.sqrt(3) / 2., 0, 0)
        #self.transAffine = IdentityTransform()

        # 3) This is the transformation from axes space to display
        # space.
        self.transAxes = BboxTransformTo(self.bbox)

        # Now put these 3 transforms together -- from data all the way
        # to display coordinates.  Using the '+' operator, these
        # transforms will be applied "in order".  The transforms are
        # automatically simplified, if possible, by the underlying
        # transformation framework.
        self.transData = \
            self.transProjection + \
            self.transAffine + \
            self.transAxes

        # The main data transformation is set up.  Now deal with
        # gridlines and tick labels.

        # Longitude gridlines and ticklabels.  The input to these
        # transforms are in display space in x and axes space in y.
        # Therefore, the input values will be in range (-xmin, 0),
        # (xmax, 1).  The goal of these transforms is to go from that
        # space to display space.  The tick labels will be offset 4
        # pixels from the equator.

        self._xaxis_pretransform = IdentityTransform()
        self._xaxis_transform = \
            self._xaxis_pretransform + \
            self.transData
        self._xaxis_text1_transform = \
            Affine2D().scale(1.0, 0.0) + \
            self.transData + \
            Affine2D().translate(0.0, -20.0)
        self._xaxis_text2_transform = \
            Affine2D().scale(1.0, 0.0) + \
            self.transData + \
            Affine2D().translate(0.0, -4.0)

        # Now set up the transforms for the latitude ticks.  The input to
        # these transforms are in axes space in x and display space in
        # y.  Therefore, the input values will be in range (0, -ymin),
        # (1, ymax).  The goal of these transforms is to go from that
        # space to display space.  The tick labels will be offset 4
        # pixels from the edge of the axes ellipse.

        self._yaxis_transform = self.transData
        yaxis_text_base = \
            self.transProjection + \
            (self.transAffine + \
             self.transAxes)
        self._yaxis_text1_transform = \
            yaxis_text_base + \
            Affine2D().translate(-8.0, 0.0)
        self._yaxis_text2_transform = \
            yaxis_text_base + \
            Affine2D().translate(8.0, 0.0)