Как реорганизовать данные для правильного построения линейного графика в Python

У меня есть следующий код, который отображает ydata против xdata, который должен быть кругом. График состоит из двух подграфиков — линейного графика с маркерами и диаграммы рассеяния.

import matplotlib.pyplot as plt


xdata = [-1.9987069285852805, -1.955030386765729, -1.955030386765729, -1.8259096357678795, -1.8259096357678795, -1.6169878720004491, -1.6169878720004491, -1.3373959790579202, -1.3373959790579202, -0.9993534642926399, -0.9993534642926399, -0.6176344077078071, -0.6176344077078071, -0.20892176376743077, -0.20892176376743077, 0.20892176376743032, 0.20892176376743032, 0.6176344077078065, 0.6176344077078065, 0.999353464292642, 0.999353464292642, 1.3373959790579217, 1.3373959790579217, 1.6169878720004487, 1.6169878720004487, 1.8259096357678786, 1.8259096357678786, 1.9550303867657255, 1.9550303867657255, 1.9987069285852832]
 
ydata = (0.0, -0.038801795445724575, 0.038801795445724575, -0.07590776623879933, 0.07590776623879933, -0.10969620340136318, 0.10969620340136318, -0.13869039009450249, 0.13869039009450249, -0.16162314123018345, 0.16162314123018345, -0.1774921855402276, 0.1774921855402276, -0.18560396964016201, 0.18560396964016201, -0.185603969640162, 0.185603969640162, -0.17749218554022747, 0.17749218554022747, -0.16162314123018337, 0.16162314123018337, -0.13869039009450224, 0.13869039009450224, -0.10969620340136294, 0.10969620340136294, -0.0759077662387991, 0.0759077662387991, -0.038801795445725006, 0.038801795445725006, 0.0)



fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16,6))
fig.suptitle('Plot comparison: line vs scatter'+ 3*'\n')
fig.subplots_adjust(wspace=1, hspace=3)
fig.supxlabel('x')
fig.supylabel('y')


ax1.plot(xdata, ydata, 'o-', c='blue')
ax1.set_title('Line-point plot', c='blue')

for i in range(len(xdata)):
   ax2.scatter(xdata, ydata, c='orange')
   ax2.set_title('Scatter plot', c='orange')
plt.savefig('line_vs_scatter_plot.png')
plt.show()

Выход:

Из выходных данных видно, что линейный график не соединяет точки (или точки). Можем ли мы каким-либо образом изменить порядок данных x или y, чтобы решить проблему? Или сделать что-то еще?

Вы можете начать с одной точки и сортировать их по расстоянию по мере последовательного добавления точек, но это будет довольно медленно. Если это разовая вещь и вам не нужно делать это для многих очков, тогда все в порядке. Как были начислены баллы?

jared 26.05.2024 20:05

Точки были созданы путем решения комплексного матричного уравнения (проблемы собственных значений).

hbaromega 26.05.2024 21:31
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
100
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете сортировать точки по часовой стрелке, здесь — реализация. В вашем случае вам придется заархивировать списки x и y:

origin = [0, 0]
refvec = [0, 1]

x2, y2 = zip(*sorted(zip(xdata, ydata), key=clockwiseangle_and_distance))

plt.plot(x2, y2, 'o-', c='blue')

Выход:

по часовой стрелке_and_distance функция @MSeifert

import math

def clockwiseangle_and_distance(point):
    # Vector between point and the origin: v = p - o
    vector = [point[0]-origin[0], point[1]-origin[1]]
    # Length of vector: ||v||
    lenvector = math.hypot(vector[0], vector[1])
    # If length is zero there is no angle
    if lenvector == 0:
        return -math.pi, 0
    # Normalize vector: v/||v||
    normalized = [vector[0]/lenvector, vector[1]/lenvector]
    dotprod  = normalized[0]*refvec[0] + normalized[1]*refvec[1]     # x1*x2 + y1*y2
    diffprod = refvec[1]*normalized[0] - refvec[0]*normalized[1]     # x1*y2 - y1*x2
    angle = math.atan2(diffprod, dotprod)
    # Negative angles represent counter-clockwise angles so we need to subtract them 
    # from 2*pi (360 degrees)
    if angle < 0:
        return 2*math.pi+angle, lenvector
    # I return first the angle because that's the primary sorting criterium
    # but if two vectors have the same angle then the shorter distance should come first.
    return angle, lenvector
Ответ принят как подходящий

Если координаты xy имеют последовательный зигзагообразный рисунок (нечетный/четный), вы можете сделать:

def unzigzag(data):
    data = list(data) # just in case
    return data[::2] + data[::-2] + [data[0]]

ax1.plot(*map(unzigzag, [xdata, ydata]), "bo-")

NB: Этот график аннотирован физическим положением (начиная с 1) x/y в их списках.

Если нет, то одним из вариантов будет использование shapely :

from shapely import MultiPoint
from shapely.geometry.polygon import orient

def unzigzag(x, y, ori=-1): # -1: clock-wise
    p = MultiPoint(list(zip(x, y))).convex_hull
    return list(orient(p, ori).boundary.coords)

ax2.plot(*zip(*unzigzag(xdata, ydata)), "-bo") # the ori has no effect

Анимация для выделения ориентации:

Спасибо. Второй ответ работает. Первый ответ дает следующую ошибку: return data[1::2] + data[-2::-2] + [data[1]] ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~ TypeError: can only concatenate tuple (not "list") to tuple. Кстати, что означает эта линия? Сначала расположите все нечетные элементы по часовой стрелке, затем добавьте четные против часовой стрелки, а затем снова добавьте первый нечетный элемент, чтобы завершить круг?

hbaromega 26.05.2024 21:54

Вы можете добавить data = list(data) просто для того, чтобы убедиться, что у нас есть списки перед объединением (см. обновление). Что касается вашего вопроса, да, это идея первого подхода/unzigzag.

Timeless 26.05.2024 21:57

Спасибо, я понял, что мой xdata — это список, а мой ydata — кортеж. Следовательно, объединение выдает ошибку из-за этого несоответствия. У меня возникла идея: если мы разделим сектор на четный и нечетный, мы сможем избежать соединения двух последовательных точек в исходном порядке. Однако почему разделение происходит по часовой стрелке и против часовой стрелки?

hbaromega 27.05.2024 01:15

Хорошие графики и объяснения @Timeless ;)

mozway 27.05.2024 09:38

Ах! Я вижу сейчас. Поскольку оба идут по часовой стрелке, соединение не теряет согласованности. И всё же есть некоторые сомнения: (1) Где data[0]? Я думаю, data[-2::-2] начинается с data[28] и заканчивается на data[0]. Если я прав, ваша вторая стрелка должна начинаться с индекса 28, а не с 30. Индекса 30 вообще нет, если вы следуете индексации на основе Python. (2) Не является ли data[1] перекрытием двух точек (одна и та же точка нанесена дважды)?

hbaromega 27.05.2024 09:40

@hbaromega, ты был прав, настаивая, исправлено;). Для индексов на графике я использую 1-индексацию.

Timeless 27.05.2024 10:16

@Timeless, спасибо за новости. Не могли бы вы соответствующим образом обновить стрелки на графике, просто чтобы они соответствовали индексации Python в коде?

hbaromega 27.05.2024 17:23

Другие вопросы по теме