У меня проблема, подобная этой статье, но немного более расстраивающей.
Я использую matplotlib для чтения из файла, который передается из другого приложения. По какой-то причине концы данных подключаются только после того, как анимация (animation.FuncAnimation
) завершила свое первое обновление. Вот несколько изображений:
Это до обновления:
И это после обновления:
Любые идеи относительно того, почему это может произойти? Вот мой код:
import json
import itertools
import dateutil.parser
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
import scipy.signal as sig
import numpy as np
import pylab as plt
sensors = {}
data = []
lastLineReadNum = 0
class Sensor:
def __init__(self, name, points = 0, lastReading = 0):
self.points = points
self.lastReading = lastReading
self.name = name
self.x = []
self.y = []
class ScanResult:
def __init__(self, name, id, rssi, macs, time):
self.name = name
self.id = id
self.rssi = rssi
self.macs = macs
# Is not an integer, but a datetime.datetime
self.time = time
def readJSONFile(filepath):
with open(filepath, "r") as read_file:
global lastLineReadNum
# Load json results into an object that holds important info
for line in itertools.islice(read_file, lastLineReadNum, None):
temp = json.loads(line)
# Only reads the most recent points...
data.append(ScanResult(name = temp["dev_id"],
id = temp["hardware_serial"],
rssi = temp["payload_fields"]["rssis"],
macs = temp["payload_fields"]["macs"],
time = dateutil.parser.parse(temp["metadata"]["time"])))
lastLineReadNum += 1
return data
style.use('fivethirtyeight')
fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)
def smooth(y, box_pts):
box = np.ones(box_pts)/box_pts
y_smooth = np.convolve(y, box, mode='same')
return y_smooth
def determineClosestSensor():
global sensors
#sensors.append(Sensor(time = xs3, rssi = ys3))
def determineXAxisTime(scanresult):
return ((scanresult.time.hour * 3600) + (scanresult.time.minute * 60) + (scanresult.time.second)) / 1000.0
def animate(i):
data = readJSONFile(filepath = "C:/python_testing/rssi_logging_json.json")
for scan in data:
sensor = sensors.get(scan.name)
# First time seeing the sensor
if(sensor == None):
sensors[scan.name] = Sensor(scan.name)
sensor = sensors.get(scan.name)
sensor.name = scan.name
sensor.x.append(determineXAxisTime(scan))
sensor.y.append(scan.rssi)
else:
sensor.x.append(determineXAxisTime(scan))
sensor.y.append(scan.rssi)
ax1.clear()
#basic smoothing using nearby averages
#y_smooth3 = smooth(np.ndarray.flatten(np.asarray(sensors.get("sentrius_sensor_3").y)), 1)
for graphItem in sensors.itervalues():
smoothed = smooth(np.ndarray.flatten(np.asarray(graphItem.y)), 1)
ax1.plot(graphItem.x, smoothed, label = graphItem.name, linewidth = 2.0)
ax1.legend()
determineClosestSensor()
fig.suptitle("Live RSSI Graph from Sentrius Sensors", fontsize = 14)
def main():
ani = animation.FuncAnimation(fig, animate, interval = 15000)
plt.show()
if __name__ == "__main__":
main()
Насколько я могу судить, вы обновляете свои данные на каждом шаге анимации, добавляя к существующим наборам данных, но тогда это означает, что ваша последняя точка x
с первого шага сопровождается первой точкой x
на втором этапе, что приводит к перемотать в сюжет. Это отображается как линия, соединяющая последний набор данных с первым; остальная часть данных не изменяется.
Соответствующая часть animate
:
def animate(i):
data = readJSONFile(filepath = "C:/python_testing/rssi_logging_json.json")
for scan in data:
sensor = sensors.get(scan.name)
# First time seeing the sensor
if(sensor is None): # always check for None with 'is'!
... # stuff here
else:
sensor.x.append(determineXAxisTime(scan)) # always append!
sensor.y.append(scan.rssi) # always append!
... # rest of the stuff here
Таким образом, на каждом шаге анимации вы 1. загружаете один и тот же файл JSON. 2. добавляйте те же данные к существующему датчику, идентифицированному sensors.get(scan.name)
3. sensors.get(scan.name)
сюжет без использования i
.
Во-первых, ваш animate
должен, естественно, использовать индекс i
: вы пытаетесь сделать что-то относительно шага i
. Я не вижу, как i
где-либо пользуюсь.
Во-вторых, ваш animate
должен быть максимально легким, чтобы получить гладкую анимацию. Загрузите свои данные один раз перед построением графика и обработайте только различия чертежа в animate
. Это будет связано с нарезкой или управлением вашими данными в зависимости от i
.
Конечно, если файл действительно меняется с шага на шаг, и это фактическая динамика в анимации (т.е. i
- фиктивная переменная, которая никогда не используется), все, что вам нужно сделать, это нуль-инициализировать все данные графика в каждом шаг. Начните с чистого листа. Затем вы перестанете видеть строки, соответствующие этим искусственным скачкам в данных. Но опять же, если вы хотите animate
светлый вес, вы должны изучить манипулирование базовыми данными существующих сюжетов, а не повторять все все время (тем более, что призывы к ax1.plot
будут содержать более ранние точки на холсте, что не так, как вы обычно хотите в анимации).