Seaborn Clustermap фиксированный размер ячейки - PullRequest
0 голосов
/ 14 октября 2018

Я использую функцию seaborn clustermap , и я хотел бы сделать несколько графиков, где размеры ячеек абсолютно идентичны.Также размер меток оси должен быть одинаковым.Это означает, что размер фигуры и пропорции должны будут измениться, остальные должны остаться идентичными.

import pandas 
import seaborn
import numpy as np
dataFrameA = pd.DataFrame([ [1,2],[3,4] ])
dataFrameB = pd.DataFrame( np.arange(3*6).reshape(3,-1))

Затем решите, насколько большим должна быть сама карта кластера, что-то вроде:

dpi = 72
cellSizePixels = 150

Это решает, что dataFrameA должен быть размером 300 на 300 пикселей.Я думаю, что они должны быть преобразованы в единицы размера фигуры, которые будут единицами cellSizePixels / dpi на пиксель.Так что для dataFrameA это будет размер тепловой карты ~ 2,01 дюйма.Здесь я представляю проблему: вокруг тепловой карты есть вещи, которые также займут некоторое пространство, и я не знаю, сколько места они точно займут.

Я попытался параметризовать функцию тепловой карты с помощью предположения о размере изображения, используя формулу выше:

def fixedWidthClusterMap( dpi, cellSizePixels, dataFrame):
    clustermapParams = {
        'square':False # Tried to set this to True before. Don't: the dendograms do not scale well with it.
    }
    figureWidth = (cellSizePixels/dpi)*dataFrame.shape[1]
    figureHeight= (cellSizePixels/dpi)*dataFrame.shape[0]
    return sns.clustermap( dataFrame, figsize=(figureWidth,figureHeight), **clustermapParams)

fixedWidthClusterMap(dpi, cellSizePixels, dataFrameA)
plt.show()
fixedWidthClusterMap(dpi, cellSizePixels, dataFrameB)
plt.show()

Это дает: Seaborn clustermap with bad scaling

Мой вопрос: как получить квадратные ячейки именно того размера, который я хочу?

1 Ответ

0 голосов
/ 15 октября 2018

Это немного сложно, потому что есть немало вещей, которые нужно принять во внимание, и, в конце концов, все зависит от того, насколько «точными» вам нужны размеры.

Взгляд на код для clustermap части тепловой карты имеет коэффициент 0,8 по сравнению с осями, используемыми для дендрограмм.Но нам также нужно учитывать поля, используемые для размещения осей.Если кто-то знает размер осей тепловой карты, он должен быть в состоянии рассчитать желаемый размер фигуры, который бы дал правильную форму.

dpi = matplotlib.rcParams['figure.dpi']
marginWidth = matplotlib.rcParams['figure.subplot.right']-matplotlib.rcParams['figure.subplot.left']
marginHeight = matplotlib.rcParams['figure.subplot.top']-matplotlib.rcParams['figure.subplot.bottom']
Ny,Nx = dataFrame.shape
figWidth = (Nx*cellSizePixels/dpi)/0.8/marginWidth
figHeigh = (Ny*cellSizePixels/dpi)/0.8/marginHeight

К сожалению, кажется, что matplotlib должен немного отрегулировать во время построения графикапотому что этого было недостаточно, чтобы получить идеально квадратные ячейки тепловой карты.Поэтому я решил изменить размеры различных осей, созданных на clustermap после факта, начиная с тепловой карты, затем осей дендрограммы.

Я думаю, что полученное изображение довольно близко к тому, что вы пытались получить, номои тесты иногда показывают некоторые ошибки на 1-2 пикселя, которые я приписываю ошибкам округления из-за всех преобразований между размерами в дюймах и пикселях.

dataFrameA = pd.DataFrame([ [1,2],[3,4] ])
dataFrameB = pd.DataFrame( np.arange(3*6).reshape(3,-1))

def fixedWidthClusterMap(dataFrame, cellSizePixels=50):
    # Calulate the figure size, this gets us close, but not quite to the right place
    dpi = matplotlib.rcParams['figure.dpi']
    marginWidth = matplotlib.rcParams['figure.subplot.right']-matplotlib.rcParams['figure.subplot.left']
    marginHeight = matplotlib.rcParams['figure.subplot.top']-matplotlib.rcParams['figure.subplot.bottom']
    Ny,Nx = dataFrame.shape
    figWidth = (Nx*cellSizePixels/dpi)/0.8/marginWidth
    figHeigh = (Ny*cellSizePixels/dpi)/0.8/marginHeight

    # do the actual plot
    grid = sns.clustermap(dataFrame, figsize=(figWidth, figHeigh))

    # calculate the size of the heatmap axes
    axWidth = (Nx*cellSizePixels)/(figWidth*dpi)
    axHeight = (Ny*cellSizePixels)/(figHeigh*dpi)

    # resize heatmap
    ax_heatmap_orig_pos = grid.ax_heatmap.get_position()
    grid.ax_heatmap.set_position([ax_heatmap_orig_pos.x0, ax_heatmap_orig_pos.y0, 
                                  axWidth, axHeight])

    # resize dendrograms to match
    ax_row_orig_pos = grid.ax_row_dendrogram.get_position()
    grid.ax_row_dendrogram.set_position([ax_row_orig_pos.x0, ax_row_orig_pos.y0, 
                                         ax_row_orig_pos.width, axHeight])
    ax_col_orig_pos = grid.ax_col_dendrogram.get_position()
    grid.ax_col_dendrogram.set_position([ax_col_orig_pos.x0, ax_heatmap_orig_pos.y0+axHeight,
                                         axWidth, ax_col_orig_pos.height])
    return grid # return ClusterGrid object

grid = fixedWidthClusterMap(dataFrameA, cellSizePixels=75)
plt.show()
grid = fixedWidthClusterMap(dataFrameB, cellSizePixels=75)
plt.show()

enter image description here enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...