通过x-scale缩放matplotlib.pyplot.Axes.scatter标记大小 [英] Scale matplotlib.pyplot.Axes.scatter markersize by x-scale
问题描述
我想根据x/y轴上的点数来缩放matplotlib.pyplot.Axes.scatter
图的markersize
.
I would like to scale the markersize
of matplotlib.pyplot.Axes.scatter
plot based on the number of points on the x/y-axis.
import matplotlib.pyplot as plt
import numpy as np
vmin = 1
vmax = 11
x = np.random.randint(vmin, vmax, 5)
y = np.random.randint(vmin, vmax, 5)
fig, ax = plt.subplots()
for v in np.arange(vmin, vmax):
ax.axvline(v - 0.5)
ax.axvline(v + 0.5)
ax.axhline(v - 0.5)
ax.axhline(v + 0.5)
ax.set_xlim(vmin - 0.5, vmax + 0.5)
ax.set_ylim(vmin - 0.5, vmax + 0.5)
ax.scatter(x, y)
ax.set_aspect(1)
plt.show()
ax
始终使用相同的纵横比,并且两个轴具有相同的lim
值.
ax
is always using an equal aspect ratio and both axes have the same lim
values.
当前,运行上述命令将生成以下图...
Currently, running the above generates the following plot ...
...并更改vmax = 41
的值
...and changing the value of vmax = 41
两个图中的markersize
保留默认值,即markersize=6
.
The markersize
in both plots is left to the default, i.e. markersize=6
.
我的问题是,如何计算markersize
值,以使marker
接触每个单元格的边缘? (每个单元格最多有一个数据点.)
My question is, how could I compute the markersize
value so the marker
s touch the edges of each cell? (Each cell has a maximum of one data point.)
推荐答案
使用圆圈
一个简单的选择是用由半径为0.5的Circles
组成的PatchCollection
代替散点.
Using Circles
An easy option is to replace the scatter by a PatchCollection
consisting of Circles
of radius 0.5.
circles = [plt.Circle((xi,yi), radius=0.5, linewidth=0) for xi,yi in zip(x,y)]
c = matplotlib.collections.PatchCollection(circles)
ax.add_collection(c)
如果需要散点图,则替代方法是将标记大小更新为数据单位.
The alternative, if a scatter plot is desired, would be to update the markersize to be in data units.
这里的简单解决方案是先绘制一次图形,然后获取轴尺寸并从中计算出标记尺寸(以磅为单位).
The easy solution here would be to first draw the figure once, then take the axes size and calculate the markersize in points from it.
import matplotlib.pyplot as plt
import numpy as np
vmin = 1
vmax = 11
x = np.random.randint(vmin, vmax, 5)
y = np.random.randint(vmin, vmax, 5)
fig, ax = plt.subplots(dpi=141)
for v in np.arange(vmin, vmax):
ax.axvline(v - 0.5)
ax.axvline(v + 0.5)
ax.axhline(v - 0.5)
ax.axhline(v + 0.5)
ax.set_xlim(vmin - 0.5, vmax + 0.5)
ax.set_ylim(vmin - 0.5, vmax + 0.5)
ax.set_aspect(1)
fig.canvas.draw()
s = ((ax.get_window_extent().width / (vmax-vmin+1.) * 72./fig.dpi) ** 2)
ax.scatter(x, y, s = s, linewidth=0)
plt.show()
有关如何使用散点标记大小的背景知识,请参见例如此答案.上述解决方案的缺点是将标记大小固定为绘图的大小和状态.万一轴的极限发生变化或图被缩放,散布图的大小将再次错误.
For some background on how markersize of scatters is used, see e.g. this answer. The drawback of the above solution is that is fixes the marker size to the size and state of the plot. In case the axes limits would change or the plot is zoomed, the scatter plot would again have the wrong sizing.
因此,以下解决方案将更通用. 这有点涉及,并且与绘制宽度以数据单位表示的行.
Hence the following solution would be more generic. This is a little involved and would work similarly as Plotting a line with width in data units.
import matplotlib.pyplot as plt
import numpy as np
vmin = 1
vmax = 32
x = np.random.randint(vmin, vmax, 5)
y = np.random.randint(vmin, vmax, 5)
fig, ax = plt.subplots()
for v in np.arange(vmin, vmax):
ax.axvline(v - 0.5)
ax.axvline(v + 0.5)
ax.axhline(v - 0.5)
ax.axhline(v + 0.5)
ax.set_xlim(vmin - 0.5, vmax + 0.5)
ax.set_ylim(vmin - 0.5, vmax + 0.5)
class scatter():
def __init__(self,x,y,ax,size=1,**kwargs):
self.n = len(x)
self.ax = ax
self.ax.figure.canvas.draw()
self.size_data=size
self.size = size
self.sc = ax.scatter(x,y,s=self.size,**kwargs)
self._resize()
self.cid = ax.figure.canvas.mpl_connect('draw_event', self._resize)
def _resize(self,event=None):
ppd=72./self.ax.figure.dpi
trans = self.ax.transData.transform
s = ((trans((1,self.size_data))-trans((0,0)))*ppd)[1]
if s != self.size:
self.sc.set_sizes(s**2*np.ones(self.n))
self.size = s
self._redraw_later()
def _redraw_later(self):
self.timer = self.ax.figure.canvas.new_timer(interval=10)
self.timer.single_shot = True
self.timer.add_callback(lambda : self.ax.figure.canvas.draw_idle())
self.timer.start()
sc = scatter(x,y,ax, linewidth=0)
ax.set_aspect(1)
plt.show()
这篇关于通过x-scale缩放matplotlib.pyplot.Axes.scatter标记大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!