Я использую Python и matplotlib для создания анимации гонок на гистограммах, данные представляют собой временные ряды и обновляются каждый день. Я хочу сохранять в файл только обновленные кадры, например, до вчерашнего дня было 10460 кадров, видеофайл был создан за один час.
Сегодня добавлены новые 10 кадров. Я использовал код для сохранения новейших кадров в файл, как показано ниже, но ось a слишком коротка. Как мне установить для оси x то же значение, что и максимальное значение x в прошлом?
anim = FuncAnimation(self.fig, self.anim_func, frames[10460:], init_func, interval=interval)






Краткое изложение того, что следует, и ответ, отвечающий ожиданиям, сформулированным в вопросе, которые не могут быть удовлетворены с помощью matplotlib:
FuncAnimation().В FuncAnimation() данные каждого кадра вычисляются и визуализируются независимо в рамках итеративного процесса обновления. Это связано с необходимостью повышения эффективности, особенно в сценариях, где кадры представляют собой непрерывный временной ряд или симуляцию, а предварительное вычисление данных каждого кадра может быть непрактичным из-за ограничений памяти или вычислительных затрат.
Краткий обзор предоставленного кода, отвечающего на вопросы о x_limit для значений оси X графика:
Посмотрите демонстрацию того, как:
# Set up the figure and axis
fig, ax = plt.subplots()
ax.set_xlim(0, 10)
ax.set_ylim(-1.5, 1.5)
влияет на результат анимации:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
# Set up the figure and axis
fig, ax = plt.subplots()
ax.set_xlim(0, 10)
ax.set_ylim(-1.5, 1.5)
# Initialize the line plot
line, = ax.plot([], [], lw=2)
# Initial data
x = np.linspace(0, 10, 1000)
y = np.sin(x)
def init():
line.set_data([], [])
return line,
def update(frame):
# Adjust the right endpoint to shorten the wave from the right
x_new = np.linspace(0, 10 - frame / 10, 1000)
y_new = np.sin(x_new * np.pi) # Multiply by pi to maintain wave pattern despite shrinking domain
line.set_data(x_new, y_new)
return line,
# Create animation
ani = animation.FuncAnimation(fig, update, frames=np.linspace(0, 30, 100), init_func=init, blit=True)
ani.event_source.stop() #stop the looping
ani.save('fixXaxisRange.gif', writer='pillow', fps=10)
plt.show()
Другой подход — динамически устанавливать диапазон оси X в зависимости от входящих данных:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def generate_sine_wave(frame, step=0.1):
""" Generate x and y data for a sine wave up to the current frame. """
# Ensure that frame is positive to avoid empty array
if frame <= 0:
return np.array([]), np.array([])
x = np.linspace(0, 2 * np.pi * frame * step, int(frame * step * 100))
y = np.sin(x)
return x, y
# Set up the figure, axis, and plot element
fig, ax = plt.subplots()
line, = ax.plot([], [], lw=2)
ax.set_ylim(-1.5, 1.5) # Set fixed y-axis limits for clarity
# Initialize the animation by setting blank data
def init():
line.set_data([], [])
ax.set_xlim(0, 10) # Initial x-axis limit
return line,
# Update function for animation
def update(frame):
x, y = generate_sine_wave(frame)
if x.size == 0:
return line, # If x is empty, just return the existing line object
line.set_data(x, y)
# Update the x-axis limits dynamically as the line grows
if x[-1] > ax.get_xlim()[1]: # Check if we need to expand the x-axis
ax.set_xlim(ax.get_xlim()[0], x[-1] + 1) # Add some padding to the right limit
ax.figure.canvas.draw() # Redraw the canvas to update the axis labels
return line,
# Number of frames depends on how long you want the animation to run
frames = 60
# Create the animation
ani = animation.FuncAnimation(fig, update, frames=range(1, frames + 1), init_func=init, blit=False, repeat=False)
ani.save('fixXaxisRange_2.gif', writer='pillow', fps=10)
plt.show()
Если вы хотите сохранить только последние 10 кадров анимации, но запустить весь диапазон данных, вы можете указать номер начального кадра анимации (версия, сохраняющая все кадры, закомментирована):
# Total frames in the full animation
total_frames = 100
# Calculate start frame for the last ten frames
start_frame = total_frames - 10
# Create the animation object, but only generate the last ten frames
ani = animation.FuncAnimation(fig, update, frames=range(start_frame, total_frames), init_func=init, blit=False, repeat=False)
#ani = animation.FuncAnimation(fig, update, frames=range(1,total_frames), init_func=init, blit=False, repeat=False)
Ниже приведен случай, в котором диапазон x-данных определяется сначала запуском исходной функции анимации, позволяющей ей сначала сгенерировать все данные для анимации, чтобы определить фактическую функцию анимации с использованием сгенерированных данных. Таким образом, все данные для анимации известны заранее, что позволяет установить ограничение по оси X для всей анимации:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def generate_sine_wave(num_frames, step=0.1):
data = []
for frame in range(1, num_frames + 1):
x = np.linspace(0, 2 * np.pi * frame * step, int(100 * step * frame))
y = np.sin(x)
data.append((x, y))
return data
# Number of frames
total_frames = 100
# Precompute all frame data
frame_data = generate_sine_wave(total_frames)
# Determine the maximum x-value across all frames
max_x = max(np.max(x) for x, y in frame_data)
# Set up the figure, axis, and plot element
fig, ax = plt.subplots()
line, = ax.plot([], [], lw=2)
ax.set_ylim(-1.5, 1.5) # Set fixed y-axis limits for clarity
ax.set_xlim(0, max_x + 1) # Set the x-axis to the maximum found
# Initialize the animation by setting blank data
def init():
line.set_data([], [])
return line,
# Update function for animation
def update(frame):
x, y = frame_data[frame - 1] # Use precomputed data
line.set_data(x, y)
return line,
# Create the animation object using precomputed frame data
numberOfFinalFramesToSave = 10
ani = animation.FuncAnimation(fig, update, frames=range(total_frames-numberOfFinalFramesToSave, total_frames + 1), init_func=init, blit=False, repeat=False)
# Save the animation as GIF
ani.save('fixXaxisRange_4.gif', writer='pillow', fps=10)
plt.show()
В случае ваших данных возьмите функцию обновления анимации, переименуйте ее и позвольте ей генерировать данные для всех кадров. Затем определите функцию анимации, как это сделано в приведенном выше коде, покадрово предоставляя данные, сгенерированные на первом этапе. Побочным эффектом такого способа создания анимации является то, что максимальное значение x известно заранее и может быть установлено для всех кадров изнутри сценария без необходимости фиксации его значения в коде.
Можете ли вы объяснить, почему предел x можно установить на максимум?
Я не хочу каждый раз устанавливать xlim, я хочу знать, может ли matplotlib знать максимальный предел во всех кадрах.
Извините... Я не понимаю вашего требования... То, что вы спрашиваете, для меня не имеет смысла. Вероятно, проблема с пониманием языка... или проблема с переводом...
maxplotlib НЕ МОЖЕТ угадать, что вы делаете в своей функции анимации... вы можете, например, анимировать случайные данные в зависимости от времени... невозможно заранее знать, какие значения они будут генерировать.
сохранение занимает больше времени, я хочу отобразить все кадры в памяти, а затем сохранить последние 10 кадров в файл, поэтому предел x должен быть установлен на максимум, возможно ли это?
Вот что мне интересно!
Мои данные одинаковы, кроме последней строки, и я использую те же параметры для создания анимации, возможно ли это в этом случае?
Другими словами, могу ли я передать все кадры в matplotlib и позволить ему сохранить некоторые кадры в файл?
Вы невнимательно просмотрели мой вопрос, сохранять все кадры нужно больше часа!
У меня есть идея, но мне нужно взломать некоторые функции: передать все кадры и сохранить кадры для создания анимации, вывести кадры в buf и получить максимальные значения xlim и ylim перед сохранением кадров, затем установить xlim и ylim, а затем сохранить кадры в файл.
Моя вторая картинка - это ваша идея, макс х отличается от предыдущей.
См. последний код, который я добавил. Он должен делать именно то, что вы хотите. Имеет ли это?
Правильно ли я понимаю, что ваш вопрос возник не из-за того, что вы ничего не знали о matplotlib, а из-за того, что не удалось разработать соответствующую функцию обновления для анимации, доставляющей предварительно вычисленные данные кадра? Теперь вы понимаете, как сложно угадать, о чем вы спрашиваете? Вы уже знали все, что вам нужно для получения желаемого результата... но не сумели правильно применить эти знания, верно?
Кстати: распечатайте максимальное значение x при запуске скрипта, и у вас будет все, что вам нужно, чтобы при следующем запуске была та же ось X, что и в предыдущем.
ОК... Надеюсь, я наконец-то дал определенный ответ, который вы искали: то, что вы просили, невозможно с помощью функции matplotlib для создания анимации.
В вашем коде учитывается только длина стержня, не включая длину метки стержня, на моем изображении за 2 нс показана полоска максимальной длины, но без метки, но на первой показана полная метка стержня, это то, что я здесь спрашивал, это не так просто.
Если вы не предоставили достаточно информации о том, что хотите, ни данных, ни кода, не ждите ответа, решающего все ваши возможные проблемы. Приведите минимальный пример кода и данных, показывающий, что вы получаете и чем это отличается от того, чего вы хотите достичь.
Извините, что не четко задал вопрос, мне казалось, что на моих двух фотографиях все по-разному...
Теперь у вас есть идеальный ответ на ваш вопрос: вам нужно самостоятельно позаботиться о максимальном значении x для оси x, matplotlib вам не поможет. Я понимаю, что вы ожидали другого исхода своего вопроса... но разве я не виноват, что matplotlib не соответствует вашим ожиданиям?
Я запускаю ваш код, нет ни одной строки....