I want to limit my graph from left and set (the current time - 2 hours) to xlim. I tried to add to the "update" function this
self.ax.set_xlim(left=max(self.data.iloc[0, 0], self.data.iloc[-1, 0] - pd.Timedelta(hours=2)))
But this is doesn't work. Could anyone help me do this, please?
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from datetime import datetime
import pandas as pd
def to_pd(wt, wf):
p = pd.DataFrame({"Date": [wt], "Cost": [wf]})
p["Date"] = pd.to_datetime(p["Date"], format='%Y-%m-%d %H:%M:%S')
return p
fig = plt.figure(figsize=(18,8), dpi=90)
class Graph():
def __init__(self):
self.ax = fig.add_subplot()
self.start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.data = to_pd(self.start_time,0)
self.line, = self.ax.plot(self.data.Date,self.data.Cost)
def update(self,i):
self.current_time = (self.data.iloc[-1,0]+pd.Timedelta(minutes=1)).strftime('%Y-%m-%d %H:%M:%S')
self.data = self.data.append(to_pd(self.current_time,(-1)**i))
self.line.set_data(self.data.Date, self.data.Cost)
self.ax.relim()
self.ax.autoscale_view()
return self.line,
object = Graph()
def animate(i):
return object.update(i)
anim = FuncAnimation(fig, animate, frames=200,interval=100, blit=True)
plt.show()
Solved, but I think there is more convenient way. But, here what am done, just added it into the 'update' function, it's clear all old data:
if self.data.iloc[-1, 0] - pd.Timedelta(hours=2) >= self.data.iloc[0, 0]:
self.data = self.data[self.data.Date > self.data.iloc[0, 0]]
Related
Does anyone have any suggestions for creating 2 datasets at once? When I run dataset = ImbCircuitDataset('test'), I want it to save 2 separate sets, even if I have to go all the way back to self.data and split it there, I just want the class to produce 2 separate datasets.
Basically run set1, set2 = ImbCircuitDataset('test')
I started doing it at the bottom of the def process(self) but I have a feeling its wrong. I am thinking in def processed_file_names(self) I need to return 'set1.pt', 'set2.pt'.
from scipy.io import loadmat
import pandas as pd
from torch_geometric.data import Data, InMemoryDataset
import torch
import neptune.new as neptune
import numpy as np
import torch_geometric
from tqdm import tqdm
from typing import Tuple, Union
from torch import Tensor
from collections.abc import Sequence
from torch_geometric.utils import from_networkx
import networkx as nx
import matplotlib.pyplot as plt
IndexType = Union[slice, Tensor, np.ndarray, Sequence]
print(f"Torch version: {torch.__version__}")
print(f"Cuda available: {torch.cuda.is_available()}")
print(f"Torch geometric version: {torch_geometric.__version__}")
class ImbCircuitDataset(InMemoryDataset):
def __init__(self, root, transform=None, pre_transform=None,
pre_filter=None):
super().__init__(root, transform, pre_transform, pre_filter)
self.data, self.slices = torch.load(self.processed_paths[0])
#property
def raw_file_names(self):
return 'shuffled_data.mat'
#property
def processed_file_names(self):
return 'data.pt'
def download(self):
pass
def process(self):
self.raw_data = loadmat(self.raw_paths[0], squeeze_me=True)
self.data = pd.DataFrame(self.raw_data['Graphs'])
self.data = self.data.sort_values('Labels', ascending=True, ignore_index=True)
for i in range(len(self.data)):
self.data['Ln'][i] = dict(enumerate(self.data['Ln'][i]))
data_list = []
for index, cir in tqdm(self.data.iterrows(), total=self.data.shape[0]):
nxg = nx.Graph(self.data['A'][index])
nx.set_node_attributes(nxg, self.data['Ln'][index], 'component')
pt_graph = self._get_graph_object(nxg)
pt_graph.x = self._get_node_features(nxg, self.data['Ln'][index])
pt_graph.performance = torch.tensor(self.data['Labels'][index], dtype=torch.float)
data_list.append(pt_graph)
if self.pre_filter is not None:
data_list = [d for d in data_list if self.pre_filter(d)]
if self.pre_transform is not None:
data_list = [self.pre_transform(d) for d in data_list]
split = 0.5
N = len(data_list)
set_1 = data_list[:N*split]
set_2 = data_list[N*split:]
data1, slices1 = self.collate(set_1)
data2, slices2 = self.collate(set_2)
torch.save((data1, slices1), self.processed_paths[0])
torch.save((data2,slices2), self.processed_paths[0])
def _get_node_features(self, nxgraph, node_labels):
betweenness = list(nx.betweenness_centrality(nxgraph).values())
eigenvector = list(nx.eigenvector_centrality(
nxgraph, max_iter=600).values())
mapping_dict = {'C': 0, 'G': 1, 'I': 2, 'O': 3, 'P': 4, 'R': 5}
component_labels = []
for value in node_labels.values():
if value in mapping_dict:
component_labels.append(mapping_dict[value])
all_feats = [component_labels, betweenness, eigenvector]
all_feats = np.asarray(all_feats).transpose()
return torch.tensor(all_feats, dtype=torch.float)
def _get_graph_object(self, nx_graph):
nxg = from_networkx(nx_graph)
return nxg
#property
def num_node_features(self) -> int:
return 3
#property
def num_classes(self) -> int:
return 2
I'm trying to import tick data from MT5 and display it on a candlestick chart in pyqtgraph but the graph only displays the first two candles which are preloaded to meet minimum data requirements to prevent an exception.
Beyond the original two candles the chart does not update with new values.
import pyqtgraph as pg
import numpy as np
from PyQt5 import QtWidgets, QtCore, QtGui
from pyqtgraph import PlotWidget, plot, QtCore, QtGui
import sys
import os
from random import randint
import time
import threading
import os
import queue
import random
import copy
import MetaTrader5 as mt5
from datetime import datetime
#------------------------------------------------------------------------------
'''chart items'''
class CandlestickItem(pg.GraphicsObject):
_boundingRect = QtCore.QRectF()
# ...
def __init__(self):
pg.GraphicsObject.__init__(self)
self.flagHasData = False
def set_data(self, data):
self.data = data
self.flagHasData = True
self.generatePicture()
self.informViewBoundsChanged()
def generatePicture(self):
self.picture = QtGui.QPicture()
path = QtGui.QPainterPath()
p = QtGui.QPainter(self.picture)
p.setPen(pg.mkPen('w'))
w = (self.data[1][0] - self.data[0][0]) / 3.
for (t, open, close) in self.data:
# line = QtCore.QLineF(t, min, t, max)
# path.moveTo(line.p1())
# path.lineTo(line.p2())
# p.drawLine(line)
rect = QtCore.QRectF(t-w, open, w*2, close-open)
path.addRect(rect)
if open > close:
p.setBrush(pg.mkBrush('r'))
else:
p.setBrush(pg.mkBrush('g'))
p.drawRect(rect)
p.end()
self._boundingRect = path.boundingRect()
def paint(self, p, *args):
if self.flagHasData:
p.drawPicture(0, 0, self.picture)
def boundingRect(self):
return self._boundingRect
#------------------------------------------------------------------------------
# establish connection to the MetaTrader 5 terminal
if not mt5.initialize():
print("initialize() failed, error code =",mt5.last_error())
quit()
# attempt to enable the display of the GBPUSD in MarketWatch
selected=mt5.symbol_select("EURUSD",True)
if not selected:
print("Failed to select EURUSD")
mt5.shutdown()
quit()
#------------------------------------------------------------------------------
class tick:
last_tick = 0
current_tick = 0
current_tick_number = 1
def __init__(self):
self.tick_array = np.zeros((100000,3), dtype = float)
self.pass_data = False
def _time(self, tick_index_number):
return self.tick_array[self.tick_index(tick_index_number),0]
def _open(self, tick_index_number):
# print(tick_index_number)
return self.tick_array[self.tick_index(tick_index_number),1]
def _close(self, tick_index_number):
return self.tick_array[self.tick_index(tick_index_number),2]
def _min(self, tick_index_number):
return self.tick_array[self.tick_index(tick_index_number),3]
def _max(self, tick_index_number):
return self.tick_array[self.tick_index(tick_index_number),4]
#return a negative index of n
def tick_index(self, n = 0):
return self.current_tick_number - n
#gets EURUSD current tick values
def get_tick(self):
return mt5.symbol_info_tick("EURUSD")
#add self.time/bid/ask to get_tick instead
#------------------------------------------------------------------------------
#updates tick array
def update_tick(self):
while True:
#get current tick value
current_tick = self.get_tick()
#if current tick is unique, add that value to last_tick and continue
if self.last_tick != current_tick:
self.last_tick = current_tick
#update the array with the new tick values
self.tick_array[self.current_tick_number,0], self.tick_array[self.current_tick_number,1], self.tick_array[self.current_tick_number,2] = datetime.fromtimestamp(current_tick[5] / 1000.0).strftime("%m%d%Y%I%M%S"), self.tick_array[self.current_tick_number-1, 2] , current_tick[1]
self.current_tick_number += 1
q.put(self.tick_array[:self.current_tick_number])
def tick_datafeed(self):
return self.tick_array[:self.current_tick_number]
tick = tick()
#------------------------------------------------------------------------------
''' launch threads that work the chart'''
class Threads:
def __init__(self):
pass
def thread_launch_update_tick(self):
t1 = threading.Thread(target = tick.update_tick, args = ())
t1.start()
def thread_launch_get_data_from_update(self):
t2 = threading.Thread(target = get_data_from_update, args = ())
t2.start()
def get_data_from_update():
while True:
i = q.get()
item.set_data(i)
print(tick.tick_array[:tick.current_tick_number])
q.task_done()
#------------------------------------------------------------------------------
app = QtWidgets.QApplication([])
item = CandlestickItem()
item.set_data(tick.tick_array[:tick.current_tick_number + 1])
plt = pg.plot()
plt.addItem(item)
plt.setWindowTitle('pyqtgraph example: customGraphicsItem')
q = queue.Queue()
threads = Threads()
threads.thread_launch_get_data_from_update()
threads.thread_launch_update_tick()
#------------------------------------------------------------------------------
if __name__ == '__main__':
# window = Window()
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtWidgets.QApplication.instance().exec_()
The resulting array data looks like this
which is comprised of the [date in unix, last tick, current tick] aka time/open/close
[[0.00000000e+00 0.00000000e+00 0.00000000e+00]
[7.26202211e+12 0.00000000e+00 1.01348000e+00]
[7.26202211e+12 1.01348000e+00 1.01349000e+00]
[7.26202211e+12 1.01349000e+00 1.01348000e+00]
[7.26202211e+12 1.01348000e+00 1.01347000e+00]
[7.26202211e+12 1.01347000e+00 1.01348000e+00]
[7.26202211e+12 1.01348000e+00 1.01347000e+00]
[7.26202211e+12 1.01347000e+00 1.01348000e+00]
[7.26202211e+12 1.01348000e+00 1.01347000e+00]
[7.26202211e+12 1.01347000e+00 1.01346000e+00]
[7.26202211e+12 1.01346000e+00 1.01347000e+00]
[7.26202211e+12 1.01347000e+00 1.01346000e+00]]
Can anyone point out my flaw?
The get_data_from_update() function should update the chart but it simply doesn't work for reasons that are beyond me.
I have a code that mimics a sensor, putting random values and timestamps on a txt file. From this file, being constantly updated, I can dynamic plot those values. Now my idea is to do the same thing, but getting data from a database. I'm already able to save whatever data comes for my server into the database. The thing now is the dynamic plot area.
My code for saving data into the table:
while True:
data = conn.recv(2048).decode('utf-8')
if not data:
break
#print('Servidor recebeu :', repr(data))
t = dt.datetime.now().strftime('%H:%M:%S')
c.execute('INSERT INTO edgedata VALUES (?,?)', (data, t))
con.commit()
My code for dynamic plotting from .txt file:
#!/usr/bin/env python
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
print("inside animate")
pullData = open("datatest.txt","r").read()
dataArray = pullData.split('\n')
xar = []
yar = []
for eachLine in dataArray:
if len(eachLine)>1:
x,y = eachLine.split(',')
xar.append(str(x))
yar.append(float(y))
ax1.clear()
ax1.plot(xar,yar)
plt.xlabel('Hora')
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.ylabel('Valor Dado')
plt.title('Pseudo-Sensor x Hora')
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
Any help will be appreciated. Thanks in advance!
This code did the job for me. Thanks
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
print("inside animate")
con = sqlite3.connect('edgedb')
c = con.cursor()
c.execute('SELECT data, timestamp FROM edgedata')
data = c.fetchall()
datas = []
dates = []
for row in data:
datas.append(row[1])
dates.append(float(row[0]))
ax1.clear()
ax1.plot_date(datas,dates,'-')
plt.xlabel('Hora')
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.ylabel('Valor Dado')
plt.title('Pseudo-Sensor x Hora')
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
I'm trying to call a function like in the example below, and plot while running the code. The real values that I get as y-data are not really random numbers, but the point is that I would like it to get updated real-time. The plot in my example code below is just empty though and isn't getting updated.
import numpy as np
import matplotlib.pyplot as plt
import random as rnd
import time
initial_time = time.time()
def multiple_runs(number_of_runs):
x_data, y_data = [], []
fig, ax = plt.subplots()
sc = ax.scatter(x_data, y_data)
plt.draw()
for i in range(0, number_of_runs):
x_data.append(i+1)
y_data.append(rnd.randint(0,100))
sc.set_offsets(np.c_[x_data, y_data])
fig.canvas.draw_idle()
plt.pause(0.1)
print ('Total time after run number ' + str(i+1) + ': ' + str(time.time() - initial_time))
multiple_runs(100)
UPDATE:
Thanks #ImportanceOfBeingErnest , I got the code to work. However my problem right now is that the figure closes down as soon as it's finished, is there anyway to keep it open? I tried using plt.waitforbuttonpress() but I get a strange error from QTimer, not sure how or why. This is my working example code;
import numpy as np
import matplotlib.pyplot as plt
import random as rnd
import time
initial_time = time.time()
def multiple_runs(number_of_runs):
x_data, y_data = [], []
x_data2, y_data2 = [], []
fig, ax = plt.subplots(2, sharex = True)
sc = ax[0].scatter(x_data, y_data)
sc2 = ax[1].scatter(x_data2, y_data2)
ax[0].set(xlim=(0,100), ylim=(0,100))
ax[1].set(xlim=(0,100), ylim=(0,100))
plt.draw()
for i in range(0, number_of_runs):
x_data.append(i+1)
y_data.append(rnd.randint(0,100))
x_data2.append(i+1)
y_data2.append(rnd.randint(0,100))
sc.set_offsets(np.c_[x_data, y_data])
sc2.set_offsets(np.c_[x_data2, y_data2])
fig.canvas.draw_idle()
plt.pause(0.1)
print ('Total time after run number ' + str(i+1) + ': ' + str(time.time() - initial_time))
multiple_runs(100)
UPDATE2:
I tried using FuncAnimation, but getting the error TypeError: update() missing 2 required positional arguments: 'y' and 'y2'. I still need to use the for-loop because in my real code I'm using the previous values of y, to calculate the next values of y. This is my example code which is giving me the error;
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import random as rnd
import time
initial_time = time.time()
def multiple_runs(number_of_runs):
x_data, y_data = [], []
x_data2, y_data2 = [], []
fig, ax = plt.subplots(2, sharex = True)
sc = ax[0].scatter(x_data, y_data)
sc2 = ax[1].scatter(x_data2, y_data2)
ax[0].set(xlim=(0,100), ylim=(0,100))
ax[1].set(xlim=(0,100), ylim=(0,100))
def update(i, y, y2):
x_data.append(i+1)
y_data.append(y)
x_data2.append(i+1)
y_data2.append(y2)
sc.set_offsets(np.c_[x_data, y_data])
sc2.set_offsets(np.c_[x_data2, y_data2])
print ('Total time after run number ' + str(i+1) + ': ' + str(time.time() - initial_time))
for i in range(0, number_of_runs):
y = rnd.randint(0,100)
y2 = rnd.randint(0,100)
update(i,y,y2)
ani = FuncAnimation(fig, update, frames=number_of_runs, interval=100, repeat=False)
plt.show()
multiple_runs(100)
As commented, I would recommend to use FuncAnimation. This would look as follows in your case. Note that in order to close the window, one would need to press q or close it with the mouse.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import random as rnd
import time
initial_time = time.time()
def multiple_runs(number_of_runs):
x_data, y_data = [], []
x_data2, y_data2 = [], []
fig, ax = plt.subplots(2, sharex = True)
sc = ax[0].scatter(x_data, y_data)
sc2 = ax[1].scatter(x_data2, y_data2)
ax[0].set(xlim=(0,100), ylim=(0,100))
ax[1].set(xlim=(0,100), ylim=(0,100))
def get_ydata(i):
y = rnd.randint(0,100)
y2 = rnd.randint(0,100)
return y, y2
def update(i):
y, y2 = get_ydata(i)
x_data.append(i+1)
y_data.append(y)
x_data2.append(i+1)
y_data2.append(y2)
sc.set_offsets(np.c_[x_data, y_data])
sc2.set_offsets(np.c_[x_data2, y_data2])
ani = FuncAnimation(fig, update, frames=number_of_runs, interval=100, repeat=False)
plt.show()
multiple_runs(100)
import time
import datetime as dt
import urllib.request
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt
import matplotlib.animation as Animation
from matplotlib import style
import matplotlib
import csv
import threading
style.use('fivethirtyeight')
fig = plt.figure()
def usd_in_bitcoin():
try:
resp = urllib.request.urlopen("https://bitcoinwisdom.com/")
except Exception as e:
print(e)
text = resp.read()
soup = BeautifulSoup(text, 'html.parser')
intermediate = soup.find('tr', {"id": "o_btcusd"})
ans = intermediate.find('td', {'class': 'r'})
return ans.contents[0]
def write_to_file(interval):
while True:
value = str(usd_in_bitcoin())
unix_time = str(time.time())
print(unix_time, value)
with open('bitcoin_usd.csv', 'a+') as file:
file.write(unix_time)
file.write("," + str(value))
file.write('\n')
time.sleep(interval)
def animate(i):
with open('bitcoin_usd.csv') as csv_file:
readcsv = csv.reader(csv_file, delimiter=',')
xs = []
ys = []
for row in readcsv:
if len(row) > 1:
x, y = [float(s) for s in row]
xs.append(dt.datetime.fromtimestamp(x))
ys.append(y)
print(len(xs))
dates = matplotlib.dates.date2num(xs)
# print(dates)
fig.clear()
plt.plot_date(dates, ys)
def plotting():
ani = Animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
def main():
# plotting()
b = threading.Thread(name='making graph', target=plotting)
# a = threading.Thread(name='updating_csv', target=write_to_file, args=(5,))
# a.start()
b.start()
if __name__ == '__main__':
main()
In the above block of code, I am trying to plot the value of a bitcoin in usd by using scraping and then putting the value in a csv file.
Then I read the csv file to plot the graph.
Both plotting and scraping seem to work fine but if I do both of them simultaneously, I am getting an error saying main thread not in main loop. I searched a lot but was not able to solve this problem
The problem here is with the sequence of lines in main()
Try this:
def main():
a = threading.Thread(name='updating_csv', target=write_to_file, args=(5,))
a.start()
b = threading.Thread(name='making graph', target=plotting)
b.start()
plotting()