Python在繪製圖片散點圖

在讀Matten的Visualizing High-Dimensional Data Using t-SNE時,發現文中在展示t-SNE算法對MNIST數據的效果時,用每個點對應的圖片作爲散點,繪製出的散點圖感覺很有特色。

其實,使用Python也可以繪製出類似的效果。Python的可視化庫matplotlib中提供了一個“藝術家”的功能,可以用來實現這種效果。

實現代碼如下所示


import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import cm
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
import os
from PIL import Image
from sklearn.manifold import TSNE
from sklearn.decomposition import PCA


def mnist_pictures(path=""):
    """生成MNIST的圖片"""
    X = np.loadtxt(path+"data.csv", dtype=np.int, delimiter=",")
    (n, m) = X.shape
    X = 255*np.ones(X.shape) - X  # 黑白顛倒

    picture_path = path + "pictures\\"
    if not os.path.exists(picture_path):
        os.makedirs(picture_path)

    for i in range(0, n):
        new_data = np.reshape(X[i, :], (28, 28))
        im = Image.fromarray(new_data.astype(np.uint8))
        im.save(picture_path+str(i)+".png")
        if i % 1000 == 0:
            print(i)


def small_image(eta=0.5, in_path="", out_path=""):
    """
    將圖片進行縮放
    :param eta: 縮小的倍數
    :param in_path: 讀取圖片路徑
    :param out_path: 保存縮小後的圖片的路徑
    :return:
    """
    for root, middle, files in os.walk(in_path):
        for file_name in files:
            im = Image.open(in_path+file_name)
            (x, y) = im.size
            s_img = im.resize((int(x*eta), int(y*eta)), Image.ANTIALIAS)
            s_img.save(out_path+file_name)


def get_image(path):
    return OffsetImage(plt.imread(path))


def mnist_images(path=None, eta=0.4):
    """
    用MNIST數據畫藝術散點圖
    :return:
    """
    mnist_pictures(path)  # 先生成圖片

    small_path = path + "smallImages\\"
    if not os.path.exists(small_path):
        os.makedirs(small_path)
    small_image(eta=eta, in_path=path+"pictures\\", out_path=small_path)
    Y = np.loadtxt(path + "y.csv", dtype=np.float, delimiter=",")
    (n, m) = Y.shape
    fig, ax = plt.subplots()

    ax.scatter(Y[:, 0], Y[:, 1])
    plt.set_cmap(cm.gray)  # 修改顏色映射
    for i in range(0, n):
        ab = AnnotationBbox(get_image(small_path + str(i)+".png"), (Y[i, 0], Y[i, 1]), frameon=False)
        ax.add_artist(ab)
    ax = plt.gca()
    ax.set_aspect(1)
    plt.show()


if __name__ == '__main__':
    path = "E:\\Project\\DataLab\\MNISTdigit\\"
    X = np.loadtxt(path+"data.csv", dtype=np.int, delimiter=",")
    (n, m) = X.shape
    pca = PCA(n_components=50)
    pca_y = pca.fit_transform(X)  # 先用PCA初步降維
    t_sne = TSNE(n_components=2, perplexity=30.0)
    Y = t_sne.fit_transform(pca_y)  # 用t-SNE得到最後的二維座標
    np.savetxt(path+"y.csv", Y, fmt="%f", delimiter=",")
    mnist_images(path=path, eta=0.5)

這段代碼是將MNIST-digits數據集中的2500個點,先使用PCA方法去除噪音,將數據降維至50維,然後用t-SNE方法將數據降維至二維,得到散點的座標。然後使用matplotlib中的“藝術家”方法,將每個樣本對應的手寫數字圖片放到散點圖中的相應座標位置,畫出圖片散點圖。由於降維方法不是本文的主要內容,因而直接調用sklearn庫中的對應函數,沒有再重新去寫。最後實現的圖片散點圖效果如下。

需要注意的是,在繪圖的時候需要對matplotlib.pyplot的顏色映射進行修改:

plt.set_cmap(cm.gray)  # 修改顏色映射

否則,按照matplotlib.pyplot默認的顏色映射畫出來的圖片會偏黃綠色,就像下面的一樣:

這個問題的解決需要感謝pycharm中matplotlib顯示圖像的顏色不對。另外,本文雖然實現了圖片散點圖,但是與Matten的原圖還有些差距,應該是沒有把圖片的背景設置爲透明的緣故。

本文所用到的數據可點擊MNISTdigit.rar進行下載。如有更好的方法,歡迎通過QQ進行深入交流。

發佈了189 篇原創文章 · 獲贊 240 · 訪問量 56萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章