Есть ли функция для создания матриц рассеяния в matplotlib? - PullRequest
48 голосов
/ 29 октября 2011

Пример матрицы рассеяния

enter image description here

Есть ли такая функция в matplotlib.pyplot?

Ответы [ 5 ]

96 голосов
/ 17 ноября 2013

Для тех, кто не хочет определять свои собственные функции, в Python есть большая библиотека для анализа данных, которая называется Pandas , где можно найти метод scatter_matrix () :

from pandas.plotting import scatter_matrix
df = pd.DataFrame(np.random.randn(1000, 4), columns = ['a', 'b', 'c', 'd'])
scatter_matrix(df, alpha = 0.2, figsize = (6, 6), diagonal = 'kde')

enter image description here

21 голосов
/ 30 октября 2011

Вообще говоря, matplotlib обычно не содержит функций построения графиков, которые работают более чем с одним объектом осей (в данном случае подпотоком). Ожидается, что вы напишите простую функцию, чтобы связать все вместе, как вам захочется.

Я не совсем уверен, как выглядят ваши данные, но довольно просто создать функцию, чтобы сделать это с нуля. Если вы всегда будете работать со структурированными массивами или массивами записей, вы можете упростить эту задачу. (т. е. с каждой серией данных всегда связано имя, поэтому вы можете не указывать имена).

Как пример:

import itertools
import numpy as np
import matplotlib.pyplot as plt

def main():
    np.random.seed(1977)
    numvars, numdata = 4, 10
    data = 10 * np.random.random((numvars, numdata))
    fig = scatterplot_matrix(data, ['mpg', 'disp', 'drat', 'wt'],
            linestyle='none', marker='o', color='black', mfc='none')
    fig.suptitle('Simple Scatterplot Matrix')
    plt.show()

def scatterplot_matrix(data, names, **kwargs):
    """Plots a scatterplot matrix of subplots.  Each row of "data" is plotted
    against other rows, resulting in a nrows by nrows grid of subplots with the
    diagonal subplots labeled with "names".  Additional keyword arguments are
    passed on to matplotlib's "plot" command. Returns the matplotlib figure
    object containg the subplot grid."""
    numvars, numdata = data.shape
    fig, axes = plt.subplots(nrows=numvars, ncols=numvars, figsize=(8,8))
    fig.subplots_adjust(hspace=0.05, wspace=0.05)

    for ax in axes.flat:
        # Hide all ticks and labels
        ax.xaxis.set_visible(False)
        ax.yaxis.set_visible(False)

        # Set up ticks only on one side for the "edge" subplots...
        if ax.is_first_col():
            ax.yaxis.set_ticks_position('left')
        if ax.is_last_col():
            ax.yaxis.set_ticks_position('right')
        if ax.is_first_row():
            ax.xaxis.set_ticks_position('top')
        if ax.is_last_row():
            ax.xaxis.set_ticks_position('bottom')

    # Plot the data.
    for i, j in zip(*np.triu_indices_from(axes, k=1)):
        for x, y in [(i,j), (j,i)]:
            axes[x,y].plot(data[x], data[y], **kwargs)

    # Label the diagonal subplots...
    for i, label in enumerate(names):
        axes[i,i].annotate(label, (0.5, 0.5), xycoords='axes fraction',
                ha='center', va='center')

    # Turn on the proper x or y axes ticks.
    for i, j in zip(range(numvars), itertools.cycle((-1, 0))):
        axes[j,i].xaxis.set_visible(True)
        axes[i,j].yaxis.set_visible(True)

    return fig

main()

enter image description here

12 голосов
/ 01 июня 2016

Вы также можете использовать Seaborn's pairplot function :

import seaborn as sns
sns.set()
df = sns.load_dataset("iris")
sns.pairplot(df, hue="species")
10 голосов
/ 10 мая 2013

Спасибо, что поделились своим кодом!Вы выяснили все сложные вещи для нас.Работая с ним, я заметил несколько мелочей, которые выглядели не совсем правильно.

  1. [FIX # 1] Тики оси не выстраивались так, как я ожидал(т. е. в приведенном выше примере вы должны быть в состоянии нарисовать вертикальную и горизонтальную линию через любую точку на всех графиках, и линии должны пересекать соответствующую точку на других графиках, но, поскольку она установлена ​​сейчас, этого не происходит.

  2. [FIX # 2] Если у вас есть нечетное количество переменных, с которыми вы строите график, то ось нижнего правого угла не вытягивает правильный xtics или ytic. Он просто оставляетотметки по умолчанию 0..1.

  3. Не исправлено, но я сделал необязательным явный ввод names, так что в переменной i устанавливается значение по умолчанию xiдиагональные позиции.

Ниже вы найдете обновленную версию своего кода, в которой рассматриваются эти две точки, в противном случае сохраняется красота вашего кода.

import itertools
import numpy as np
import matplotlib.pyplot as plt

def scatterplot_matrix(data, names=[], **kwargs):
    """
    Plots a scatterplot matrix of subplots.  Each row of "data" is plotted
    against other rows, resulting in a nrows by nrows grid of subplots with the
    diagonal subplots labeled with "names".  Additional keyword arguments are
    passed on to matplotlib's "plot" command. Returns the matplotlib figure
    object containg the subplot grid.
    """
    numvars, numdata = data.shape
    fig, axes = plt.subplots(nrows=numvars, ncols=numvars, figsize=(8,8))
    fig.subplots_adjust(hspace=0.0, wspace=0.0)

    for ax in axes.flat:
        # Hide all ticks and labels
        ax.xaxis.set_visible(False)
        ax.yaxis.set_visible(False)

        # Set up ticks only on one side for the "edge" subplots...
        if ax.is_first_col():
            ax.yaxis.set_ticks_position('left')
        if ax.is_last_col():
            ax.yaxis.set_ticks_position('right')
        if ax.is_first_row():
            ax.xaxis.set_ticks_position('top')
        if ax.is_last_row():
            ax.xaxis.set_ticks_position('bottom')

    # Plot the data.
    for i, j in zip(*np.triu_indices_from(axes, k=1)):
        for x, y in [(i,j), (j,i)]:
            # FIX #1: this needed to be changed from ...(data[x], data[y],...)
            axes[x,y].plot(data[y], data[x], **kwargs)

    # Label the diagonal subplots...
    if not names:
        names = ['x'+str(i) for i in range(numvars)]

    for i, label in enumerate(names):
        axes[i,i].annotate(label, (0.5, 0.5), xycoords='axes fraction',
                ha='center', va='center')

    # Turn on the proper x or y axes ticks.
    for i, j in zip(range(numvars), itertools.cycle((-1, 0))):
        axes[j,i].xaxis.set_visible(True)
        axes[i,j].yaxis.set_visible(True)

    # FIX #2: if numvars is odd, the bottom right corner plot doesn't have the
    # correct axes limits, so we pull them from other axes
    if numvars%2:
        xlimits = axes[0,-1].get_xlim()
        ylimits = axes[-1,0].get_ylim()
        axes[-1,-1].set_xlim(xlimits)
        axes[-1,-1].set_ylim(ylimits)

    return fig

if __name__=='__main__':
    np.random.seed(1977)
    numvars, numdata = 4, 10
    data = 10 * np.random.random((numvars, numdata))
    fig = scatterplot_matrix(data, ['mpg', 'disp', 'drat', 'wt'],
            linestyle='none', marker='o', color='black', mfc='none')
    fig.suptitle('Simple Scatterplot Matrix')
    plt.show()

Спасибоснова, чтобы поделиться этим с нами. У меня естьиспользовал это много раз!О, и я перестроил часть кода main() так, чтобы он мог быть формальным примером кода или не вызываться, если он импортируется в другой фрагмент кода.

4 голосов
/ 22 июня 2013

Читая вопрос, я ожидал увидеть ответ, включающий rpy .Я думаю, что это хороший вариант, использующий два прекрасных языка.Итак, вот оно:

import rpy
import numpy as np

def main():
    np.random.seed(1977)
    numvars, numdata = 4, 10
    data = 10 * np.random.random((numvars, numdata))
    mpg = data[0,:]
    disp = data[1,:]
    drat = data[2,:]
    wt = data[3,:]
    rpy.set_default_mode(rpy.NO_CONVERSION)

    R_data = rpy.r.data_frame(mpg=mpg,disp=disp,drat=drat,wt=wt)

    # Figure saved as eps
    rpy.r.postscript('pairsPlot.eps')
    rpy.r.pairs(R_data,
       main="Simple Scatterplot Matrix Via RPy")
    rpy.r.dev_off()

    # Figure saved as png
    rpy.r.png('pairsPlot.png')
    rpy.r.pairs(R_data,
       main="Simple Scatterplot Matrix Via RPy")
    rpy.r.dev_off()

    rpy.set_default_mode(rpy.BASIC_CONVERSION)


if __name__ == '__main__': main()

Я не могу опубликовать изображение, чтобы показать результат :( извините!

...