簡體   English   中英

通過x比例縮放matplotlib.pyplot.Axes.scatter標記大小

[英]Scale matplotlib.pyplot.Axes.scatter markersize by x-scale

我想根據x / y軸上的點數來縮放matplotlib.pyplot.Axes.scatter圖的markersize

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值。

當前,運行上面的代碼會生成以下圖... 在此處輸入圖片說明

...並更改vmax = 41的值 在此處輸入圖片說明

兩個圖中的markersize均保留默認值,即markersize=6

我的問題是,我該如何計算markersize值,使marker觸及每個單元格的邊緣? (每個單元格最多有一個數據點。)

使用圈子

一個簡單的選擇是用由半徑為0.5的Circles組成的PatchCollection代替散點圖。

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)

在此處輸入圖片說明

將散點圖與數據單位的大小標記一起使用

如果需要散點圖,則替代方法是將標記大小更新為數據單位。

此處簡單的解決方案是先繪制一次圖形,然后獲取軸尺寸並從中計算出標記尺寸(以磅為單位)。

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()

有關如何使用散布的標記大小的一些背景知識,請參見此答案 上述解決方案的缺點是將標記大小固定為繪圖的大小和狀態。 萬一軸的極限發生變化或圖被放大,散布圖的大小將再次錯誤。

因此,以下解決方案將更為通用。 這涉及到一點點,並且其工作原理與繪制以數據單位為寬度的線類似。

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()

(由於這個問題 ,我更新了代碼以使用計時器重繪畫布)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM