Как перебрать список по списку для точечного графика и создать легенду об уникальных элементах - PullRequest
0 голосов
/ 13 февраля 2020

Фон:

У меня есть list_of_x_and_y_list, который содержит x и y значения, которые выглядят так:

[[(44800, 14888), (132000, 12500), (40554, 12900)], [(None, 193788), (101653, 78880), (3866, 160000)]]

У меня есть еще data_name_list ["data_a","data_b"] так что

  • "data_a" = [(44800, 14888), (132000, 12500), (40554, 12900)]

  • "data_b" = [(None, 193788), (101653, 78880), (3866, 160000)]

len из list_of_x_and_y_list / или len из data_name_list -> 20.

Вопрос:

Как создать точечный график для каждого элемента (того же цвета) в data_name_list?

Что я пробовал:

   fig = plt.figure()
   ax = fig.add_subplot(1, 1, 1)
   ax = plt.axes(facecolor='#FFFFFF')
   prop_cycle = plt.rcParams['axes.prop_cycle']
   colors = prop_cycle.by_key()['color']

   print(list_of_x_and_y_list)
   for x_and_y_list, data_name, color in zip(list_of_x_and_y_list, data_name_list, colors):
       for x_and_y in x_and_y_list,:
          print(x_and_y)
          x, y = x_and_y
          ax.scatter(x, y, label=data_name, color=color) # "label=data_name" creates 
                                                         # a huge list as a legend! 
                                                         # :(


       plt.title('Matplot scatter plot')
       plt.legend(loc=2)
       file_name = "3kstc.png"
       fig.savefig(file_name, dpi=fig.dpi)
       print("Generated: {}".format(file_name))

Проблема:

Легенда выглядит очень длинным списком, который я не знаю, как исправить:

enter image description here

Соответствующее исследование:

Ответы [ 2 ]

2 голосов
/ 13 февраля 2020

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

Быстрое исправление состоит в том, чтобы перебрать список и сжать вместе значения x и y для каждой серии в виде двух кортежей, чтобы кортеж x содержал все значения x, а кортеж y - значения y.

Затем вы можете передать эти кортежи в метод plt.plot вместе с метками.

Я чувствовал, что имена list_of_x_and_y_list были излишне длинными и сложными, поэтому в моем коде я использовал более короткие имена.

import matplotlib.pyplot as plt

data_series = [[(44800, 14888), (132000, 12500), (40554, 12900)],
               [(None, 193788), (101653, 78880), (3866, 160000)]]
data_names = ["data_a","data_b"]

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax = plt.axes(facecolor='#FFFFFF')
prop_cycle = plt.rcParams['axes.prop_cycle']
colors = prop_cycle.by_key()['color']

for data, data_name, color in zip(data_series, data_names, colors):
    x,y = zip(*data)
    ax.scatter(x, y, label=data_name, color=color)
    plt.title('Matplot scatter plot')
    plt.legend(loc=1)

Output

1 голос
/ 13 февраля 2020

Чтобы получить только одну запись для data_name, вы должны добавить data_name только один раз в качестве метки. Остальные звонки должны go с label=None. Простейшее, чего вы можете добиться, используя текущий код, это установить для data_name значение None в конце l oop:

from matplotlib import pyplot as plt
from random import randint

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_facecolor('#FFFFFF')
# create some random data, suppose the sublists have different lengths
list_of_x_and_y_list = [[(randint(1000, 4000), randint(2000, 5000)) for col in range(randint(2, 10))]
                        for row in range(10)]
data_name_list = list('abcdefghij')
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
for x_and_y_list, data_name, color in zip(list_of_x_and_y_list, data_name_list, colors):
    for x_and_y in x_and_y_list :
        x, y = x_and_y
        ax.scatter(x, y, label=data_name, color=color)
        data_name = None
plt.legend(loc=2)
plt.show()

Некоторые вещи можно упростить, сделав код «более pythoni» c ', например:

for x_and_y in x_and_y_list :
    x, y = x_and_y

можно записать как:

for x, y in x_and_y_list:

Другая проблема заключается в том, что при большом количестве данных для каждой точки может быть вызван scatter довольно медленно Все x и y, принадлежащие одному и тому же списку, можно построить вместе. Например, используя понимание списка :

for x_and_y_list, data_name, color in zip(list_of_x_and_y_list, data_name_list, colors):
    xs = [x for x, y in x_and_y_list]
    ys = [y for x, y in x_and_y_list]
    ax.scatter(xs, ys, label=data_name, color=color)

scatter можно даже получить список цветов на точку, но построение всех точек в одном go не позволит меток на data_name.

Очень часто numpy используется для хранения числовых данных. Это имеет некоторые преимущества, такие как векторизация для быстрых вычислений. С numpy код будет выглядеть так:

import numpy as np

for x_and_y_list, data_name, color in zip(list_of_x_and_y_list, data_name_list, colors):
    xys = np.array(x_and_y_list)
    ax.scatter(xys[:,0], xys[:,1], label=data_name, color=color)

sample plot

...