Построение линий для уникальной метки в col — Python

#python #pandas #matplotlib

#python #pandas #matplotlib

Вопрос:

Я пытаюсь передать функцию, которая отображает различные объекты для каждой уникальной метки. Используя df ниже, A-D используются для построения различных объектов. Затем я передаю каждое уникальное значение в label функцию.

Я надеюсь передать что-то более эффективное, чем вызов функции для каждого уникального элемента в списке. Перебор списка для получения отдельной цифры для каждого уникального значения в label . Используя ниже, это должно быть 3 (X,Y,Z) .

  import pandas as pd
 import matplotlib.pyplot as plt
 import numpy as np
 import random

def plot(dfs, label):

    fig, ax = plt.subplots()

    for l in label:

        df = dfs[dfs['label'] == l]

        x1 = df['A']
        y1 = df['B']

        x2 = df['C']
        y2 = df['D']

        plt.scatter(x1, y1, c = 'orange', marker = 'o', zorder = 3)
        plt.scatter(x2, y2, c = 'green', marker = 'o', zorder = 2)

        ax.plot([x1,x2],[y1,y2], color = 'k', linestyle = '-', linewidth = 1) 

    plt.show()  

np.random.seed(2020)
df = pd.DataFrame(np.random.randint(0,20,size=(20, 4)), columns=list('ABCD'))
labels = df['A'].apply(lambda x: random.choice(['X', 'Y', 'Z']) ) 
df['label'] = labels

unq_label = df['label'].unique()

figs = df.groupby('label').apply(plot,unq_label)
  

Ответ №1:

@r-beginners уже решил проблему. В моем посте я также решу эту проблему, используя тот же (возможно, единственный) способ, но с другим Dataframe для лучшей визуализации.

 import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import random

def plot(dfs, label):
    
    label = sorted(label)
    fig, ax = plt.subplots(nrows=1,ncols=len(label),figsize=(12,6))

    for ind,l in enumerate(label):

        df = dfs[dfs['label'] == l]

        x1 = df['A']
        y1 = df['B']

        x2 = df['C']
        y2 = df['D']

        ax[ind].scatter(x1, y1, c = 'orange', marker = 'o', zorder = 3,)
        ax[ind].scatter(x2, y2, c = 'green', marker = 'o', zorder = 2,)
        ax[ind].plot([x1,x2],[y1,y2], color = 'k', linestyle = '-', linewidth = 1,)
        ax[ind].set_title('class %s' % l)
        ax[ind].set_ylim(-11,21)

    plt.show()  

np.random.seed(2020)
x,y,z = np.random.randint(0,5,size=(5, 4)),np.random.randint(-10,0,size=(5, 4)),np.random.randint(10,20,size=(5, 4)),
data = np.vstack((x,y,z))
df = pd.DataFrame(data, columns=list('ABCD'))
df['label'] = ['X'] *5   ['Y'] * 5   ['Z'] * 5

unq_label = df['label'].unique()
plot(df, unq_label)
  

Выходная цифра

вывод


Обновить

Чтобы отображать разные метки на разных рисунках, а не на подзаголовках, вы можете попробовать приведенный ниже код. Идея состоит в том, чтобы создать новую фигуру для каждой метки.

 import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import random

def plot(dfs, label):
    
    label = sorted(label)
    for ind,l in enumerate(label):
        
        fig = plt.figure(ind)
        df = dfs[dfs['label'] == l]

        x1 = df['A']
        y1 = df['B']

        x2 = df['C']
        y2 = df['D']

        plt.scatter(x1, y1, c = 'orange', marker = 'o', zorder = 3,)
        plt.scatter(x2, y2, c = 'green', marker = 'o', zorder = 2,)
        plt.plot([x1,x2],[y1,y2], color = 'k', linestyle = '-', linewidth = 1,)
        plt.title('class %s' % l)
        plt.ylim(-11,21)

        plt.show()  

np.random.seed(2020)
x,y,z = np.random.randint(0,5,size=(5, 4)),np.random.randint(-10,0,size=(5, 4)),np.random.randint(10,20,size=(5, 4)),
data = np.vstack((x,y,z))
df = pd.DataFrame(data, columns=list('ABCD'))
df['label'] = ['X'] *5   ['Y'] * 5   ['Z'] * 5

unq_label = df['label'].unique()
plot(df, unq_label)
  

Комментарии:

1. Я надеюсь получить выходные данные. Итак, отдельная цифра для каждой уникальной метки. Не отдельные подзаголовки в пределах одного рисунка.

2. это то, что я искал df.groupby('label').apply(plot,unq_label)

3. @jonboy Я понимаю, см. Мой обновленный пост, идея состоит в том, чтобы создать новую фигуру для каждой уникальной метки.

Ответ №2:

По мере развития вопроса я изменил код для текущей проблемы. axes[] чтобы сделать его массивом. Так ли это задумано?

 import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import random

def plot(dfs, label):

    fig, axes = plt.subplots(1,3)

    for i,l in enumerate(label):

        df = dfs[dfs['label'] == l]

        x1 = df['A']
        y1 = df['B']

        x2 = df['C']
        y2 = df['D']

        axes[i].scatter(x1, y1, c = 'orange', marker = 'o', zorder = 3)
        axes[i].scatter(x2, y2, c = 'green', marker = 'o', zorder = 2)

        axes[i].plot([x1,x2],[y1,y2], color = 'k', linestyle = '-', linewidth = 1) 
    fig.subplots_adjust(wspace=0.5)
    plt.show()  

np.random.seed(2020)
df = pd.DataFrame(np.random.randint(0,20,size=(20, 4)), columns=list('ABCD'))
labels = df['A'].apply(lambda x: random.choice(['X', 'Y', 'Z']) ) 
df['label'] = labels

unq_label = df['label'].unique()
plot(df, unq_label)
  

введите описание изображения здесь

Комментарии:

1. Я получаю сообщение об ошибке в строке : ax.plot([Ax,Cx],[By,Dy], color = 'k', linestyle = '-', linewidth = 1) . Error: KeyError: 0

2. print(df) чтобы увидеть, существуют ли данные. В этом случае легче отлаживать, если вы установите np.random.seed(2020) значение до генерации случайного числа. Это не генерирует ошибку в моей среде. Вы скопировали весь код?

3. Да, данные существуют. Я ввел начальное значение. Я думаю, что это количество элементов на этикетке. Если я увеличу длину df до 1000 значений, это сработает. Но я надеюсь построить отдельные цифры для каждой уникальной метки.

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