Экземпляр копии оси из одной фигуры подсети в другую [дубликат]

Я собираюсь продемонстрировать альтернативную структуру, чтобы передать значение списка по умолчанию функции (она одинаково хорошо работает со словарями).

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

Неверный метод (возможно ...):

def foo(list_arg=[5]):
    return list_arg

a = foo()
a.append(6)
>>> a
[5, 6]

b = foo()
b.append(7)
# The value of 6 appended to variable 'a' is now part of the list held by 'b'.
>>> b
[5, 6, 7]  

# Although 'a' is expecting to receive 6 (the last element it appended to the list),
# it actually receives the last element appended to the shared list.
# It thus receives the value 7 previously appended by 'b'.
>>> a.pop()             
7

Вы можете убедиться, что это один и тот же объект, используя id:

>>> id(a)
5347866528

>>> id(b)
5347866528

Per Brett Slatkin's «Эффективный Python: 59 конкретных способов записи лучшего Python», Пункт 20: Использование None и Docstrings для указания динамических аргументов по умолчанию (стр. 48)

Соглашение о достижении желаемого результата в Python заключается в предоставлении значения по умолчанию None и документируйте фактическое поведение в docstring.

Эта реализация гарантирует, что каждый вызов функции либо получает список по умолчанию, либо список, переданный функции.

Предпочтительный Метод:

def foo(list_arg=None):
   """
   :param list_arg:  A list of input values. 
                     If none provided, used a list with a default value of 5.
   """
   if not list_arg:
       list_arg = [5]
   return list_arg

a = foo()
a.append(6)
>>> a
[5, 6]

b = foo()
b.append(7)
>>> b
[5, 7]

c = foo([10])
c.append(11)
>>> c
[10, 11]

В «Неправильном методе» могут быть законные варианты использования, в соответствии с которыми программист предполагает, что параметр списка по умолчанию должен быть общим, но это скорее исключение, чем правило.

48
задан juanchopanza 12 June 2011 в 09:13
поделиться

3 ответа

Как правило, вы просто передаете экземпляр осей функции.

Например:

import matplotlib.pyplot as plt
import numpy as np

def main():
    x = np.linspace(0, 6 * np.pi, 100)

    fig1, (ax1, ax2) = plt.subplots(nrows=2)
    plot(x, np.sin(x), ax1)
    plot(x, np.random.random(100), ax2)

    fig2 = plt.figure()
    plot(x, np.cos(x))

    plt.show()

def plot(x, y, ax=None):
    if ax is None:
        ax = plt.gca()
    line, = ax.plot(x, y, 'go')
    ax.set_ylabel('Yabba dabba do!')
    return line

if __name__ == '__main__':
    main()

Чтобы ответить на ваш вопрос, вы всегда можете сделать что-то вроде этого:

def subplot(data, fig=None, index=111):
    if fig is None:
        fig = plt.figure()
    ax = fig.add_subplot(index)
    ax.plot(data)

Кроме того, вы можете просто добавить экземпляр осей к другому рисунку:

import matplotlib.pyplot as plt

fig1, ax = plt.subplots()
ax.plot(range(10))

fig2 = plt.figure()
fig2.axes.append(ax)

plt.show()

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

24
ответ дан Community 22 August 2018 в 06:35
поделиться
  • 1
    +1 Это полезно, но мне кажется, что оси все еще соединены с фигурами и / или некоторым состоянием в пипоте. Я не могу отделить создание оси от создания фигуры и построения графика по вашему примеру. – juanchopanza 10 June 2011 в 18:17
  • 2
    Оси фундаментально связаны с определенной фигурой в matplotlib. Нет никакого способа обойти это. Тем не менее, вы все еще можете полностью «отделить создание оси от рисунка и построения графика». просто проходя вокруг осей и объектов фигуры вокруг. Я не совсем уверен, что следую тому, что вы хотите сделать ... – Joe Kington 10 June 2011 в 18:41
  • 3
    На самом деле, я думаю, они не так связаны с финансами, как я думал. Вы можете просто добавить те же самые оси к другой фигуре. (Просто сделайте fig2.axes.append(ax1)) Также возможно изменение размера его в соответствии с различными формами подзаголовков. Вероятно, это приведет к большим проблемам, чем это стоит, хотя ... – Joe Kington 10 June 2011 в 18:52
  • 4
    добавление экземпляра осей к другому рисунку (последний пример) не работает для меня в Enthought 7.3-2 (matplotlib 1.1.0). – aaren 7 December 2012 в 14:53
  • 5
    @aaren - он не работает, потому что способ сложения осей для фигуры был изменен в более новых версиях matplotlib. В настоящее время оси намеренно не должны делиться между разными фигурами. В качестве обходного пути вы можете сделать это fig2._axstack.add(fig2._make_key(a), a), но это хаки и, вероятно, изменится в будущем. Кажется, что он работает правильно, но это может сломать некоторые вещи. – Joe Kington 7 December 2012 в 15:21

Ниже показано, как «перемещать» оси с одной фигуры на другую. Это назначенная функциональность @ последнего примера JoeKington , который в новых версиях matplotlib больше не работает, потому что оси не могут жить сразу на нескольких фигурах.

Сначала вам нужно будет удалите оси с первого рисунка, затем добавьте его к следующему рисунку и дайте ему некоторое место для жизни.

import matplotlib.pyplot as plt

fig1, ax = plt.subplots()
ax.plot(range(10))
ax.remove()

fig2 = plt.figure()
ax.figure=fig2
fig2.axes.append(ax)
fig2.add_axes(ax)

dummy = fig2.add_subplot(111)
ax.set_position(dummy.get_position())
dummy.remove()
plt.close(fig1)

plt.show()
4
ответ дан ImportanceOfBeingErnest 22 August 2018 в 06:35
поделиться
  • 1
    маленькое добавление: когда plt.show() заменяется на fig2.savefig('out.png', dpi=300), позиционирование перепутано из-за ключевого слова dpi. Этого можно избежать, установив конечный dpi, когда инициализируется ax: fig1, ax = plt.subplots(dpi=300) – Matthias123 7 November 2017 в 10:25
  • 2
    В моей оболочке Python это выглядит не так: fig2.axes.append (ax) – Spirko 7 January 2018 в 17:47
  • 3
    ax.remove() приводит к NotImplementedError: cannot remove artist (Python 3.7.0, matplotlib 2.2.2) – gerrit 14 August 2018 в 10:52
  • 4
    @gerrit Вы что-то изменили по сравнению со сниппетом выше? Он отлично работает для меня. – ImportanceOfBeingErnest 14 August 2018 в 11:29
  • 5
    @ImportanceOfBeingErnest Да; Я получил свою фигуру из pickle. Прошу прощения за исключение этой важной детали. Я закончил настройку 9 AxesSubplot на set_visible(False) и изменил позицию той, которую я хотел показать только. – gerrit 14 August 2018 в 11:48

Для графиков строк вы можете иметь дело с самими объектами Line2D:

fig1 = pylab.figure()
ax1 = fig1.add_subplot(111)
lines = ax1.plot(scipy.randn(10))

fig2 = pylab.figure()
ax2 = fig2.add_subplot(111)
ax2.add_line(lines[0])
5
ответ дан Steve Tjoa 22 August 2018 в 06:35
поделиться
  • 1
    +1 Хороший пример. Кажется, я не могу отделить создание осей от создания фигуры, но я могу захватить экземпляр осей и передать его новым фигурам. – juanchopanza 12 June 2011 в 08:40
  • 2
    Обратите внимание, что этот подход больше не работает. См. Комментарий Джо Кингтона от 7 декабря 2012 года, на его ответ выше. – Joel Ostblom 4 October 2016 в 12:06
  • 3
    ax2.add_line(lines[0]) приводит к RuntimeError: Can not put single artist in more than one figure (Python 3.7.0, matplotlib 2.2.2). – gerrit 14 August 2018 в 10:55
Другие вопросы по тегам:

Похожие вопросы: