Получить истинный предел площади участка осей в matplotlib?

Я хотел бы узнать точные объемы данных внутри объекта оси 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()?)


person mszegedy    schedule 24.06.2018    source источник
comment
Я сомневаюсь, что существует единый подход к этому, учитывая, что я могу установить xlim в (-2, -1) в вашем примере, и объект не будет отображаться. И каково будет минимальное значение для гистограммы? Центр, потому что это фактическое значение? Левая граница левой панели?   -  person Mr. T    schedule 24.06.2018
comment
О, хороший момент, пределы можно установить. Это портит все. Для гистограммы это будут центры; Я ищу пределы данных, поступающих на график, независимо от того, какой это график.   -  person mszegedy    schedule 24.06.2018
comment
Такого нет, так как в сюжете артисты, а не данные. Вам нужно знать взаимосвязь между исполнителями и данными, и это зависит от типа исполнителей, а также от некоторых других вещей — что, если столбчатый график представляет собой гистограмму? Соответствующие данные x - это не центры, а края бина.   -  person Stop harming Monica    schedule 10.06.2019
comment
@Goyo Цель моего вопроса - просто спросить о сокращении сбора данных от каждого исполнителя, а затем получить мин / макс. Это правда, что связь между этими данными и пределами графика очень нетривиальна, поэтому вы не можете использовать ограничения графика, кроме как в особых случаях, но я думаю, что я полагал, что график должен где-то отслеживать эти числа.   -  person mszegedy    schedule 14.06.2019


Ответы (1)


это должно работать правильно:

lower_xlim = xlim[0] + (0.5 * xmargin) / (0.5 + xmargin) * width
upper_xlim = xlim[1] - (0.5 * xmargin) / (0.5 + xmargin) * width
person loudness    schedule 13.07.2020