This question mostly pertains to Matplotlib and animation. The issue is that when animation is updated i need to clear out the axis each time or I get overlapping images because of color changes. When i was using matplotlib-1.0.1 the code below was working fine, but now that I am using matplotlib-1-3.1 if I continue to use ax.clear() in the code below the images of ax do not show up on the chart. Here is the code:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
from finance_pylab import quotes_historical_yahoo, candlestick,plot_day_summary, candlestick2,volume_overlay
from pylab import *
import f_charting
import f_datamanip # to use idx_of_last_unique
import f_tcnvrt # for dukascopy date
from numpy import*
import f_file_handling
import first_add2file
import f_dukascopy_fetcher
import datetime ## so we can print a time stamp we recognize
import f_candle_stick_maker3_fluent
anim_data_file='candle_test6'
showlast_idxs=40
tframe=5 ##how many minutes candles will be #minutes
dukas_file_name="EURUSD_1m_jan2012"
first_candle=datetime.datetime(2012,1,1,22,10,0) ## start chart here
last_candle=datetime.datetime(2012,1,2,1,55,0) ## start trading after here
candle_name_LDP_diff=datetime.timedelta(0,(tframe-1)*60) ##LDP = last_data_point
dukas_last_data_point=last_candle+candle_name_LDP_diff
Dcsv,D,O,H,L,C,V=f_dukascopy_fetcher.dukas2(dukas_file_name,first_candle,dukas_last_data_point)## will get data up to data_end, could just put in high date to take all in file#,s_date)#,data_start,s_date)
f_candle_stick_maker3_fluent.candle_2_txtfile(anim_data_file,tframe,first_candle,last_candle,Dcsv,D,O,H,L,C,V,0)
filename='candle_test6';file_name=filename+'.txt'
candle_width=.8;colorup='#33CC33'; colordown='#E80000' ;up_col='#B8B8B8';down_col='w'
rect1=[.05,.14,.94,.82]#left, bottom, width, height #rect1=[.1,.1,.8,.7] #seems full:rect1=[.02,.04,.95,.93] , the more you move left , you also have to adjust width. bottom and hight push on each other as well
fig =plt.figure(figsize=(15,7),facecolor='white');axescolor ='#f6f6f6' #'#200000' #'#180000' ##100000'#f6f6f6' # the axies background color # border of chart
ax = fig.add_axes(rect1, axisbg=axescolor) #start with volume axis
ax1v = ax.twinx()
def candle_animate(i):
pullData = open(anim_data_file+'.txt','r').read()
dataArray= pullData.split('\n')
contig_time=[];_open=[];_close=[];_high=[];_low=[];_vol=[]; _timevec=[]
for eachLine in dataArray:
if len(eachLine)>1:
_t,_o,_c,_h,_l,_v,u=eachLine.split(',')##x,y=eachLine.split(',')
_timevec.append(f_tcnvrt.str2time_dukascopy(_t))
_open.append(float(_o))
_close.append(float(_c))
_high.append(float(_h))
_low.append(float(_l))
_vol.append(float(_v))
units_print=u
_open=array(_open);_close=array(_close);_high=array(_high);_low=array(_low);_vol=array(_vol)
ax.clear();ax1v.clear() # this line worked with matplotlib-1.0.1 but matplotlib-1.3.1 keeps ax blank
D=_timevec;O=_open;H=_high;L=_low;C=_close;V=_vol
time_delta=datetime.timedelta(0,tframe*60)
last_data_point=D[-1]
_time,_open,_high,_low,_close,_vol=f_candle_stick_maker3_fluent.cs_maker(tframe,first_candle,last_data_point,D,O,H,L,C,V)
contig_time=range(0,len(_time))
chartstart=len(contig_time)-showlast_idxs
numXlbls=12
myidx,x_label=f_charting.x_labels_last_tick_showall_contig(_time,numXlbls)
data4candleshow=transpose([contig_time,_open,_close,_high,_low,_vol])
data4candle=transpose([contig_time,_open,_close,_high,_low,_vol])[-showlast_idxs:]
candlestick(ax, data4candle, width=candle_width,colorup='#33CC33',colordown='#E80000') #'#00FF00' '#C11B17'
f_charting.bar_vol(contig_time[-showlast_idxs:],_open[-showlast_idxs:],_close[-showlast_idxs:],_vol[-showlast_idxs:],ax1v,candle_width,up_col,down_col)
ani=animation.FuncAnimation(fig,candle_animate, interval=1000)
plt.show()
I took a lot out of the code to make it simpler, but i know there is still a lot to look at. Hopefully some expert knows more about the difference between the 2 matplotlib editions or is familiar with my issue. There must be a a clean way to clear out the chart between updates so i don't get overlapping images.
Note: the line: ax.clear();ax1v.clear() can be found in the code above and has a comment next to it denoting this is the line that worked for its purpose in the older matplotlib, but now unfortunately clears out the graph when using matplotlib-1.3.1
Thank you
Related
I am working on a project that requires me to log data over time, while also plotting the data on screen with a live line graph. I have gotten everything but the line graph to work this far and am unsure what I am doing incorrectly. This is the imports that I am currently using.
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import pyplot as plt
from matplotlib import style
from tkinter import *
from PIL import Image
import numpy as np
import serial
from serial import Serial
import sqlite3
import time
from datetime import datetime
from array import *
import cv2
from pathlib import Path
from itertools import count
The data that is meant to be used for the Y axis plotting is stored in an array of data. Each index in this array is to hold the last read value from the sensors, i=0 is sensor 1 and so on.
A=[0,0,0,0,0,0,0,0]
This is the definition of the subplot that I am trying to draw to. I think I am setting this up correctly, however I am not getting the expected result so likely not.
fig1 = plt.Figure(dpi=100, facecolor="#f0f0f0")
a = fig1.add_subplot(111)
a.patch.set_facecolor("#f0f0f0")
a.set_xlabel('time (Sec)')
a.set_ylabel('pressure(kPa)')
a.set_ylim(0,100)
a.set_xlim(0,30)
graph1 = FigureCanvasTkAgg(fig1, master=root)
graph1.get_tk_widget().place(x=10, y=220, width=210, height=280)
graph1.draw();
I am currently just trying to get one of the lines to draw first before handling the, seemingly, minor issue that is overlapping multiple lines. This is the function that I am trying to use in order to draw said line.
def graph_plotdata():
global A
global a
line1 = []
time = []
time.append(next(index))
line1.append(A[0])
a.cla()
a.plot(time, line1)
graph1.draw()
I have tried several iterations of this code in order attempt to solve this problem. The closest I have to getting it to work is in the current state in which something is happening however instead of keeping my min and max limits on the graph it completely reformats my plot and plots an "invisible" line.
Before starting:
After starting:
I am not overwhelmingly experienced when is comes to python libraries so bare with me.
I use a dictionary to store the various lines and line plots and then update the plots using set_data(xdata, ydata). I'm not sure how your datastream works, so mine just updates when I push the update button and generates a random reading. You'll obviously want to change those parts to match your data input.
fig, ax = plt.subplots(1, 1)
plt.subplots_adjust(bottom = 0.20)
num_sensors = 10
latest_reading = [0]*num_sensors
lines = {index: [0] for index in range(num_sensors)}
times = [0]
line_plots = {index: ax.plot(lines[index])[0] for index in range(num_sensors)}
btn_ax = plt.axes([0.475, 0.05, 0.10, 0.05])
def update(event):
latest_reading = np.random.randint(0, 10, num_sensors)
times.append(times[-1] + 1)
for index in range(num_sensors):
lines[index].append(latest_reading[index])
line_plots[index].set_data(times, lines[index])
# Adjust limits
max_time_window = 20
ax.set_xlim(max(0, max(times)-max_time_window), max(times))
ax.set_ylim(0, max(lines))
plt.draw()
btn = mpl.widgets.Button(btn_ax, 'Update')
btn.on_clicked(update)
Thank you for the response.
I figured out the issue, it had nothing to do with my matplotlib/tkinter implementation. I just totally missed that I had a scope inheritance issue. The lists of 'time' and 'line1' are not persistent in the entire scope and therefore being rewritten to empty lists every time the 'graph_plotdata()' function is called.
my solution is as follows:
timet = []
line1 = []
"""----------Graph Updater-----------"""
def graph_plotdata():
global B
global a
global graph1
global timet
global line1
timet.append(next(index))
line1.append(B[0])
a.clear()
a.plot(timet, line1)
a.patch.set_facecolor("#f0f0f0")
a.set_xlabel('time (Sec)')
a.set_ylabel('pressure(kPa)')
a.set_ylim(0,30)
a.set_xlim(0,30)
graph1.draw()
Hopefully this helps people in the future running into a similar issue!
I would like to be able to change the x limits so it shows a time frame of my choice.
reproducible example:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# libraries for Data Download
import datetime # if you want to play with the dates
from pandas_datareader import data as pdr
import yfinance as yf
df = pdr.get_data_yahoo('ETH-USD', interval = '1d', period = "5y")
plt.figure(figsize=(24,10), dpi=140)
plt.grid()
df['Close'].plot()
df['Close'].ewm(span=50).mean().plot(c = '#4d00ff')
df['Close'].ewm(span=100).mean().plot(c = '#9001f0')
df['Close'].ewm(span=200).mean().plot(c = '#d102e8')
df['Close'].ewm(span=300).mean().plot(c = '#f101c2')
df['Close'].rolling(window=200).mean().plot(c = '#e80030')
plt.title('ETH-USD PLOT',fontsize=25, ha='center')
plt.legend(['C L O S E', 'EMA 50','EMA 100','EMA 200','EMA 300','MA 200', ])
# plt.xlim(['2016-5','2017-05']) # My attempt
plt.show()
when un-commenting the line above I get:
I would have liked '2016-5' to '2017-05' to have taken up the whole plot so I can see more detail.
It seems to me that you xlim works well, however, if I understand your question correctly, you also need to adjust ylim (let's say (0,100) from your graph, as it doesn't seem data within the time period specified goes past value of 100) to stretch data vertically, and so fill the graph efficiently.
try adding plt.ylim((0,100)) together with your commented code
Output:
with your plt.xlim(['2016-5','2017-05']) and plt.ylim((0,100))
with your plt.xlim(['2016-5','2017-05']) and plt.ylim((0,40))
as you can see, due to data variance in the period, you might lose some data information at later dates or have less clear image of movement at earlier dates.
I have a graph within a GUI which opens with a button click. It opens from a csv file that constantly updates, hence the counting at the beginning, I wanted to limit the number of entries for the x-axis.
The plot works for the four lines however, I have been unable to refine the x axis, what I would like to do is;
Rotate the font
Remove the trailing zeros for the dates
Possibly Change the Date Format to D-M-Y H:M
The Below script is what I have so far:
def open_graph():
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt
from dateutil import parser
from csv import reader
with open('Voltage_Readings.csv','r') as f:
data = list(reader(f))
file=open('Voltage_Readings.csv')
numlines=(len(file.readlines())-1)
start=numlines-100
end=numlines
fig=plt.figure()
ax=plt.subplot(111)
DTG = [parser.parse(i[1]) for i in data[start:end]]
Battery_Level = [i[2] for i in data[start:end]]
Gene_Supply = [i[3] for i in data[start:end]]
Solar_Supply = [i[4] for i in data[start:end]]
Wind_Supply = [i[5] for i in data[start:end]]
plt.plot(DTG, Battery_Level,'-r', label='Battery')
plt.plot(DTG, Gene_Supply,'-y', label='Gene')
plt.plot(DTG, Solar_Supply,'-b', label='Solar')
plt.plot(DTG, Wind_Supply,'-g', label='Wind')
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width *0.85, box.height])
ax.legend(bbox_to_anchor=(1, 1),loc=2)
plt.title('VOLTAGE MEASUREMENTS FROM POWER SOURCES')
plt.xlabel('Time')
plt.ylabel('Voltage')
plt.show()
I would appreciate any assistance is being able to achieve this as I am still learning.
Here is a better answer:
Just add this before your plt.show() command:
fig.autofmt_xdate()
import matplotlib.dates as mdates
ax.fmt_xdata = mdates.DateFormatter('%d-%m-%Y %H:%M')
datetimefmt = mdates.DateFormatter("%d-%m-%Y %H:%M")
ax.xaxis.set_major_formatter(datetimefmt)
Running autofmt_xdate makes the dates slanted.
Setting ax.fmt_xdata sets the date format when you hover your mouse over a point.
Running ax.xaxis.set_major_formatter sets the date format on the x axis.
Interestingly enough in my own matplotlib code I've done my own formatting of the dates on the x axis because I wasn't aware of these auto formatting features. I'm going to have to revise my code to use what's already in matplotlib.
Bobby
I am quite new to Python, so please excuse if this is a stupid beginner's error. However I am struggling with it for quite some time.
I want to create a figure with n x m subplots, each subplot being np.array of shape [1024,264,264]. As I am looking for differences occuring in the stack along the 0-dimension I want to use a slider to explore all stacks in my figure simultaneously.
The slider instance works nicely for a figure with one subplot but I can't bring them all to work.
That's the code I am using:
import os
from matplotlib import pyplot as plt
import numpy as np
import glob
import h5py
#Define the xy size of the mapped array
xsize=3
ysize=3
lengthh5=9
readlist=[]
for i in range (0,lengthh5):
npraw=np.random.rand(200,50,50)
readlist.append (npraw)
''' Slider visualization'''
from matplotlib.widgets import Slider
fig=plt.figure()
for k in range (0,lengthh5):
ax=fig.add_subplot(xsize,ysize,k)
frame = 10
l = ax.imshow(readlist[k][frame,:,:])
plt.axis('off')
sframe = Slider(fig.add_subplot(50,1,50), 'Frame', 0, len(readlist[0])-1, valinit=0)
def update(val):
frame = np.around(sframe.val)
l.set_data(readlist[k][frame,:,:])
sframe.on_changed(update)
plt.show()
For this particular case I stripped it down to a 3x3 array for my figure and just create randmom (smaller) arrays.
The slider is interestinly only operable on the second last subplot. However I have no real idea how to link it to all subplots simulatenously. Perhaps someone has an idea how to do this.
Thanks a lot in advance,
Tilman
You need to store each imshow AxesImage in a list and inside update, loop over all of them and update each based on the slider,
import os
from matplotlib import pyplot as plt
from matplotlib.widgets import Slider
import numpy as np
import glob
import h5py
#Define the xy size of the mapped array
xsize=3
ysize=3
lengthh5=9
readlist=[]
for i in range (0,lengthh5):
npraw=np.random.rand(200,50,50)
readlist.append (npraw)
fig=plt.figure()
ls = []
for k in range (0,lengthh5):
ax=fig.add_subplot(xsize,ysize,k)
frame = 10
l = ax.imshow(readlist[k][frame,:,:])
ls.append(l)
plt.axis('off')
sframe = Slider(fig.add_subplot(50,1,50), 'Frame',
0, len(readlist[0])-1, valinit=0)
def update(val):
frame = np.around(sframe.val)
for k, l in enumerate(ls):
l.set_data(readlist[k][frame,:,:])
sframe.on_changed(update)
plt.show()
I am creating a demo using IPython notebook. I launch the notebook in the pylab inline mode, e.g. ipython notebook --pylab=inline, and what I would like to do is progressively build a plot, modifying aspects of the plot in subsequent cells, and having the chart redisplay after each modification. For instance, I would like to have consecutive cells,
CELL 1:
from pandas.io.data import DataReader
from datetime import datetime
import matplotlib.pyplot as plt
goog = DataReader("GOOG", "yahoo", datetime(2000,1,1), datetime(2012,1,1))
close_vals = goog['Close']
plot(close_vals.index, close_vals.values)
CHART DISPLAYED INLINE
CELL 2:
xlim(datetime(2009,1,1), datetime(2010,1,1))
MODIFIED CHART DISPLAYED INLINE
However, the original chart doesn't seem to make it's way into subsequent cells, and the chart displayed in CELL 2 is empty. In order to see the original plot with the modification, I have to re-issue the plot command,
CELL 2:
plot(close_vals.index, close_vals.values)
xlim(datetime(2009,1,1), datetime(2010,1,1))
This quickly gets clunky and inelegant as I add moving average trend lines and labels. Also, working from the IPython console, this method of progressively building a plot works just fine. Anyone know of a better way to create this kind of demo in the notebook? Thanks.
UPDATE:
My final code ended up looking like this.
CELL 1:
from pandas.io.data import DataReader
from datetime import datetime
import matplotlib.pyplot as plt
goog = DataReader("GOOG", "yahoo", datetime(2000,1,1), datetime(2012,1,1))
close_vals = goog['Close']
fig, ax = subplots(1,1)
ax.plot(close_vals.index, close_vals.values,label='GOOG Stock Price')
CELL 2:
ax.set_xlim(datetime(2009,1,1), datetime(2010,1,1))
fig
CELL 3:
avg_20 = [ sum(close_vals.values[i-20:i])/20.0 for i in range(20,len(close_vals))]
avg_20_times = close_vals.index[20:]
ax.plot(avg_20_times, avg_20, label='20 day trailing average')
ax.legend()
fig
After updating ax in each subsequent cell, calling fig redisplays the plot; exactly what I was looking for. Thanks!
You can use variables to reference the figure and Axe objects:
In cell 1:
fig, ax = subplots(1, 1)
plot(randn(100));
In cell 2:
ax.set_xlim(20, 40)
fig