使用偏移变换创建阴影特效
ScaledTranslation的另一个用途是创建另一个变换的偏移新变换,例如,将一个对象相对于另一个对象偏移一点。通常,您希望偏移在某种物理尺度上,如点或英寸,而不是在数据坐标中,这样在不同的缩放级别和dpi设置下,偏移效果是恒定的。 偏移的一个用途是创建阴影特效,即在其右侧和下方绘制一个与第一个对象相同的对象,调整zorder参数以确保首先绘制阴影,然后在其之上绘制阴影的源对象。 在这里,与上面相反的顺序使用ScaledTranslation进行变换。首先在数据坐标(ax.transData)中绘制图表,然后使用fig.dpi_scale_trans偏移dx和dy点。(在排版中,一个点是1/72英寸,通过以点为单位指定偏移量,无论保存的dpi分辨率如何,图形看起来都是一样的。)
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.transforms as transforms
fig, ax = plt.subplots()
# make a simple sine wavex = np.arange(0., 2., 0.01)y = np.sin(2*np.pi*x)line, = ax.plot(x, y, lw=3, color='blue')
# shift the object over 2 points, and down 2 pointsdx, dy = 2/72., -2/72.offset = transforms.ScaledTranslation(dx, dy, fig.dpi_scale_trans)shadow_transform = ax.transData + offset
# now plot the same data with our offset transform;# use the zorder to make sure we are below the lineax.plot(x, y, lw=3, color='gray', transform=shadow_transform, zorder=0.5*line.get_zorder())
ax.set_title('creating a shadow effect with an offset transform')plt.show()
注意:
dpi和英寸偏移量是一个非常常见的用例,我们有一个特殊的辅助函数来在matplotlib.transforms.offset_copy()中创建它,它返回一个添加了偏移量的新变换。因此,本例的阴影转换可以改为:
·
·
shadow_transform = transforms.offset_copy(ax.transData, fig, dx, dy, units='inches')
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.transforms as transforms
fig, ax = plt.subplots()
# make a simple sine wavex = np.arange(0., 2., 0.01)y = np.sin(2*np.pi*x)line, = ax.plot(x, y, lw=3, color='blue')
# shift the object over 2 points, and down 2 pointsdx, dy = 2/72., -2/72.shadow_transform = transforms.offset_copy(ax.transData, fig, dx, dy, units='inches')
# now plot the same data with our offset transform;# use the zorder to make sure we are below the lineax.plot(x, y, lw=3, color='gray', transform=shadow_transform, zorder=0.5*line.get_zorder())
ax.set_title('creating a shadow effect with an offset transform')plt.show()
转换的管道
我们在本教程中使用的ax.transData转换是三种不同转换的组合,它们构成了数据坐标到显示坐标的转换管道。Michael Droettboom实现了转换框架,精心设计了一个简洁的API,将极坐标图和对数图中的非线性映射和比例,与平移和缩放时发生的线性仿射转换分离开来。这里有一个效率问题,因为你可以在影响仿射变换的图表域上平移和缩放,但你可能不需要计算简单导航事件上潜在的昂贵非线性比例或映射。也可以将仿射变换矩阵相乘,然后一步将它们应用于坐标。并非所有可能的变换都是如此。
以下是如何在基本的可分离轴Axes类中定义ax.transData实例:
·
self.transData = self.transScale + (self.transLimits + self.transAxes)
我们已经在图表域坐标(Axes coordinates)中介绍了上面的transAxes实例,它将图表域或子图表边界框的(0, 0)、(1, 1)角映射到显示空间,所以让我们看看其他两部分。
self.transLimits是从数据坐标到图表域坐标的转换;即,它将视图xlim和ylim映射到图表域的单元空间(然后transAxes将该单元空间作为显示空间)。我们可以在下面的代码中看到这一点:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
In [1]: %matplotlib tk
In [2]: import matplotlib.pyplot as plt
In [3]: ax = plt.subplot()
In [4]: ax.set_xlim(0, 10)Out[4]: (0.0, 10.0)
In [7]: ax.set_ylim(-1, 1)Out[7]: (-1.0, 1.0)
In [8]: ax.transLimits.transform((0, -1))Out[8]: array([0., 0.])
In [9]: ax.transLimits.transform((10, -1))Out[9]: array([1., 0.])
In [10]: ax.transLimits.transform((10, 1))Out[10]: array([1., 1.])
In [11]: ax.transLimits.transform((5, 0))Out[11]: array([0.5, 0.5])
我们可以使用与之对应的逆变换,从单元图表域坐标回到数据坐标。
·
·
·
In [23]: inv = ax.transLimits.inverted()In [24]: inv.transform((0.25, 0.25))Out[24]: array([ 2.5, -0.5])
最后一部分是self.transScale属性,它负责数据的可选非线性缩放,例如对数图表域(axes)。当一个图表域(Axes)初始化时,只是设置为本体变换(identity transform),因为底层的Matplotlib图表域具有线性比例,但当你调用像semilogx()这样的对数缩放函数或使用set_xscale()显式将比例设置为对数时,ax.transScale属性将设置为处理非线性映射。缩放变换是各自xaxis和yaxis轴(Axis)实例的属性。例如,当调用ax.set_xscale('log')时,xaxis会将其比例更新为matplotlib.scale.LogScale实例。
对于不可分离的图表域PolarAxes,还有一件事需要考虑,那就是投影变换(projection transformation)。 matplotlib.projections.polar.PolarAxes的transData与典型的可分离matplotlib图表域类似,只增加了一个transProjection:
·
·
·
self.transData = ( self.transScale + self.transShift + self.transProjection + (self.transProjectionAffine + self.transWedge + self.transAxes))
transProjection处理从空间(例如,地图数据的纬度和经度,或极坐标数据的半径和θ)到可分离笛卡尔坐标系的投影。matplotlib.projections包中有几个投影示例,了解更多信息的最佳方法是打开这些包的源代码,看看如何制作自己的包,因为matplotlib支持可扩展的图表域(axes)和投影。Michael Droettboom提供了一个很好的创建Hammer投影图表域的教程示例;请参见自定义投影(Custom projection)。
ScaledTranslation:
https://matplotlib.org/stable/api/transformations.html#matplotlib.transforms.ScaledTranslation
matplotlib.transforms.offset_copy():
https://matplotlib.org/stable/api/transformations.html#matplotlib.transforms.offset_copy
Axes:
https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.html#matplotlib.axes.Axes
Axes coordinates:
https://matplotlib.org/stable/tutorials/advanced/transforms_tutorial.html#axes-coords
semilogx():
https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.semilogx.html#matplotlib.axes.Axes.semilogx
set_xscale():
https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_xscale.html#matplotlib.axes.Axes.set_xscale
Axis:
https://matplotlib.org/stable/api/axis_api.html#matplotlib.axis.Axis
matplotlib.scale.LogScale:
https://matplotlib.org/stable/api/scale_api.html#matplotlib.scale.LogScale
matplotlib.projections:
https://matplotlib.org/stable/api/projections_api.html#module-matplotlib.projections
Custom projection:
https://matplotlib.org/stable/gallery/misc/custom_projection.html