Я хотел бы узнать точные объемы данных внутри объекта оси matplotlib; т. е. их самые высокие и самые низкие значения x, а также самые высокие и самые низкие значения y. (Мое конкретное приложение требует, чтобы я мог определить самое высокое значение x с ошибкой менее 0,5, но мне любопытен общий случай.)
Вы должны использовать Axes.get_xlim()
и .get_ylim()
, чтобы получить экстент объекта Axes, но из-за полей эти пределы будут немного выходить за пределы данных. Например:
import matplotlib.pyplot as plt
plt.plot(range(100), range(100))
ax = plt.gca()
print(ax.get_xlim()) # prints (-4.95, 103.95)
Поля задаются Axes.margins()
как часть осей, что, если мы их вычтем? В итоге мы немного недооцениваем пределы:
xlim, xmargin = ax.get_xlim(), ax.margins()[0]
width = xlim[1] - xlim[0]
lower_xlim = xlim[0] + width*xmargin # 0.495, should be 0
upper_xlim = xlim[1] - width*xmargin # 98.505, should be 99
Путем проб и ошибок мы обнаруживаем, что если мы умножим корректирующий член на 10/11
, мы, наконец, попадем в точку:
lower_xlim = xlim[0] + width*xmargin*10/11 # 0.
upper_xlim = xlim[1] - width*xmargin*10/11 # 99.
При ближайшем рассмотрении с различными диапазонами данных и размерами полей выясняется, что фактический фактор таков:
lower_xlim = xlim[0] + width*5/110 # 0.
upper_xlim = xlim[1] - width*5/110 # 99.
Очень странно, но работает очень хорошо. За исключением... что, если мы используем Axes.imshow()
вместо Axes.plot()
? В этом случае график не имеет полей (если Axes.use_sticky_edges()
равен True
, что является значением по умолчанию), но результат Axes.margins()
в любом случае одинаков. Кроме того, это может быть испорчено добавлением исполнителей, не связанных с данными, таких как текстовые поля за пределами текущих границ. (Возможно. Я никогда не пробовал.)
Я знаю, что надежный способ найти пределы данных — перебрать все данные в объекте Axes и вычислить их максимумы и минимумы. Это можно сделать, найдя исполнителей объекта Axes с помощью Axes.get_children()
и получив данные от тех, которые предоставляют метод .get_data()
. Но это очень затратно в вычислительном отношении.
Есть ли способ лучше? Или мой хак 5/110 лучше всего подходит? Почему коэффициент 5/110 вообще необходим? Почему это не зависит от xmargin
? (Должен ли я сначала позвонить Axes.autoscale()
?)