Имеется ли функция matplotlib для рисования диагональных линий в координатах оси?

Оси Matplotlib имеют функции axhline и axvline для рисования горизонтальных или вертикальных линий при заданной координате y или x (соответственно) независимо от шкалы данных осей.

Есть ли аналогичная функция для построения постоянной диагонали? Например, если у меня есть диаграмма рассеяния переменных с подобным доменом, часто бывает полезно знать, попадают ли они выше или ниже строки y = x:

mean, cov = [0, 0], [(1, .6), (.6, 1)]
x, y = np.random.multivariate_normal(mean, cov, 100).T
y += x + 1
f, ax = plt.subplots(figsize=(6, 6))
ax.scatter(x, y, c=".3")
ax.plot([-3, 3], [-3, 3], ls="--", c=".3")
ax.set(xlim=(-3, 3), ylim=(-3, 3))

enter image description here

Конечно, это можно сделать программно, захватив ограничения по оси, (ax.get_xlim() и т.д.), но что a) делает несколько дополнительных шагов и b) является хрупким в случаях, когда больше данных может оказаться на графике и сдвиг пределов. (На самом деле в некоторых случаях просто добавление самой постоянной линии растягивает оси).

Было бы предпочтительнее просто, например, ax.axdline(ls="--", c=".3"), но неясно, существует ли что-то подобное в кодовой базе matplotlib. Все, что вам нужно сделать, это изменить код axhline на график из [0, 1] в координатах осей для x и y, я думаю.

Ответы

Ответ 1

Построение диагональной линии, основанной на нижнем левом верхнем правом углу экрана, довольно просто, вы можете просто использовать ax.plot(ax.get_xlim(), ax.get_ylim(), ls="--", c=".3"). Метод ax.get_xlim() будет просто возвращать текущие значения оси x (и аналогично для оси y).

Однако, если вы хотите иметь возможность масштабирования с помощью графика, это становится немного более сложным, так как диагональная линия, которую вы построили, не изменится, чтобы соответствовать вашим новым xlims и ylims.

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

import numpy as np
import matplotlib.pyplot as plt

mean, cov = [0, 0], [(1, .6), (.6, 1)]
x, y = np.random.multivariate_normal(mean, cov, 100).T
y += x + 1

f, ax = plt.subplots(figsize=(6, 6))

ax.scatter(x, y, c=".3")
ax.set(xlim=(-3, 3), ylim=(-3, 3))

# Plot your initial diagonal line based on the starting
# xlims and ylims.
diag_line, = ax.plot(ax.get_xlim(), ax.get_ylim(), ls="--", c=".3")

def on_change(axes):
    # When this function is called it checks the current
    # values of xlim and ylim and modifies diag_line
    # accordingly.
    x_lims = ax.get_xlim()
    y_lims = ax.get_ylim()
    diag_line.set_data(x_lims, y_lims)

# Connect two callbacks to your axis instance.
# These will call the function "on_change" whenever
# xlim or ylim is changed.
ax.callbacks.connect('xlim_changed', on_change)
ax.callbacks.connect('ylim_changed', on_change)

plt.show()

Обратите внимание: если вы не хотите, чтобы диагональная линия менялась с увеличением, вы просто удаляете все ниже diag_line, = ax.plot(...

Ответ 2

Нанесение диагонали из левого нижнего в верхние правые углы вашего сюжета будет выполняться с помощью следующих

ax.plot([0, 1], [0, 1], transform=ax.transAxes)

Используя transform=ax.transAxes, поставленные координаты x и y интерпретируются как координаты осей вместо координат данных.

Это, как указывал @fqq, является только линией, когда ваши пределы x и y равны. Чтобы нарисовать линию y=x таким образом, чтобы она всегда простиралась до пределов вашего сюжета, подход, подобный тому, который был задан @Ffisegydd, будет работать и может быть записан как следующая функция.

def add_identity(axes, *line_args, **line_kwargs):
    identity, = axes.plot([], [], *line_args, **line_kwargs)
    def callback(axes):
        low_x, high_x = axes.get_xlim()
        low_y, high_y = axes.get_ylim()
        low = max(low_x, low_y)
        high = min(high_x, high_y)
        identity.set_data([low, high], [low, high])
    callback(axes)
    axes.callbacks.connect('xlim_changed', callback)
    axes.callbacks.connect('ylim_changed', callback)
    return axes

Пример использования:

import numpy as np
import matplotlib.pyplot as plt

mean, cov = [0, 0], [(1, .6), (.6, 1)]
x, y = np.random.multivariate_normal(mean, cov, 100).T
y += x + 1

f, ax = plt.subplots(figsize=(6, 6))
ax.scatter(x, y, c=".3")
add_identity(ax, color='r', ls='--')

plt.show()

Ответ 3

Я решаю таким образом:

ident = [0.0, 1.0]
plt.plot(ident,ident)