Как настроить вторичную ось на графике matplotlib, когда отношение оси получено эмпирически? - PullRequest
0 голосов
/ 19 марта 2020

Я пытался следовать этой документации

https://matplotlib.org/3.1.0/gallery/subplots_axes_and_figures/secondary_axis.html

в третьем случае преобразования вторичных осей, т. Е. Когда " мы хотим связать оси в преобразовании, которое является ad-ho c из данных и получено эмпирически ", таким образом, устанавливая" функции прямого и обратного преобразования, чтобы они были линейными интерполяциями из одного набора данных в другой. ». Но я не смог достичь удовлетворительного результата.

Рассмотрим, например, простой график первого примера этой документации: синусоида с двумя горизонтальными осями, где один - это пересчет радиан в градусы на тот же график.

Код ниже дает правильный результат, где нижняя ось в радианах, а верхняя ось в градусах

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(constrained_layout=True)
x = np.linspace(0, 2*np.pi, 1000)
y = np.sin(x)
ax.plot(x, y)

def deg2rad(x):
    return x * np.pi / 180

def rad2deg(x):
    return x * 180 / np.pi

secax = ax.secondary_xaxis('top', functions=(rad2deg,deg2rad))

plt.show()

enter image description here

Тем не менее, приведенный ниже код предназначен для имитации того, что «оси градусов» будут получены из эмпирических данных (переменная массива xnew, которая может быть другими значениями), но это не дает правильного результата (после функции интерполяции документации).

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(constrained_layout=True)
x = np.linspace(0, 2*np.pi, 1000)
y = np.sin(x)
ax.plot(x, y)

xold = x
xnew = x * 180 / np.pi

def forward(x):
    return np.interp(x, xold, xnew)

def inverse(x):
    return np.interp(x, xnew, xold)

secax = ax.secondary_xaxis('top', functions=(forward,inverse))

plt.show()

enter image description here

Чего мне не хватает?

1 Ответ

1 голос
/ 20 марта 2020

Проблема в том, что и прямая, и обратная функции вызываются для значений, которые немного выходят за пределы диапазона заданных значений x. Например, они используются для xlims. (Можно добавить print(x) внутри этих функций, чтобы увидеть, как они вызываются.)

Если эти функции записаны как простое линейное преобразование, такое как в примере deg2rad, проблем нет. Функция работает одинаково за пределами своих границ. Но у np.interp нет хорошей подсказки вне его диапазона, поэтому он возвращает свой нижний или верхний предел. Это отсечение вызывает нежелательную маркировку тиков.

Для детали это можно исправить, установив жесткую ось X, поэтому без заполнения, которое происходит по умолчанию:

plt.autoscale(enable=True, axis='x', tight=True)

Но даже тогда всплывает нежелательный тик 400.

Лучшее решение состоит в том, чтобы сделать диапазон для обеих функций немного шире, чем пределы, показанные на старой оси x, включая отступ. Например, установка

xold = np.linspace(x[0]-0.5, x[-1]+0.5, 100)
xnew = xold * 180 / np.pi

Обратите внимание, что в связанном примере они устанавливают xold = np.arange(0, 11, 0.2), но затем выполняют только график, начиная с третьего индекса, чтобы создать достаточно места для заполнения. : ax.plot(xold[3:], xnew[3:]).

Полный пример может выглядеть следующим образом:

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(constrained_layout=True)
x = np.linspace(0, 2*np.pi, 1000)
y = np.sin(x)
ax.plot(x, y)

xold = np.linspace(x[0]-0.5, x[-1]+0.5, 100)
xnew = xold * 180 / np.pi

def forward(x):
    return np.interp(x, xold, xnew)

def inverse(x):
    return np.interp(x, xnew, xold)

secax = ax.secondary_xaxis('top', functions=(forward,inverse))

plt.show()

result

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...