Есть ли способ построить непрерывную линию с наклоном, рассчитанным по парам координат? - PullRequest
0 голосов
/ 05 февраля 2020

Я новичок в кодировании, и в настоящее время я работаю над созданием программы, которая вычисляет форму линии наклона-пересечения и такую ​​информацию, как x-intercept и y-intercept этой линии, исходя из значений любых двух случайных пары координат, например (x1, y1), (x2, y2) = (1,2), (3,4), что это представляет, как в matplotlib, когда на графике изображен отрезок линии с вычисленным наклоном (в данном случае это 1 y = 1x + 1), который не пересекает никакую ось '. Я хотел бы нарисовать еще одну линию с таким же наклоном, что и у непрерывного отрезка, чтобы показать, где отрезок линии будет пересекать оси x и y, но я хочу сделать это для любой комбинации ввода случайных пар координат пользователем. Я также хотел бы установить график для загрузки с источником графика (0,0) внизу слева в кадре, когда он создается, и не иметь график в центре моего отрезка при его создании. Любая помощь очень ценится.

import numpy as np
import math
x1 = float(input("Enter a x coordinate for x1: "))
y1 = float(input("Enter a y coordinate for y1: "))
x2 = float(input("Enter a x coordinate for x2: "))
y2 = float(input("Enter a y coordinate for y2: "))
m = (y2-y1)/(x2-x1)
d = math.sqrt((x2 - x1)**2 + (y2-y1)**2)
slope_multiplied_by_negative_x1 = m * (-1 * x1)
b = float(y1) + float(slope_multiplied_by_negative_x1)
b_absolute = abs(b)
result = "y = " + (str(m) + "x " if m != 0 else "")
if m == 0:
    sign = ""
elif b == 0:
    sign = ""
elif b > 0:
    sign = "+ "
else:
    sign = "- "
try: X_intercept = float((-1 * b)/m)
except ZeroDivisionError:
    X_intercept = 'n/a'
print(result + sign + ("" if b == 0 else (str(b_absolute))))
print("X intercept: " + ("0.0" if X_intercept == 0 else str(X_intercept)))
print("Y intercept: " + str(b))
print("Distance between (x1,y1) and (x2,y2): " + str(d))
x = [x1,x2]
y=[y1,y2]
t = np.arange(0.0, 2.0, 0.01)
fig, ax = plt.subplots()
plt.plot(x, y, color='c', linestyle='-', marker='o')
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.grid()
plt.show()

Ответы [ 2 ]

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

Сегмент с конечными точками (x1,y1), (x2,y2) принадлежит строке с уравнением

(x - x1) / (x2 - x1) = (y - y1) / (y2 - y1)

Сначала нам нужно проверить дополнительные случаи вертикальных и горизонтальных линий:

if x1 == x2:
    x_intercept = x1
    y_intercept does not exist 
    use screen window border coordinates to draw line
    (x1,0)-(x1,height)  

if y1 == y2:
    y_intercept = y1
    x_intercept does not exist
    use screen window border coordinates to draw line
    (0,y1)-(width,y1)  

В противном случае, чтобы найти пересечения с осями, мы можем просто подставить y=0 или x=0 в это уравнение.

x_intercept = x1 - y1 * (x2 - x1) / (y2 - y1)
y_intercept = y1 - x1 * (y2 - y1) / (x2 - x1)
draw line
(0, y_intercept) - (x_intercept, 0)  

PS Обратите внимание, что вам редко требуется наклон в вычислительной геометрии - существует много более общих подходов для линии определение (описано одно, параметр c, метод тета-ро)

0 голосов
/ 05 февраля 2020

Вот подход, не меняющий исходный код слишком сильно. Он проверяет горизонтальные и вертикальные линии и дает результат, когда начальная и конечная точки равны.

Точка (0,0) должна быть на графике, рисуя там невидимую точку. Линии добавляются между каждой из конечных точек и каждым из перехватов. Это также заставит оба (если они существуют) быть в области заговора. Вы заметите, что это будет рисовать одни и те же сегменты несколько раз, но это позволяет избежать слишком большого количества тестов, чтобы знать, какие сегменты необходимы. Порядок рисования гарантирует, что сегмент между (x1, y1) и (x2, y2) находится сверху.

Numpy удаляется, так как в этом нет необходимости, но это будет полезно для других типов кривых. Преобразования в число с плавающей точкой обычно не нужны в вычислениях, так как Python3 автоматически преобразует целые числа в числа с плавающей точкой для делений.

Некоторые расширения, которые можно рассмотреть:

  • тестирование чисел на равенство избегать деления на 0 может быть опасно для поплавков, возникающих из-за больших расчетов; иногда числа с плавающей точкой почти, но не точно равны, а деление на их разность приводит к переполнению (или нежелательным большим числам)
  • , чтобы удлинить линии, пока они не коснутся границ, вам нужно будет найти уравнения, чтобы найти пересечения с каждой из четырех границ и отклонить те пересечения, которые выходят за пределы других границ
  • альтернативно, вы можете нарисовать очень длинную линию и затем повторно применить пределы x и y

Здесь Вот некоторый код, который может послужить основой для дальнейших экспериментов:

import matplotlib.pyplot as plt
import math

x1 = float(input("Enter a x coordinate for x1: "))
y1 = float(input("Enter a y coordinate for y1: "))
x2 = float(input("Enter a x coordinate for x2: "))
y2 = float(input("Enter a y coordinate for y2: "))

d = math.sqrt((x2 - x1)**2 + (y2-y1)**2)
if x2 != x1:
    m = (y2-y1)/(x2-x1)
    slope_multiplied_by_negative_x1 = m * (- x1)
    b = y1 + slope_multiplied_by_negative_x1
    result = "y = " + (str(m) + "x" if m != 0 else "")
    if m != 0:
        X_intercept = (-1 * b) / m
    else:
        X_intercept = 'n/a'
    if m == 0:
        sign = ""
    elif b < 0:
        sign = " - "
    else:
        sign = " + "
    result = result + ("" if b == 0 else sign + str(abs(b)))
elif y1 != y2:
    result = "x = " + str(x1)
    X_intercept = x1
    b = 'n/a'
else:
    result = "(x, y) = (" + str(x1) + ", " + str(y1) + ')'
    X_intercept = 'n/a' if x1 != 0 else x1
    b = 'n/a' if y1 != 0 else y1
print(result)
print("X intercept: " + ("0.0" if X_intercept == 0 else str(X_intercept)))
print("Y intercept: " + str(b))
print("Distance between (x1,y1) and (x2,y2): " + str(d))

fig, ax = plt.subplots()
plt.plot(0, 0, color='k', marker='')  # just to make sure the plot contains 0,0
if X_intercept != 'n/a':
    plt.plot([X_intercept, x1], [0, y1], color='m', marker='o', linewidth=0.5)
    plt.plot([X_intercept, x2], [0, y2], color='m', marker='', linewidth=0.5)
if b != 'n/a':
    plt.plot([0, x1], [b, y1], color='m', marker='o', linewidth=0.5)
    plt.plot([0, x2], [b, y2], color='m', marker='', linewidth=0.5)
plt.plot([x1, x2], [y1, y2], color='c', linestyle='-', marker='o')
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.grid()
plt.show()

enter image description here

Вот подход к рисованию длинной линии. zorder=-1 используется для наложения этой линии за другими линиями и точками. Мы называем это в конце (как раз перед plt.show), чтобы matplotlib мог автоматически рассчитать пределы, чтобы соответствовать всем более ранним вещам.

xlims = plt.xlim()  # save the current limits
ylims = plt.ylim()
dx = (x2 - x1) * 100
dy = (y2 - y1) * 100
plt.plot([x1 - dx, x2 + dx], [y1 - dy, y2 + dy], color='k', linestyle='-', marker='', linewidth=0.5, zorder=-1)
plt.xlim(xlims)  # reapply the limits
plt.ylim(ylims)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...