无法在 matplotlib 中保存动画:Windows 权限被拒绝
Cannot save animation in matplotlib: Windows permission denied
我已经尝试了一天的时间来解决这个问题,检查了类似的线程,但没有成功。
Stretch's Cannot save matplotlib animation with ffmpeg 帮助解决了之前的错误(我的 ffmpeg 路径错误),但修复后我一直拒绝访问。
我的 ffmpeg 二进制文件在 C:\ffmpeg\bin
一个不错的选择是能够导出 gif 文件,但我总是收到 imagemagick 的 ascii 错误。我认为这两个问题是相关的,所以我想先把ffmpeg整理一下。
我认为问题可能与我正在使用 Canopy(在 Windows 8 64 位中)这一事实有关,它几乎控制了我的路径变量并在此过程中破坏了一些东西(例如我自从我安装了 Canopy 之后就无法打开 IDLE,还没有尝试修复它)。当我沿途修复问题时,我发现至少 3 个不同的路径变量,我更新了所有这些变量:windows 高级设置路径(手动设置),windows 控制台路径(通过控制台使用 setx 设置),和 sys.path(在运行时设置或检查),添加 ";C:\ffmpeg\bin"
,其中 ffmpeg 有效。不管我有没有解决这个问题,我想知道这些环境变量中的哪些是相关的,我觉得很困惑。
代码如下:
# -*- coding: utf-8 -*-
import sys
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
plt.rcParams['animation.ffmpeg_path'] = r'C:\ffmpeg\bin'
if r'C:\ffmpeg\bin' not in sys.path: sys.path.append(r'C:\ffmpeg\bin')
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)
plt.show()
# This case generates Windows err: Access Denied
FFwriter = animation.FFMpegWriter()
# anim.save(r'C:\basic_animation.mp4', writer = FFwriter, fps=30)
# This case generates UnicodeDecodeError:'ascii' codec can't decode byte 0xa0 in position 3
# anim.save(r'C:\animation.gif', writer='imagemagick', fps=30)
anim.save(r'C:\basic_animation.mp4', writer = FFwriter, fps=30)
的回溯:
%run "C:\Users\Yahveh\Documents\Vlad\Investigacion\animation saving.py"
---------------------------------------------------------------------------
WindowsError Traceback (most recent call last)
C:\Users\Yahveh\Documents\Vlad\Investigacion\animation saving.py in <module>()
27 # This case generates Windows err: Access Denied
28 FFwriter = animation.FFMpegWriter()
---> 29 anim.save(r'C:\basic_animation.mp4', writer = FFwriter, fps=30)
30
31 # This case generates UnicodeDecodeError:'ascii' codec can't decode byte 0xa0 in position 3
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in save(self, filename, writer, fps, dpi, codec, bitrate, extra_args, metadata, extra_anim, savefig_kwargs)
759 # since GUI widgets are gone. Either need to remove extra code to
760 # allow for this non-existant use case or find a way to make it work.
--> 761 with writer.saving(self._fig, filename, dpi):
762 for data in zip(*[a.new_saved_frame_seq()
763 for a in all_anim]):
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5.2.2785.win-x86_64\lib\contextlib.pyc in __enter__(self)
15 def __enter__(self):
16 try:
---> 17 return self.gen.next()
18 except StopIteration:
19 raise RuntimeError("generator didn't yield")
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in saving(self, *args)
184 '''
185 # This particular sequence is what contextlib.contextmanager wants
--> 186 self.setup(*args)
187 yield
188 self.finish()
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in setup(self, fig, outfile, dpi, *args)
174 # Run here so that grab_frame() can write the data to a pipe. This
175 # eliminates the need for temp files.
--> 176 self._run()
177
178 @contextlib.contextmanager
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in _run(self)
202 stdout=output, stderr=output,
203 stdin=subprocess.PIPE,
--> 204 creationflags=subprocess_creation_flags)
205
206 def finish(self):
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5.2.2785.win-x86_64\lib\subprocess.pyc in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags)
707 p2cread, p2cwrite,
708 c2pread, c2pwrite,
--> 709 errread, errwrite)
710 except Exception:
711 # Preserve original exception in case os.close raises.
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5.2.2785.win-x86_64\lib\subprocess.pyc in _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, to_close, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite)
955 env,
956 cwd,
--> 957 startupinfo)
958 except pywintypes.error, e:
959 # Translate pywintypes.error to WindowsError, which is
WindowsError: [Error 5] Acceso denegado
anim.save(r'C:\animation.gif', writer='imagemagick', fps=30)
的回溯:
In [8]: %run "C:\Users\Yahveh\Documents\Vlad\Investigacion\animation saving.py"
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
C:\Users\Yahveh\Documents\Vlad\Investigacion\animation saving.py in <module>()
30
31 # This case generates UnicodeDecodeError:'ascii' codec can't decode byte 0xa0 in position 3
---> 32 anim.save(r'C:\animation.gif', writer='imagemagick', fps=30)
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in save(self, filename, writer, fps, dpi, codec, bitrate, extra_args, metadata, extra_anim, savefig_kwargs)
765 # TODO: Need to see if turning off blit is really necessary
766 anim._draw_next_frame(d, blit=False)
--> 767 writer.grab_frame(**savefig_kwargs)
768
769 # Reconnect signal for first draw if necessary
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in grab_frame(self, **savefig_kwargs)
225 verbose.report('MovieWriter -- Error '
226 'running proc:\n%s\n%s' % (out,
--> 227 err), level='helpful')
228 raise
229
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 3: ordinal not in range(128)
盯着他们看了一会儿。
感谢您的宝贵时间!
更新: 我按照 this post 中的步骤授予对 C:\ffmpeg 和目标文件夹的访问权限,但运气不好:(
尝试将文件保存到其他地方,以便进行调试。
那就是:在您保存 "C:\basic_animation.mp4" 的地方,尝试类似“C:\TEMP\basic_animation.mp4”的内容。
如果我没记错的话,win7+ 在 "C:\" 和其他目录中增加了额外的安全性。这个简单的测试会告诉您问题是否出在目标目录上。
我建议始终使用系统的临时目录来处理此类事情,然后将文件移动到它应该去的地方。您可以像这样在 Python 中获取当前系统的 TEMP 目录:
import tempfile
print tempfile.gettempdir()
另外,关于“'ascii'编解码器无法解码”的问题:是字符串转换问题。一直都在发生,特别是在 Windows。
看看这个:http://nedbatchelder.com/text/unipain/unipain.html#1
但这次似乎是在 FFMPEG 的内部,因为 "anim" 是 "FuncAnimation" 返回的某个实例,而且我没有看到您在使用它时有任何不当行为。您能做的最好的事情就是保证您的所有字符串在使用前都已正确转换。例如,就像路径字符串一样。
这是另一条评论:
根据我对您的堆栈跟踪的了解,字符串转换错误发生在 canopy 内的某些 verbose/log 函数中。也许正在尝试使用非 ascii 字符记录某些内容。所以,你也可以尝试一些 canopy 标志来禁用 log/verbose;也许这就够了。
也许并不意外。我通往 ffmpeg C:\ffmpeg\bin
的路径是错误的;因为它应该是指向 exe 文件的路径,而不仅仅是父文件夹,正如我从 Stretch 的 post 中误解的那样,正如 Daniel 指出的那样。
请注意,我之前已经尝试过,但当时只是更改了错误消息。
冷静,休息一下,仔细阅读,而不是只寻找适合您的代码。这只是一个错误。
这就是答案。
我已经尝试了一天的时间来解决这个问题,检查了类似的线程,但没有成功。 Stretch's Cannot save matplotlib animation with ffmpeg 帮助解决了之前的错误(我的 ffmpeg 路径错误),但修复后我一直拒绝访问。
我的 ffmpeg 二进制文件在 C:\ffmpeg\bin
一个不错的选择是能够导出 gif 文件,但我总是收到 imagemagick 的 ascii 错误。我认为这两个问题是相关的,所以我想先把ffmpeg整理一下。
我认为问题可能与我正在使用 Canopy(在 Windows 8 64 位中)这一事实有关,它几乎控制了我的路径变量并在此过程中破坏了一些东西(例如我自从我安装了 Canopy 之后就无法打开 IDLE,还没有尝试修复它)。当我沿途修复问题时,我发现至少 3 个不同的路径变量,我更新了所有这些变量:windows 高级设置路径(手动设置),windows 控制台路径(通过控制台使用 setx 设置),和 sys.path(在运行时设置或检查),添加 ";C:\ffmpeg\bin"
,其中 ffmpeg 有效。不管我有没有解决这个问题,我想知道这些环境变量中的哪些是相关的,我觉得很困惑。
代码如下:
# -*- coding: utf-8 -*-
import sys
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
plt.rcParams['animation.ffmpeg_path'] = r'C:\ffmpeg\bin'
if r'C:\ffmpeg\bin' not in sys.path: sys.path.append(r'C:\ffmpeg\bin')
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)
plt.show()
# This case generates Windows err: Access Denied
FFwriter = animation.FFMpegWriter()
# anim.save(r'C:\basic_animation.mp4', writer = FFwriter, fps=30)
# This case generates UnicodeDecodeError:'ascii' codec can't decode byte 0xa0 in position 3
# anim.save(r'C:\animation.gif', writer='imagemagick', fps=30)
anim.save(r'C:\basic_animation.mp4', writer = FFwriter, fps=30)
的回溯:
%run "C:\Users\Yahveh\Documents\Vlad\Investigacion\animation saving.py"
---------------------------------------------------------------------------
WindowsError Traceback (most recent call last)
C:\Users\Yahveh\Documents\Vlad\Investigacion\animation saving.py in <module>()
27 # This case generates Windows err: Access Denied
28 FFwriter = animation.FFMpegWriter()
---> 29 anim.save(r'C:\basic_animation.mp4', writer = FFwriter, fps=30)
30
31 # This case generates UnicodeDecodeError:'ascii' codec can't decode byte 0xa0 in position 3
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in save(self, filename, writer, fps, dpi, codec, bitrate, extra_args, metadata, extra_anim, savefig_kwargs)
759 # since GUI widgets are gone. Either need to remove extra code to
760 # allow for this non-existant use case or find a way to make it work.
--> 761 with writer.saving(self._fig, filename, dpi):
762 for data in zip(*[a.new_saved_frame_seq()
763 for a in all_anim]):
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5.2.2785.win-x86_64\lib\contextlib.pyc in __enter__(self)
15 def __enter__(self):
16 try:
---> 17 return self.gen.next()
18 except StopIteration:
19 raise RuntimeError("generator didn't yield")
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in saving(self, *args)
184 '''
185 # This particular sequence is what contextlib.contextmanager wants
--> 186 self.setup(*args)
187 yield
188 self.finish()
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in setup(self, fig, outfile, dpi, *args)
174 # Run here so that grab_frame() can write the data to a pipe. This
175 # eliminates the need for temp files.
--> 176 self._run()
177
178 @contextlib.contextmanager
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in _run(self)
202 stdout=output, stderr=output,
203 stdin=subprocess.PIPE,
--> 204 creationflags=subprocess_creation_flags)
205
206 def finish(self):
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5.2.2785.win-x86_64\lib\subprocess.pyc in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags)
707 p2cread, p2cwrite,
708 c2pread, c2pwrite,
--> 709 errread, errwrite)
710 except Exception:
711 # Preserve original exception in case os.close raises.
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5.2.2785.win-x86_64\lib\subprocess.pyc in _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, to_close, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite)
955 env,
956 cwd,
--> 957 startupinfo)
958 except pywintypes.error, e:
959 # Translate pywintypes.error to WindowsError, which is
WindowsError: [Error 5] Acceso denegado
anim.save(r'C:\animation.gif', writer='imagemagick', fps=30)
的回溯:
In [8]: %run "C:\Users\Yahveh\Documents\Vlad\Investigacion\animation saving.py"
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
C:\Users\Yahveh\Documents\Vlad\Investigacion\animation saving.py in <module>()
30
31 # This case generates UnicodeDecodeError:'ascii' codec can't decode byte 0xa0 in position 3
---> 32 anim.save(r'C:\animation.gif', writer='imagemagick', fps=30)
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in save(self, filename, writer, fps, dpi, codec, bitrate, extra_args, metadata, extra_anim, savefig_kwargs)
765 # TODO: Need to see if turning off blit is really necessary
766 anim._draw_next_frame(d, blit=False)
--> 767 writer.grab_frame(**savefig_kwargs)
768
769 # Reconnect signal for first draw if necessary
C:\Users\Yahveh\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\animation.pyc in grab_frame(self, **savefig_kwargs)
225 verbose.report('MovieWriter -- Error '
226 'running proc:\n%s\n%s' % (out,
--> 227 err), level='helpful')
228 raise
229
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 3: ordinal not in range(128)
盯着他们看了一会儿。
感谢您的宝贵时间!
更新: 我按照 this post 中的步骤授予对 C:\ffmpeg 和目标文件夹的访问权限,但运气不好:(
尝试将文件保存到其他地方,以便进行调试。 那就是:在您保存 "C:\basic_animation.mp4" 的地方,尝试类似“C:\TEMP\basic_animation.mp4”的内容。
如果我没记错的话,win7+ 在 "C:\" 和其他目录中增加了额外的安全性。这个简单的测试会告诉您问题是否出在目标目录上。
我建议始终使用系统的临时目录来处理此类事情,然后将文件移动到它应该去的地方。您可以像这样在 Python 中获取当前系统的 TEMP 目录:
import tempfile
print tempfile.gettempdir()
另外,关于“'ascii'编解码器无法解码”的问题:是字符串转换问题。一直都在发生,特别是在 Windows。
看看这个:http://nedbatchelder.com/text/unipain/unipain.html#1
但这次似乎是在 FFMPEG 的内部,因为 "anim" 是 "FuncAnimation" 返回的某个实例,而且我没有看到您在使用它时有任何不当行为。您能做的最好的事情就是保证您的所有字符串在使用前都已正确转换。例如,就像路径字符串一样。
这是另一条评论:
根据我对您的堆栈跟踪的了解,字符串转换错误发生在 canopy 内的某些 verbose/log 函数中。也许正在尝试使用非 ascii 字符记录某些内容。所以,你也可以尝试一些 canopy 标志来禁用 log/verbose;也许这就够了。
也许并不意外。我通往 ffmpeg C:\ffmpeg\bin
的路径是错误的;因为它应该是指向 exe 文件的路径,而不仅仅是父文件夹,正如我从 Stretch 的 post 中误解的那样,正如 Daniel 指出的那样。
请注意,我之前已经尝试过,但当时只是更改了错误消息。
冷静,休息一下,仔细阅读,而不是只寻找适合您的代码。这只是一个错误。
这就是答案。