Я собираюсь продемонстрировать альтернативную структуру, чтобы передать значение списка по умолчанию функции (она одинаково хорошо работает со словарями).
Поскольку другие подробно комментируют, параметр списка привязан к функции, когда она определена, а не когда она выполняется. Поскольку списки и словари изменяемы, любое изменение этого параметра влияет на другие вызовы этой функции. В результате последующие вызовы функции получат этот общий список, который может быть изменен любыми другими вызовами функции. Хуже того, два параметра используют общий параметр этой функции, в то же время не обращая внимания на изменения, сделанные другим.
Неверный метод (возможно ...):
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 заключается в предоставлении значения по умолчанию
blockquote>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]
В «Неправильном методе» могут быть законные варианты использования, в соответствии с которыми программист предполагает, что параметр списка по умолчанию должен быть общим, но это скорее исключение, чем правило.
Как правило, вы просто передаете экземпляр осей функции.
Например:
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()
Изменение размера в соответствии с другими «фигурами» подзаголовка также возможно, но оно быстро станет больше проблем, чем того стоит. Подход простого прохождения экземпляра фигуры или осей (или список экземпляров) намного проще для сложных случаев, по моему опыту ...
Ниже показано, как «перемещать» оси с одной фигуры на другую. Это назначенная функциональность @ последнего примера 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()
plt.show()
заменяется на fig2.savefig('out.png', dpi=300)
, позиционирование перепутано из-за ключевого слова dpi
. Этого можно избежать, установив конечный dpi
, когда инициализируется ax
: fig1, ax = plt.subplots(dpi=300)
– Matthias123
7 November 2017 в 10:25
ax.remove()
приводит к NotImplementedError: cannot remove artist
(Python 3.7.0, matplotlib 2.2.2)
– gerrit
14 August 2018 в 10:52
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])
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
fig2.axes.append(ax1)
) Также возможно изменение размера его в соответствии с различными формами подзаголовков. Вероятно, это приведет к большим проблемам, чем это стоит, хотя ... – Joe Kington 10 June 2011 в 18:52fig2._axstack.add(fig2._make_key(a), a)
, но это хаки и, вероятно, изменится в будущем. Кажется, что он работает правильно, но это может сломать некоторые вещи. – Joe Kington 7 December 2012 в 15:21