还是大家熟悉的猴脑文章,可能是大家较为熟悉的一张UMAP图片,但是其呈现方式和其他的UMAP图片却是有所不同,它的UMAP图片如下所示,其名字为Voronoi图:

20240118160457

具体思想如下,画出每个点,然后找出两个点之间的平分线,遍历所有的点,完成构图,进行颜色填充,具体代码如下所示:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from scipy.spatial import Voronoi, voronoi_plot_2d
from shapely.geometry import Polygon

def bounded_voronoi(bnd, pnts):
    gn_pnts = np.concatenate([pnts, np.array([[100, 100], [100, -100], [-100, 0]])])
    vor = Voronoi(gn_pnts)
    bnd_poly = Polygon(bnd)
    vor_polys = []

    for i in range(len(gn_pnts) - 3):

        vor_poly = [vor.vertices[v] for v in vor.regions[vor.point_region[i]]]
        i_cell = bnd_poly.intersection(Polygon(vor_poly))
        vor_polys.append(list(i_cell.exterior.coords[:-1]))

    fig = plt.figure(figsize=(7, 6))
    ax = fig.add_subplot(111)

    ax.scatter(pnts[:,0], pnts[:,1], c =colors, zorder=2)

    poly_vor = PolyCollection(vor_polys, edgecolor="black",
                              facecolor="None", linewidth=1.0)
    poly_vor.set_facecolor(set_facecolor)
    ax.add_collection(poly_vor)

    xmin = np.min(bnd[:,0])
    xmax = np.max(bnd[:,0])
    ymin = np.min(bnd[:,1])
    ymax = np.max(bnd[:,1])

    # ax.set_xlim(xmin-0.1, xmax+0.1)
    # ax.set_ylim(ymin-0.1, ymax+0.1)
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)
    ax.set_aspect('equal')
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_xlabel('umap2')
    ax.set_ylabel('umap1')
    ax.set_title('My dont know system')
    plt.show()

    return vor_polys

代码结构非常简单,比较容易理解,具体的效果如下所示:

# 定义颜色颜色

colors = [
    '#FF0000', '#00FF00', '#0000FF', '#FFA500', '#800080', '#FFFF00', '#00FFFF', '#FF00FF', '#00FF00', '#FFC0CB',
    '#008080', '#E6E6FA', '#A52A2A', '#F5F5DC', '#800000', '#F5FFFA', '#808000', '#FF7F50', '#000080', '#808080',
    '#000000', '#C0C0C0', '#FFD700', '#4B0082', '#F0FFFF', '#EE82EE', '#D2B48C', '#FA8072', '#F0E68C', '#DDA0DD'
]
# 颜色亮度减小
def lighten_colors(colors, delta=0.5):
    lightened_colors = []
    for color in colors:
        r, g, b = tuple(int(color[i:i+2], 16) for i in (1, 3, 5))  # 将十六进制颜色转换为RGB值
        r = min(255, int(r + delta * (255 - r)))
        g = min(255, int(g + delta * (255 - g)))
        b = min(255, int(b + delta * (255 - b)))
        lightened_color = f"#{r:02x}{g:02x}{b:02x}"  # 将RGB值转换为十六进制颜色
        lightened_colors.append(lightened_color)
    return lightened_colors
set_facecolor = lighten_colors(colors, delta = 0.5)

# 代码调用
bnd = np.array([[0, 0], [1, 0], [1, 1], [0, 1]])

n = 30
pnts = np.random.rand(n, 2)

# 这里的 pnts 为你的UMAP数据
vor_polys = bounded_voronoi(bnd, pnts)

以上