簡體   English   中英

如何在 Matplotlib 中創建“點圖”? (不是散點圖)

[英]How to create a “dot plot” in Matplotlib? (not a scatter plot)

我想創建我的統計書所說的“點圖”,其中圖中的點數等於觀察數。 這是來自mathisfun.com的一個例子:

示例點圖

在該示例中,X 軸上0值上方有六個點,代表值為零的六個觀測值。

似乎“點圖”可以有多種變化。 在查找如何使用 Matplotlib 創建它時,我只遇到了我所知道的散點圖,其中數據點表示 X 和 Y 值之間的關系。

我嘗試使用 Matplotlib 創建的繪圖類型是否可行?

假設您有一些數據可以生成如下所示的直方圖,

import numpy as np; np.random.seed(13)
import matplotlib.pyplot as plt

data = np.random.randint(0,12,size=72)

plt.hist(data, bins=np.arange(13)-0.5, ec="k")

plt.show()

在此處輸入圖片說明

您可以通過計算直方圖並繪制所有可能點的散點圖來創建點圖,如果點的顏色超過直方圖給出的數字,則點的顏色為白色。

import numpy as np; np.random.seed(13)
import matplotlib.pyplot as plt

data = np.random.randint(0,12,size=72)
bins = np.arange(13)-0.5

hist, edges = np.histogram(data, bins=bins)

y = np.arange(1,hist.max()+1)
x = np.arange(12)
X,Y = np.meshgrid(x,y)

plt.scatter(X,Y, c=Y<=hist, cmap="Greys")

plt.show()

或者,您可以將不需要的點設置為nan

Y = Y.astype(np.float)
Y[Y>hist] = np.nan

plt.scatter(X,Y)

在此處輸入圖片說明

這個答案是建立在 eyllanesc 在他對該問題的評論中發布的代碼之上的,因為我覺得它足夠優雅,值得一個說明性的例子。 我提供了兩個版本:一個是手動設置格式參數的簡單版本,另一個是根據數據自動設置一些格式參數的第二個版本。

帶有手動格式的簡單版本

import numpy as np                 # v 1.19.2
import matplotlib.pyplot as plt    # v 3.3.2

# Create random data
rng = np.random.default_rng(123) # random number generator
data = rng.integers(0, 13, size=40)
values, counts = np.unique(data, return_counts=True)

# Draw dot plot with appropriate figure size, marker size and y-axis limits
fig, ax = plt.subplots(figsize=(6, 2.25))
for value, count in zip(values, counts):
    ax.plot([value]*count, list(range(count)), 'co', ms=10, linestyle='')
for spine in ['top', 'right', 'left']:
    ax.spines[spine].set_visible(False)
ax.yaxis.set_visible(False)
ax.set_ylim(-1, max(counts))
ax.set_xticks(range(min(values), max(values)+1))
ax.tick_params(axis='x', length=0, pad=8, labelsize=12)

plt.show()

dotplot_manual


具有自動格式化功能的高級版本

如果您計划經常使用此圖,添加一些自動格式化參數以獲得適當的圖形尺寸和標記大小會很有用。 在下面的示例中,參數的定義方式最適合這種類型的圖通常對其有用的數據類型(整數數據的范圍最多為幾十個單位,不超過幾百個數據分)。

# Create random data
rng = np.random.default_rng(1) # random number generator
data = rng.integers(0, 21, size=100)
values, counts = np.unique(data, return_counts=True)

# Set formatting parameters based on data
data_range = max(values)-min(values)
width = data_range/2 if data_range<30 else 15
height = max(counts)/3 if data_range<50 else max(counts)/4
marker_size = 10 if data_range<50 else np.ceil(30/(data_range//10))

# Create dot plot with appropriate format
fig, ax = plt.subplots(figsize=(width, height))
for value, count in zip(values, counts):
    ax.plot([value]*count, list(range(count)), marker='o', color='tab:blue',
            ms=marker_size, linestyle='')
for spine in ['top', 'right', 'left']:
    ax.spines[spine].set_visible(False)
ax.yaxis.set_visible(False)
ax.set_ylim(-1, max(counts))
ax.set_xticks(range(min(values), max(values)+1))
ax.tick_params(axis='x', length=0, pad=10)

plt.show()

dotplot_automated

將您的數據集傳遞給此函數:

def dot_diagram(dataset):
    values, counts = np.unique(dataset, return_counts=True)
    data_range = max(values)-min(values)
    width = data_range/2 if data_range<30 else 15
    height = max(counts)/3 if data_range<50 else max(counts)/4
    marker_size = 10 if data_range<50 else np.ceil(30/(data_range//10))
    fig, ax = plt.subplots(figsize=(width, height))
    for value, count in zip(values, counts):
        ax.plot([value]*count, list(range(count)), marker='o', color='tab:blue',
                ms=marker_size, linestyle='')
    for spine in ['top', 'right', 'left']:
        ax.spines[spine].set_visible(False)
    ax.yaxis.set_visible(False)
    ax.set_ylim(-1, max(counts))
    ax.set_xticks(range(min(values), max(values)+1))
    ax.tick_params(axis='x', length=0, pad=10)

假設這是我的數據:

data  = [5,8,3,7,1,5,3,2,3,3,8,5]

為了繪制“點圖”,我需要數據(x 軸)和頻率(y 軸)

pos = [] 
keys = {} # this dict will help to keep track ...

# this loop will give us a list of frequencies to each number
for num in data: 
   if num not in keys:
      keys[num] = 1
      pos.append(1)
   else:
      keys[num] += 1
      apos.append(keys[num])


print(pos)
[1, 1, 1, 1, 1, 2, 2, 1, 3, 4, 2, 3]

plt.scatter(data, pos)
plt.show()

在此處輸入圖片說明

暫無
暫無

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

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