我正在尝试在Tkinter画布小部件中嵌入股票价格图表。我有一个用matplotlib编写的功能齐全的股票价格图表。在尝试将我的图形嵌入Tkinter时,我发现(已被告知)作为绘图编写的matplotlib图形无法在Tkinter中正确嵌入,并且图形必须采用图形的形式才能使嵌入正常工作。为了便于说明,这里是一个绘图形式的matplotlib样本图。
def schart20(stock_sym):
x = [1,2,3,4]
y = [20,21,20.5, 20.8]
plt.plot(x,y)
plt.show()
这是相同的图,但是以图的形式。
def schart21(stock_sym):
x = [1,2,3,4]
y = [20,21,20.5, 20.8]
fig = Figure()
axes = fig.add_subplot(111)
axes.plot(x,y)
return fig
schart21代码可以成功嵌入到Tkinter中,但schart20代码不能。我的股票价格图表代码是一个情节的形式,我需要将其转换为数字的形式。我对matplotlib的经验很少,我不确定如何根据需要修改我的代码。这是我的股票价格图表代码。此代码功能齐全,但需要访问基础文件才能工作。
def graphData(stock, MA1, MA2):
try:
stockFile = '/Users/BioASys/BioasysDB/CompanyStockPriceData/'+stock+'.txt'
date, closep, highp, lowp, openp,volume=np.loadtxt(stockFile,delimiter=',',unpack=True,
converters={ 0: mdates.strpdate2num('%Y%m%d')})
x = 0
y = len(date)
candleAr = []
while x < y:
appendLine = date[x], openp[x], closep[x], highp[x], lowp[x], volume[x]
candleAr.append(appendLine)
x+=1
Av1 = movingaverage(closep, MA1)
Av2 = movingaverage(closep, MA2)
SP = len(date[MA2-1:])
label1 = str(MA1) + ' SMA'
label2 = str(MA2) + ' SMA'
fig = plt.figure()
ax1 = plt.subplot2grid((5,4),(0,0), rowspan=4, colspan=4)
candlestick(ax1, candleAr[-SP:], width=0.6, colorup='g', colordown='r')
ax1.plot(date[-SP:],Av1[-SP:],'#5998ff', label=label1, linewidth=1.5)
ax1.plot(date[-SP:],Av2[-SP:],'blue', label=label2, linewidth=1.5)
plt.ylabel('Stock price')
ax1.grid(True)
plt.legend(loc=3,prop={'size':7},fancybox=True,)
ax2 = plt.subplot2grid((5,4), (4,0), sharex=ax1, rowspan=1, colspan=4)
#ax2 = plt.subplot2grid((5,4), (4,0), rowspan=1, colspan=4)
ax2.bar(date, volume)
ax2.axes.yaxis.set_ticklabels([])
plt.ylabel('Volume')
ax2.grid(True)
ax1.xaxis.set_major_locator(mticker.MaxNLocator(10))
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
for label in ax1.xaxis.get_ticklabels():
label.set_rotation(90)
for label in ax2.xaxis.get_ticklabels():
label.set_rotation(45)
plt.xlabel('Date')
#plt.ylabel('Stock Price')
plt.suptitle(stock+' Stock Price')
plt.setp(ax1.get_xticklabels(), visible=False)
plt.subplots_adjust(left=.09, bottom=.18, right=.94, top=.94, wspace=.20, hspace=0)
plt.show()
#fig.savefig('example.png') # saves a copy of the sticok chart to example.png
except Exception, e:
print 'failed main loop',str(e)
如果有人知道如何将这个从情节转换为数字我会很感激帮助。真诚的,乔治
答案 0 :(得分:2)
要了解Matplotlib最重要的事情之一是它以三种模式之一运行(缺少更好的词)。 1)它根深蒂固在 pylab ,2)它有一个 pyplot 接口,3)它有它的底层对象接口。我会尝试解开它们,如果有人比我更熟悉我看到下面的内容有什么问题,请告诉我,我会解决它!
第一个应该在几乎所有时间都应该被避免 - 它也会出现numpy和scipy,并且永远不会用于编写脚本或编码。第二个(或应该)主要用于交互式绘图,旨在模仿Matlab的功能。到目前为止,最后一个是编码最强大的,对于你想要的嵌入类型是必不可少的。
你的代码目前正在使用后两者的混搭,这实际上可能会导致问题 - pyplot在幕后做的比做绘图更多。 Matplotlib本质上是面向对象的,为了方便起见,pyplot只是一个巨大的包装器,可以帮助Matlab用户过渡。它使用默认后端进行显示(在我的情况下,大多数情况下它使用Qt4Agg),而你实际上想要强制它使用TkAgg,因此Tkinter知道如何处理它。如果你不小心,Pyplot会干扰它。
你应该保留的唯一一个pyplot调用是数字创建fig = plt.figure()
和你的subplot2grid
调用。实际上,如果直接导入Figure对象(from matplotlib.figure import Figure
),也可以修改数字调用。获得轴后,放弃pyplot并直接使用对象方法(即ax.plot()
)。在线阅读documentation以了解如何使用它们,它们的通话要求有时会有所不同!
Tkinter嵌入使用了一个FigureCanvasTkAgg对象,它需要一个Figure对象。因此,您的绘图函数必须返回该Figure对象,以便可以使用它来构造FigureCanvasTkAgg。您也不需要任何plt.show()
- 所有这一切都会弹出当前的 pyplot 数字,您实际上并不想要,因为您的数字嵌入在GUI中
因此,手头问题的答案与以前相同 - 尽可能多地消除plt.
个命令,return fig
。然后在GUI代码中你可以做
fig = graphData(stock, MA1, MA2)
canvas = FigureCanvasTkAgg(fig)
这是一个最小的例子,它运行时没有以类似于你的方式构造错误,而根本没有使用pyplot。
import Tkinter as Tk
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
def myplotcode():
x = np.linspace(0,2*np.pi)
fig = Figure()
ax = fig.add_subplot(111)
ax.plot(x, x**2)
return fig
class mygui(Tk.Frame):
def __init__(self, parent):
Tk.Frame.__init__(self, parent)
self.parent = parent
self.fig = myplotcode()
self.canvas = FigureCanvasTkAgg(self.fig, master=parent)
self.canvas.show()
self.canvas.get_tk_widget().pack()
self.pack(fill=Tk.BOTH, expand=1)
root = Tk.Tk()
app = mygui(root)
root.mainloop()