需要帮助解决 matplotlib 在 Raspberry Pi 上的性能问题
Need help to solve performance problems of matplotlib on a Raspberry Pi
首先,对于这么长的文字感到抱歉。我是 python 和 matplotlib 的新手,所以请多多包涵。
作为此 的跟进,我发现在 Raspberry Pi 使用 web2py 生成网格的方法非常耗时。我有一个大约 12k 行的 csv 文件,如下所示:
1;1.0679759979248047;0.0;147.0;0.0;;{'FHR1': 'US', 'FHR2': 'INOP', 'MHR': 'INOP'};69;good;;;;1455891539.502167
事实是,用 numpy.genfromtxt 读取那些 12k 行已经需要 30 秒左右。然后填充图表(没有花哨的网格)又花了 30 秒,仅使用该 csv 的第 1、3 和 7 列。但在添加解决方案后,时间激增至 170 秒。所以现在我必须弄清楚如何将时间消耗减少到不到一分钟。
我的第一个想法是消除 csv - 无论如何我都是读取数据的人,所以我可以通过将数据保存在内存中或直接将其写入绘图来跳过它。这就是我所做的,使用(在我看来)简单的测试布局并使用 pdf 后端。我选择每次获取数据时都将数据写入图表,并在传输完成后保存图表。我认为那应该可以正常工作,但事实并非如此。我不断收到可笑的错误:
RuntimeError: RRuleLocator estimated to generate 9178327 ticks from 0001-01-01 15:20:31.883239+00:00 to 0001-04-17 20:52:39.779205+00:00: exceeds Locator.MAXTICKS * 2 (6000000)
相信我,我会在每次测试中不断增加这些 maxticks 运行 超过错误消息显示的数字。这很荒谬,因为该消息仅针对 60 秒的数据,而我想转到接近 24 小时 的数据。我要么希望 RRuleLocator 停止估计,要么闭嘴等待数据结束。我真的不认为我可以用它来制作 MCVE,但我可以找出我最有可能搞砸的细节。
首先,我设置了一些 classes,所以没有全局变量。为了简化,我有一个通信 class,它以一秒的间隔读取串行端口。这 运行 很好,直到昨天才将串行端口上输入的所有内容写入 csv。现在我想看看我是否可以在获取数据的同时填充图表,并在完成后保存它。所以为了测试,我将它添加到我的 .py
import matplotlib
matplotlib.use('PDF') # I want a PDF in the end
from matplotlib import dates
import matplotlib.pyplot as plt
import numpy as np
from numpy import genfromtxt
然后有的成员来交流class,表示来自图表部分,主要是上面提到的解决方案。我在 classes init
中初始化它们
self.fig = None
self.ctg = None
self.toco = None
然后我会调用这个方法,一旦我觉得我收到的数据是正确的form/state,这样图表就可以准备好填充数据
def prepchart(self):
# how often to show xticklabels and repeat yticklabels:
print('prepchart')
xtickinterval = 5
hfmt = dates.DateFormatter('%H:%M:%S')
self.fig = plt.figure()
self.ctg = self.fig.add_subplot(2, 1, 1) # two rows, one column, first plot
plt.ylim(50, 210)
self.toco = self.fig.add_subplot(2, 1, 2)
plt.ylim(0, 100)
# Set the minor ticks to every 30 seconds
minloc = dates.SecondLocator(bysecond=[0,30])
minloc.MAXTICKS = 3000000
self.ctg.xaxis.set_minor_locator(minloc)
# self.ctg.xaxis.set_minor_locator(dates.MinuteLocator())
self.ctg.xaxis.set_major_formatter(hfmt)
self.toco.xaxis.set_minor_locator(dates.MinuteLocator())
self.toco.xaxis.set_major_formatter(hfmt)
# actg.xaxis.set_ticks(rotation=45)
plt.xticks(rotation=45)
然后每隔一段时间,一旦我有数据想要绘制,我就会在我的数据处理方法中这样做
self.ctg.plot_date(timevalue, heartrate, '-')
self.toco.plot_date(timevalue, toco, '-')
最后,一旦不再发送数据(可能是一分钟或 24 小时后),我会打电话给
def handleCTG(self):
self.fig.savefig('/home/pi/test.pdf')
结论:我的做法是完全错误的还是我的代码中存在错误?这真的是一种减少图表生成等待时间的方法吗?
好的,这就是交易。显然 web2py 运行非常严格。这意味着没有那么多线程浮动,它肯定不会为我的小图表创建启动一个新线程。我有点注意到这一点,当我在我的 Raspis taskmanager 上使用 CPU 时,只看到了大约 25% 的东西。现在 Raspberry Pi 有 4 个内核...去计算一下。首先,我 运行 我的脚本在我的 Raspi 上的 web2py 之外,你瞧,包括 csv 读取和图表渲染在内的整个过程只需要 20 秒。从那里开始(受 How to run a task outside web2py and retrieve the output 启发)这是小菜一碟:使用记录良好的子流程通过此脚本调用新的 python 并完成。所以感谢任何对此提出一些想法的人。
首先,对于这么长的文字感到抱歉。我是 python 和 matplotlib 的新手,所以请多多包涵。
作为此
1;1.0679759979248047;0.0;147.0;0.0;;{'FHR1': 'US', 'FHR2': 'INOP', 'MHR': 'INOP'};69;good;;;;1455891539.502167
事实是,用 numpy.genfromtxt 读取那些 12k 行已经需要 30 秒左右。然后填充图表(没有花哨的网格)又花了 30 秒,仅使用该 csv 的第 1、3 和 7 列。但在添加解决方案后,时间激增至 170 秒。所以现在我必须弄清楚如何将时间消耗减少到不到一分钟。
我的第一个想法是消除 csv - 无论如何我都是读取数据的人,所以我可以通过将数据保存在内存中或直接将其写入绘图来跳过它。这就是我所做的,使用(在我看来)简单的测试布局并使用 pdf 后端。我选择每次获取数据时都将数据写入图表,并在传输完成后保存图表。我认为那应该可以正常工作,但事实并非如此。我不断收到可笑的错误:
RuntimeError: RRuleLocator estimated to generate 9178327 ticks from 0001-01-01 15:20:31.883239+00:00 to 0001-04-17 20:52:39.779205+00:00: exceeds Locator.MAXTICKS * 2 (6000000)
相信我,我会在每次测试中不断增加这些 maxticks 运行 超过错误消息显示的数字。这很荒谬,因为该消息仅针对 60 秒的数据,而我想转到接近 24 小时 的数据。我要么希望 RRuleLocator 停止估计,要么闭嘴等待数据结束。我真的不认为我可以用它来制作 MCVE,但我可以找出我最有可能搞砸的细节。
首先,我设置了一些 classes,所以没有全局变量。为了简化,我有一个通信 class,它以一秒的间隔读取串行端口。这 运行 很好,直到昨天才将串行端口上输入的所有内容写入 csv。现在我想看看我是否可以在获取数据的同时填充图表,并在完成后保存它。所以为了测试,我将它添加到我的 .py
import matplotlib
matplotlib.use('PDF') # I want a PDF in the end
from matplotlib import dates
import matplotlib.pyplot as plt
import numpy as np
from numpy import genfromtxt
然后有的成员来交流class,表示来自图表部分,主要是上面提到的解决方案。我在 classes init
中初始化它们 self.fig = None
self.ctg = None
self.toco = None
然后我会调用这个方法,一旦我觉得我收到的数据是正确的form/state,这样图表就可以准备好填充数据
def prepchart(self):
# how often to show xticklabels and repeat yticklabels:
print('prepchart')
xtickinterval = 5
hfmt = dates.DateFormatter('%H:%M:%S')
self.fig = plt.figure()
self.ctg = self.fig.add_subplot(2, 1, 1) # two rows, one column, first plot
plt.ylim(50, 210)
self.toco = self.fig.add_subplot(2, 1, 2)
plt.ylim(0, 100)
# Set the minor ticks to every 30 seconds
minloc = dates.SecondLocator(bysecond=[0,30])
minloc.MAXTICKS = 3000000
self.ctg.xaxis.set_minor_locator(minloc)
# self.ctg.xaxis.set_minor_locator(dates.MinuteLocator())
self.ctg.xaxis.set_major_formatter(hfmt)
self.toco.xaxis.set_minor_locator(dates.MinuteLocator())
self.toco.xaxis.set_major_formatter(hfmt)
# actg.xaxis.set_ticks(rotation=45)
plt.xticks(rotation=45)
然后每隔一段时间,一旦我有数据想要绘制,我就会在我的数据处理方法中这样做
self.ctg.plot_date(timevalue, heartrate, '-')
self.toco.plot_date(timevalue, toco, '-')
最后,一旦不再发送数据(可能是一分钟或 24 小时后),我会打电话给
def handleCTG(self):
self.fig.savefig('/home/pi/test.pdf')
结论:我的做法是完全错误的还是我的代码中存在错误?这真的是一种减少图表生成等待时间的方法吗?
好的,这就是交易。显然 web2py 运行非常严格。这意味着没有那么多线程浮动,它肯定不会为我的小图表创建启动一个新线程。我有点注意到这一点,当我在我的 Raspis taskmanager 上使用 CPU 时,只看到了大约 25% 的东西。现在 Raspberry Pi 有 4 个内核...去计算一下。首先,我 运行 我的脚本在我的 Raspi 上的 web2py 之外,你瞧,包括 csv 读取和图表渲染在内的整个过程只需要 20 秒。从那里开始(受 How to run a task outside web2py and retrieve the output 启发)这是小菜一碟:使用记录良好的子流程通过此脚本调用新的 python 并完成。所以感谢任何对此提出一些想法的人。