I have data stored in stock_data in JSON format (which can be any arbitrary data). I want to plot 4 axes, and WHEN there is new data, update the graph (through animate I am assuming).
I only want this to occur when using INTRADAY data (as you can see I have an if intraday check at the bottom). I am pulling this intraday data from an API. This API updates every minute or so, and only during certain hours. I don't mind if it doesn't update instantly, but ideally within a 1 minute period of new data.
I have tried pulling new data and comparing it to the old DF (as you can see at the end of the code) and putting it in a while True: loop, however the graph fails to render. I have tried simply putting the entire function in a loop and rendering the graph every time - this not only takes ages to render, but if I am zoomed in on the graph, it completely resets it. I figure this is a problem with redrawing?
Finally, I am unsure what to put in the animation.FuncAnimation() either.. I have excluded ax3 and ax4 because they'll act the same as ax2 for demonstration purposes. Help is much appreciated.
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import matplotlib.dates as mdates
import matplotlib.animation as animation
from mpl_finance import candlestick_ohlc
import numpy as np
## CANDLESTICK GRAPH ##
def candlestick(symbol, MA1 = 20, MA2 = 200):
try:
## arbitrary colors ##
candle_upcol = '#cccccc'
candle_downcol = '#cccccc'
fill_col = '#cccccc'
bg_col = '#cccccc'
spine_col = '#cccccc'
## load stocks ##
stock_data = pd.DataFrame.from_dict(json.load(open('db/AAPL.txt')), orient = 'index', dtype = np.float64)
stock_data = stock_data.values
## BEGIN PLOTTING ##
start_point = len(stock_data[max(MA1, MA2)-1:])
fig = plt.figure(facecolor=bg_col)
#set grids
ax1 = plt.subplot2grid((8,4), (1,0), rowspan = 5, colspan = 4, facecolor = bg_col)
ax2 = plt.subplot2grid((8,4), (7,0), rowspan = 1, colspan = 4, sharex = ax1, facecolor= bg_col)
ax3 = plt.subplot2grid((8,4), (0,0), rowspan = 1, colspan = 4, sharex = ax1, facecolor = bg_col)
ax4 = plt.subplot2grid((8,4), (6,0), rowspan = 1, colspan = 4, sharex = ax1, facecolor = bg_col)
#PRICE plot (AX1)
candlestick_ohlc(ax1, stock_data[-start_point:,0:5], width = 0.6, colorup = candle_upcol, colordown = candle_downcol)
ax1.xaxis.set_major_locator(mticker.MaxNLocator(10))
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
ax1.grid(True)
plt.setp(ax1.get_xticklabels(), visible=False) #remove x ticks
#MOVING AVERAGES plot (AX1)
if MA1 != 0:
av1 = moving_average(stock_data[:,4], MA1) #using close prices
label_ma1 = '{MA} SMA'.format(MA = str(MA1))
ax1.plot(stock_data[-start_point:,0], av1[-start_point:], label = label_ma1, color = '#aec6cf', linewidth = .8)
if MA2 != 0:
av2 = moving_average(stock_data[:,4], MA2) #using close prices
label_ma2 = '{MA} SMA'.format(MA = str(MA2))
ax1.plot(stock_data[-start_point:,0], av2[-start_point:], label = label_ma2, color = '#ffb347', linewidth = .8)
if MA1 != 0 or MA2 != 0:
ax1.text(0, 1, 'MA ({MA1}, {MA2})'.format(MA1 = str(MA1), MA2 = str(MA2)), va = 'top', ha = 'left', color = 'w', transform = ax1.transAxes, alpha = 0.5, fontweight = 'bold')
#VOLUME plot (AX2)
volume_min = 0 #stock_data[:,5].min()
ax2.plot(stock_data[-start_point:,0], stock_data[-start_point:,5], '#00ffe8', linewidth = .8)
ax2.fill_between(stock_data[-start_point:,0], volume_min, stock_data[-start_point:,5], facecolor = fill_col, alpha = 0.5)
ax2.axes.yaxis.set_ticklabels([]) #remove y ticks
ax2.text(0, 1, 'VOLUME', va = 'top', ha = 'left', color = 'w', transform = ax2.transAxes, alpha = 0.5, fontweight = 'bold')
#RSI plot (AX3)
#similar to VOL
#MACD plot (AX4)
#similar to VOL
#SHARED plot (ALL AX)
for all_ax in (ax1, ax2''', ax3, ax4'''):
plt.setp(all_ax.spines.values(), color=spine_col)
all_ax.tick_params(axis='both', colors = 'w')
all_ax.yaxis.label.set_color("w")
all_ax.yaxis.tick_right()
all_ax.xaxis.set_tick_params(labelsize=9)
all_ax.yaxis.set_tick_params(labelsize=9)
#ENTIRE plot
plt.subplots_adjust(hspace = 0)
fig.autofmt_xdate()
fig.suptitle('{STOCK}'.format(STOCK = symbol), color = 'w', fontweight='bold', alpha = 0.75)
print('Drawing graph.')
if data_type != 'Intraday':
print('Graphing complete.')
else:
#this will be replaced by an API fetch function at some point, this is just for testing if animation works.. needs a sleep function? and while True loop..?
new_stock_data = pd.DataFrame.from_dict(json.load(open('db/AAPL_new.txt')), orient = 'index', dtype = np.float64)
new_stock_data = new_stock_data.values
if (new_stock_data[-1] == stock_data[-1]).all() == False:
stock_data = np.vstack([stock_data, new_stock_data[-1]])
#ani = animation.FuncAnimation(fig, '''???''', interval = 10000) #blit=True?
plt.show()
except:
print('Failed main loop.')
A FuncAnimation will draw (or blit) repeatedly at a rate given by the interval. In case that is not desired, one could use a timer instead. The timer calls a function that will, depending on some condition either do nothing, or update the plot with new data. This way you make sure to only draw the canvas when new data is available (i.e. condition is true).
import datetime
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
t = []
x = []
line, = ax.plot_date(t,x, ls="-")
def update():
now = datetime.datetime.now()
if np.random.rand() > 0.9:
t.append(now)
x.append(np.random.randn())
line.set_data(t,x)
ax.relim()
ax.autoscale_view()
fig.canvas.draw_idle()
message = "new data drawn"
else:
message = "no new data"
print(now.time(), message)
timer = fig.canvas.new_timer(interval=200)
timer.add_callback(update)
timer.start()
plt.show()
Related
I finally managed to make my animations work. The only problem comes when I save them with ffmpeg writer. A ~250 frame gif takes literally a few hours to save. It took me 3 hours to save an 11 second video.
What is making it take so long??
import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import contextily as cx
from matplotlib.offsetbox import AnchoredText
#Writer information, path, and where to save
plt.rcParams['animation.ffmpeg_path'] =r"the path I saved ffmpeg"
#writer = animation.writers['ffmpeg']
f = r"location I will save the .mp4"
# Reads the Excel sheet specified from the doc. IT ONLY OPENS .XLSM
df = pd.read_excel(r'the excel file', sheet_name='the sheet name')
# Creates a list of important datasets
df['Points'] = list(zip(df.Latitude,df.Longitude))
Longs = list(df.Longitude)
Lats = list(df.Latitude)
Time = list(df.Last_Record)
Speed = list(df.Speed)
#This is the list of Coordinates
Coords = df['Points']
#print(Coords)
#how many frames to save for the animation
savecount = len(Longs)
print("Frames: ",savecount)
#turns the dataframe into a geodataframe
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.Longitude, df.Latitude),crs='EPSG:4326')
#Geodataframe boundaries
minx, miny, maxx, maxy = gdf.geometry.total_bounds
print("Boundaries: ",minx, miny, maxx, maxy)
#plt background
ax = gdf.plot(figsize=(6,6), alpha =0.5, facecolor="None")
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0,
hspace = 0, wspace = 0)
ax.margins(0,0)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.axis('off')
#North arrow
x, y, arrow_length = 0.85, 0.10, 0.07
ax.annotate('N', xy=(x, y), xytext=(x, y-arrow_length),
arrowprops=dict(facecolor='black', width=5, headwidth=15),
ha='center', va='center', fontsize=20,
xycoords=ax.transAxes)
#Use contextily to create the basemap
cx.add_basemap(ax, crs=gdf.crs.to_string())
#Saves map
plt.savefig("image name.png", dpi=300, bbox_inches='tight', format="png", transparent=False,pad_inches = 0)
plt.close()
#Read the map
plotmap = r"image name above^^"
truthplot = plt.imread(plotmap)
#Create subplot over the map
fig, ax = plt.subplots(figsize = (6,6),linewidth = 0.1, frameon=False)
plottitle = "plot title"
ax.set_title(plottitle)
ax.set_xlabel("Longitude")
ax.set_ylabel("Latitude")
fig.tight_layout()
def animate(i):
Time.remove(Time[0])
Speed.remove(Speed[0])
scat = ax.scatter(Longs[i], Lats[i], zorder=1, alpha= 0.5, c='r', s=7)
annotation = AnchoredText(s=("Time: " + str(Time[0]) + "\n" + "Speed: " + str(Speed[0])),
prop=dict(size=8), frameon=True, loc='upper left')
annotation.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
ax.add_artist(annotation)
ax.imshow(truthplot, extent=(minx, maxx, miny, maxy), aspect='auto')
return [annotation],[scat],[Longs],[Lats]
#make the animation
ani = FuncAnimation(fig, animate,frames = savecount, interval=20, repeat = False)
ani.save(f, fps=15,writer='ffmpeg'
)
Everything else works except saving it takes WAY longer than it should, I think.
Thank you for any help!
I have put together this piece of code that asks for an input in one Tkinter entry. I want the 3rd entry to be the graph, but I can't seem to get the graph to be put into window, rather than it's own.
Ignoring what goes into the first 2 rows of the Tkinter grid, I don't know where to go from here. I'm assuming I need to use some canvas which is why it's been imported but I don't know if I can reproduce this graph in that way.
#Import matplotlib modules
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
#Put image under graph
img = plt.imread("graph.png")
fig, ax1 = plt.subplots()
ax1.imshow(img, extent=[-10,10,-10,10], aspect='equal')
#Set graph ranges
plt.ylim(-10, 10)
plt.xlim(-10, 10)
#Set axis & labels
ax1.set_xlabel('NEGATIVE')
ax1.set_ylabel('HAPPY')
ax2 = ax1.secondary_xaxis('top')
ax2.set_xlabel('POSITIVE')
ax3 = ax1.secondary_yaxis('right')
ax3.set_ylabel('SAD', rotation=270, labelpad=12.5)
#Remove ticks/values
for ax in (ax1, ax2, ax3):
ax.tick_params(left=False, labelleft=False, top=False, labeltop=False,
right=False, labelright=False, bottom=False, labelbottom=False)
#Calculate score
##TESTING##
import random
posNeg=0
hapSad=0
posNeg = random.randint(-12, 12)
hapSad = random.randint(-12, 12)
if posNeg < (-10):
posNeg = (-10)
if posNeg > 10:
posNeg = 10
if hapSad < (-10):
hapSad = (-10)
if hapSad > 10:
hapSad = 10
##TESTING##
#Plot point on graph
plt.plot([posNeg], [hapSad], marker = 'o', markersize = 15, color = 'red')
from tkinter import *
#testing input function
def print_input():
user_input = entry_1.get()
label_2["text"] = user_input
#window
window = Tk()
label_1 = Label(window, text = "What's your Twitter handle?")
entry_1 = Entry(window)
button_1 = Button(window, text = "go", command = print_input)
label_2 = Label(window)
label_1.grid(row = 0, column = 0)
entry_1.grid(row = 0, column = 1)
button_1.grid(row = 0, column = 2)
label_2.grid(row = 1, column = 0)
graph_1 = plt.show()
graph_1.grid(row = 3, column = 0)
window.mainloop()
#\window
You need to embed the graph using FigureCanvasTkAgg. It is a canvas on which matplotlib graphs can be drawn.
You have imported it, but have not used it. To display it, do the following:
graph_1 = FigureCanvasTkAgg(fig, master=window)
graph_1.get_tk_widget().grid(row = 3, column = 0)
graph_1.draw()
I am trying to move a dot to a particular location on the graph dynamically based on real-time data. I'm basically plotting the graph, emitting a signal from a worker thread which calls the 'move_dot' function. It works, however it is slow. I can only call one frame per second. I'm using the MPL widget in pythonxy. I am also using Windows. Is there a way to speed this up?
Here is the code:
from PyQt4 import QtGui
import ui_sof_test #Gui File
import sys
from matplotlib.ticker import AutoMinorLocator
class Gui(QtGui.QMainWindow, ui_sof_test.Ui_MainWindow):
def __init__(self):
super(self.__class__, self).__init__()
self.setupUi(self) # This is defined in ui_pumptest.py file automatically
self.mpl_plot(0)
self.move_dot()
cursorplot = 0
def move_dot(self, x = 100, y = 5, color = 'r'):
fig = self.mplwidget_3.figure
par = fig.add_subplot(111)
ax3 = par.twinx()
plty = fig.gca()
plty.yaxis.set_visible(False)
ax3.plot(x, y, color, marker = 'o', linewidth = 1)
fig.canvas.draw()
#ax3.cla()
def mpl_plot(self, plot_page, replot = 0): #Data stored in lists
fig = self.mplwidget_3.figure #Add a figure
#Clears Figure if data is replotted
if replot == 1:
fig.clf()
plty = fig.gca()
plty.yaxis.set_visible(False)
par0 = fig.add_subplot(111)
#Add Axes
plt = par0.twinx()
#Plot Chart
plt.hold(False)
plt.plot([0,100,200,300,400,500], [1,3,2,4,7,5], 'b', linestyle = "dashed", linewidth = 1)
#Plot Factory Power
minorLocatorx = AutoMinorLocator()
plt.xaxis.set_minor_locator(minorLocatorx)
plt.tick_params(which='both', width= 0.5)
plt.tick_params(which='major', length=7)
plt.tick_params(which='minor', length=4, color='k')
#Plot y axis minor tick marks
minorLocatory = AutoMinorLocator()
plt.yaxis.set_minor_locator(minorLocatory)
plt.tick_params(which='both', width= 0.5)
plt.tick_params(which='major', length=7)
plt.tick_params(which='minor', length=4, color='k')
plt.minorticks_on()
#Make Border of Chart White
fig.set_facecolor('white')
#Plot Grid
plt.grid(b=True, which='both', color='k', linestyle='-')
#Manually make vertical gridlines. Above line doesn't make vertical lines for some reason
for xmaj in plt.xaxis.get_majorticklocs():
plt.axvline(x=xmaj, color = 'k',ls='-')
for xmin in plt.xaxis.get_minorticklocs():
plt.axvline(x=xmin, color = 'k', ls='-')
#Set Scales
plt.yaxis.tick_left()
# Set Axes Colors
plt.tick_params(axis='y', colors='b')
# Set Chart Labels
plt.yaxis.set_label_position("left")
plt.set_xlabel(" ")
plt.set_ylabel(" " , color = 'b')
fig.canvas.draw()
self.move_dot()
def main():
app = QtGui.QApplication(sys.argv) # A new instance of QApplication
form = Gui() # We set the form to be our ExampleApp (design)
form.show() # Show the form
app.exec_() # and execute the. app
if __name__ == '__main__': # if we're running file directly and not importing it
main() # run the main function
I am new to programming and was wondering if I could get some expert assistance from the very helpful community on here.
I am trying to create a mouse click event upon which the entire area of the plot to the right of the mouse click gets shaded. So, I want the mouse click to register the x-value, create a vertical line over that x-value, and shade the entire plot to the right of the vertical line.
I have 5 subplots showing distributions. I would like this mouse click event to trigger only on the 4th (PDF plot) and 5th (CDF plot) subplot. The purpose of this is to set margins and analyze the distributions.
See pic below
I managed to write a code to perform this action but it is not updating (shading the area) the plot upon mouse click. Here's my code
import numpy as np
from scipy.stats import norm, lognorm, uniform
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons, CheckButtons
from matplotlib.patches import Polygon
#####Mean and standard deviation#####
mu_a1 = 1
mu_b1 = 10
mu_c1 = -13
sigma_a1 = 0.14
sigma_b1 = 1.16
sigma_c1 = 2.87
mu_x01 = -11
sigma_x01 = 1.9
#####_____#####
#####Generating random data#####
a1 = 0.75*mu_a1 + (1.25 - 0.75)*sigma_a1*np.random.sample(10000)
b1 = 8*mu_b1 + (12 - 8)*sigma_b1*np.random.sample(10000)
c1 = -12*mu_c1 + 2*sigma_c1*np.random.sample(10000)
x01 = (-b1 - np.sqrt(b1**2 - (4*a1*c1)))/(2*a1)
#####_____#####
#####Creating Subplots#####
fig = plt.figure()
plt.subplots_adjust(left=0.13,right=0.99,bottom=0.05)
ax1 = fig.add_subplot(331) #Subplot 1
ax1.set_xlabel('a' , fontsize = 14)
ax1.grid(True)
ax2 = fig.add_subplot(334) #Subplot 2
ax2.set_xlabel('b', fontsize = 14)
ax2.grid(True)
ax3 = fig.add_subplot(337) #Subplot 3
ax3.set_xlabel('c', fontsize = 14)
ax3.grid(True)
ax4 = fig.add_subplot(132) #Subplot 4
ax4.set_xlabel('x0', fontsize = 14)
ax4.set_ylabel('PDF', fontsize = 14)
ax4.grid(True)
ax5 = fig.add_subplot(133) #Subplot 5
ax5.set_xlabel('x0', fontsize = 14)
ax5.set_ylabel('CDF', fontsize = 14)
ax5.grid(True)
#####_____#####
#####Plotting Distributions#####
[n1,bins1,patches] = ax1.hist(a1, bins=50, color = 'red',alpha = 0.5, normed = True)
[n2,bins2,patches] = ax2.hist(b1, bins=50, color = 'red',alpha = 0.5, normed = True)
[n3,bins3,patches] = ax3.hist(c1, bins=50, color = 'red',alpha = 0.5, normed = True)
[n4,bins4,patches] = ax4.hist(x01, bins=50, color = 'red',alpha = 0.5, normed = True)
ax4.axvline(np.mean(x01), color = 'black', linestyle = 'dashed', lw = 2)
dx = bins4[1] - bins4[0]
CDF = np.cumsum(n4)*dx
ax5.plot(bins4[1:], CDF, color = 'red')
#####_____#####
#####Event handler for button_press_event#####
def onclick(event):
'''
Event handler for button_press_event
#param event MouseEvent
'''
global ix
ix = event.xdata
if ix is not None:
print 'x = %f' %(ix)
ax4.clear()
ax5.clear()
ax4.grid(True)
ax5.grid(True)
[n4,bins4,patches] = ax4.hist(x01, bins=50, color = 'red',alpha = 0.5, normed = True)
ax4.axvline(np.mean(x01), color = 'black', linestyle = 'dashed', lw = 2)
ax4.axvspan(ix, -90, facecolor='0.9', alpha=0.5)
dx = bins4[1] - bins4[0]
CDF = np.cumsum(n4)*dx
ax5.plot(bins4[1:], CDF, color = 'red')
ax5.axvspan(ix, -75, facecolor='0.9', alpha=0.5)
return ix
cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
#####_____#####
Also, since I am using axvspan, it asks me to input xmin and xmax value. The xmin = mouse_click_value, and the xmax, I would like it to be till the end of the plot, what ever the end value may be. Currently, I am using a fixed value (-90 or -75 from the pic). This doesn't seem to work as the value of the variables change.
For your main question:
Just add:
plt.draw()
after all the updates you do (i.e before the return of onClick).
For your seconed question:
You can use (on ax5 for example):
ax5.get_xlim()[1]
to get the xmax of ax5
I'm working with the following class:
import numpy as np
import matplotlib
matplotlib.use('Qt4Agg')
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
class matplotLIV():
def __init__(self, BaseFilename, temperatures, length=None, width=None, area=None, title = '', ylim=None):
self.BaseFilename = BaseFilename
self.temperatures = temperatures
if length and width:
self.length = length
self.width = width
self.area = length*width*1e-5
else:
self.area = area
self.title = title
self.ylim = ylim
filenames = [("%s_%sK.txt" % (self.BaseFilename, str(temp)), temp) for temp in self.temperatures]
self.rawData = [(np.loadtxt(fname), temp) for fname, temp in filenames]
self.colors = colors = ['#1b9e77', '#d95f02', '#7570b3', '#e7298a', '#e6ab02', '#a6761d', '#666666']
self.maxValueRow = (0,0,0)
def plot(self):
self.fig = plt.figure()
self.ax1 = self.fig.add_subplot(111)
ax1 = self.ax1
ax1.tick_params(bottom='off')
ax1.xaxis.tick_top()
self.ax2 = ax1.twinx()
ax2 = self.ax2
self.ax3 = ax2.twiny()
ax3 = self.ax3
ax3.xaxis.tick_bottom()
ax1.set_xlabel("current / A")
ax1.xaxis.set_label_position('top')
ax1.set_ylabel("voltage / V")
ax2.set_ylabel("light intensity / arb. u.")
ax3.set_xlabel(r'current density / $\mathregular{Acm^{-2}}$')
ax3.xaxis.set_label_position('bottom')
for i, (datafile, label) in enumerate(self.rawData):
self.checkMaxValues(datafile)
ax1.plot( datafile[:,0], datafile[:,1], color=self.colors[i], label='%sK' % str(label))
ax2.plot( datafile[:,0], datafile[:,2], color=self.colors[i], label='%sK' % str(label), linewidth=2)
ax1.margins(x=0)
ax1.grid(True, axis='y')
ax3.grid(True)
start, end = ax1.get_xlim()
self.setAxesScale(ax1, ax2)
if self.ylim:
ax2.set_ylim(top=self.ylim)
ax3.set_xlim(start/self.area, end/self.area)
leg = ax2.legend(loc='upper left')
self.fig.suptitle(self.title, y=0.98, weight='bold')
self.fig.subplots_adjust(top=0.86)
loc = plticker.MultipleLocator(base=20.0) # this locator puts ticks at regular intervals
ax3.xaxis.set_major_locator(loc)
def checkMaxValues(self, data):
maxInd = data.argmax(axis=0)[2]
if data[maxInd][2] > self.maxValueRow[2]:
self.maxValueRow = data[maxInd]
def setAxesScale(self, ax1, ax2):
yrange = ax1.get_ylim()
y1Fraction = self.maxValueRow[1]/yrange[1]
y2Fraction = y1Fraction - 0.02
ax2.set_ylim(top=self.maxValueRow[2]/y2Fraction)
def show(self):
plt.savefig(self.BaseFilename + '.pdf')
plt.show()
which you can run with this sample code:
import matplotLIV as mpliv
######## configuration
BaseFilename = "testdata"
temperatures = (5,)
area = 1e-8
######## end of configuration
liv = mpliv.matplotLIV(BaseFilename, temperatures, area=area)
liv.plot()
liv.show()
on this file: http://pastebin.com/GMAC3mUu
The problem that I'm experiencing is that the legend is transparent to the grid. Oddly enough, it is only the vertical grid that you can see through the legend box:
Is this a bug? If not, how do I set the legend so it is NOT transparent?
The problem is the vertical grid is on ax3, and the legend is on ax2, so the grid is plotted after the legend.
One way around this is pasted below (just the section you need to modify). You need to plot the legend on ax3, and explicitly tell it which lines and labels you want.
# make a list for the lines that you are plotting
l1 = []
l2 = []
for i, (datafile, label) in enumerate(self.rawData):
self.checkMaxValues(datafile)
# Give your lines some names (l1,l2)
l1+=ax1.plot( datafile[:,0], datafile[:,1], color=self.colors[i], label='%sK' % str(label))
l2+=ax2.plot( datafile[:,0], datafile[:,2], color=self.colors[i], label='%sK' % str(label), linewidth=2)
# Define which lines to put in the legend. If you want l1 too, then use lns = l1+l2
lns = l2
labs = [l.get_label() for l in lns]
ax1.margins(x=0)
ax1.grid(True, axis='y')
ax3.grid(True)
start, end = ax1.get_xlim()
self.setAxesScale(ax1, ax2)
if self.ylim:
ax2.set_ylim(top=self.ylim)
ax3.set_xlim(start/self.area, end/self.area)
# Set the legend on ax3, not ax2
leg = ax3.legend(lns,labs,loc='upper left')