Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
250 views
in Technique[技术] by (71.8m points)

python - While switching between two different tkinter embedded matplotlib candlestick charts data does not appear

This is a follow up to the question posted at How do I use a button to switch between two different graphs in matplotlib
Many thanks to endyd for that solution.

The code at that url works perfectly if the graphs being switched between are typical matplotlib graphs but I am attempting to use a button to switch between two graphs where one is a candlestick chart without a volume overlay and the second is the same candlestick chart but with a volume overlay. Unfortunately I have been unable to get this code to display the candlestick data or the volume data using the code from the shown url.

The matplotlib code for the candlestick code is from mpl_finance and is located at https://github.com/matplotlib/mpl_finance/blob/master/mpl_finance.py

Here is my complete code that embeds the two candlestick charts (without and with the volume overlay) into a tkinter widget and which allows the use of a button to switch between the two graphs per the code from my initial question:

import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from tkinter import *
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.backend_bases import key_press_handler
from SQL_code import connectToSQL
from matplotlib.dates import date2num, num2date
from matplotlib.dates import DateFormatter, WeekdayLocator, 
DayLocator, MONDAY
from mpl_finance import candlestick_ohlc
from datetime import datetime

# Separated out config of plot to just do it once
def config_plot():
    fig, ax = plt.subplots(figsize=(18, 5))
    #ax.set(xlabel='time (s)', ylabel='voltage (mV)', title='Graph 
One')
    return (fig, ax)

class matplotlibStock:
    def __init__(self, master):
        self.master = master
        self.frame = Frame(self.master)
        self.fig, self.ax = config_plot()
        self.graphIndex = 0
        self.canvas = FigureCanvasTkAgg(self.fig, self.master)
        self.config_window()
        self.ohlc_daily_date_axis()
        self.frame.pack(expand=YES, fill=BOTH)

    def quotes_info(self):
        quotes = [(737042.0, 2.72, 2.78, 2.6815, 2.74, 414378.0),
                  (737045.0, 2.71, 2.77, 2.57, 2.63, 578841.0),
                  (737046.0, 2.64, 2.64, 2.4228, 2.47, 1451450.0),
                  (737047.0, 2.9, 3.15, 2.7, 2.96, 7230260.0),
                  (737048.0, 2.92, 3.29, 2.67, 2.83, 2784110.0),
                  (737049.0, 2.78, 2.82, 2.4701, 2.51, 822776.0),
                  (737052.0, 2.56, 2.6344, 2.49, 2.5, 278883.0),
                  (737054.0, 2.5, 2.619, 2.34, 2.6, 606002.0),
                  (737055.0, 2.57, 2.63, 2.45, 2.57, 1295820.0),
                  (737056.0, 2.57, 2.75, 2.51, 2.65, 435838.0)]

        return quotes

    def config_window(self):
        self.canvas.mpl_connect("key_press_event", self.on_key_press)
        toolbar = NavigationToolbar2Tk(self.canvas, self.master)
        toolbar.update()
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, 
expand=1)
        self.button = Button(self.master, text="Quit", 
command=self._quit)
        self.button.pack(side=BOTTOM)
        self.button_switch = Button(self.master, text="Switch Graphs", 
command=self.switch_graphs)
        self.button_switch.pack(side=BOTTOM)

    def ohlc_daily_date_axis(self):
        quotes = self.quotes_info()
        mondays = WeekdayLocator(MONDAY)  # major ticks on the mondays
        alldays = DayLocator()  # minor ticks on the days
        weekFormatter = DateFormatter('%b %d %Y')  # e.g., Jan 12 2018
        dayFormatter = DateFormatter('%d')  # e.g., 12



        #self.fig, self.ax = plt.subplots(figsize=(18, 5))
        self.ax.clear()  # clear current axes
        plt.subplots_adjust(bottom=0.2)
        self.ax.xaxis.set_major_locator(mondays)
        self.ax.xaxis.set_minor_locator(alldays)
        self.ax.xaxis.set_major_formatter(weekFormatter)
        # ax.xaxis.set_minor_formatter(dayFormatter)
        plt.title('Graph One')
        self.ax.set_ylabel('Share Price ($)', size=10)

        # plot_day_summary(ax, quotes, ticksize=3)
        candlestick_ohlc(self.ax, quotes, width=0.6)

        self.ax.xaxis_date()
        self.ax.autoscale_view()
        plt.setp(plt.gca().get_xticklabels(), rotation=45, 
horizontalalignment='right')

        #plt.show()
        self.canvas.draw()

    def ohlc_daily_date_axis_w_vol(self):
        mondays = WeekdayLocator(MONDAY)  # major ticks on the mondays
        alldays = DayLocator()  # minor ticks on the days
        weekFormatter = DateFormatter('%b %d %Y')  # e.g., Jan 12 2018
        dayFormatter = DateFormatter('%d')  # e.g., 12

        quotes = self.quotes_info()
        dates_pos = []
        dates_neg = []
        vols_pos = []
        vols_neg = []
        for i in range(len(quotes)):
            if quotes[i][1] - quotes[i][4] <= 0:
                dates_pos.append(quotes[i][0])
                vols_pos.append(quotes[i][5])
            if quotes[i][1] - quotes[i][4] > 0:
                dates_neg.append(quotes[i][0])
                vols_neg.append(quotes[i][5])


        self.ax.clear()  # clear current axes
        self.fig = plt.figure(figsize=(18, 5))
        self.ax = plt.subplot2grid((5, 4), (0, 0), rowspan=4, 
colspan=4)
        plt.subplots_adjust(bottom=0.2)
        self.ax.xaxis.set_major_locator(mondays)
        self.ax.xaxis.set_minor_locator(alldays)
        self.ax.xaxis.set_major_formatter(weekFormatter)
        # ax.xaxis.set_minor_formatter(dayFormatter)
        self.ax.set_ylabel('Share Price ($)', size=10)
        plt.title("Graph Two")

        # begin volume code
        self.ax2 = plt.subplot2grid((5, 4), (4, 0), sharex=self.ax, 
rowspan=1, colspan=4)

        self.ax2.bar(dates_pos, vols_pos, color='green', width=1, 
align='center')
        self.ax2.bar(dates_neg, vols_neg, color='red', width=1, 
align='center')
        labels = [int(l) for l in self.ax2.get_yticks()]
        self.ax2.axes.yaxis.set_ticklabels(labels)

        yticks = self.ax2.get_yticks()
        self.ax2.yaxis.tick_right()
        self.ax2.set_yticks(yticks)

        self.ax2.yaxis.set_label_position("right")
        self.ax2.set_ylabel('Volume', size=10)

        candlestick_ohlc(self.ax, quotes, width=0.6)

        self.ax.xaxis_date()
        self.ax.autoscale_view()
        plt.setp(plt.gca().get_xticklabels(), rotation=45, 
horizontalalignment='right')

        # these next 2 lines are vol lines
        plt.setp(self.ax.get_xticklabels(), visible=False)
        plt.subplots_adjust(hspace=0)

        #plt.show()
        self.canvas.draw()


    def on_key_press(event):
        print("you pressed {}".format(event.key))
        key_press_handler(event, canvas, toolbar)

    def _quit(self):
        self.master.quit()  # stops mainloop

    def switch_graphs(self):
        # Need to call the correct draw, whether we're on graph one or 
two
        self.graphIndex = (self.graphIndex + 1 ) % 2
        if self.graphIndex == 0:
            self.ohlc_daily_date_axis()
        else:
            self.ohlc_daily_date_axis_w_vol()



def main():
    root = Tk()
    matplotlibStock(root)
    root.mainloop()

if __name__ == '__main__':
    main()

I am encountering two problems in using this code with my candlestick charts. The first is that the data does not display and I believe this is somehow related to the

self.canvas.draw()

command. The second problem is that my candlestick chart with the volume overlay has two sets of axis, one for the candlestick OHLC data and the second for the volume data, which does not seem workable using the config_plot def. Any advice on resolving these issues is greatly appreciated.

The following is code that shows just how the candlestick chart with the volume overlay looks. This code uses two axes, one for the candlestick chart and the second for the volume overlay and then combines them into one figure.

For general information purposes an OHLC candlestick chart shows stock prices where for every date the open (O), high (H), low (L) and close (C) are all plotted. The volume overlay is a separate graph below the candlestick chart that plots the number of shares (volume) traded for that date. It is typical when viewing stock charts that a candlestick chart is used to view the changes in a stocks price on a day to day basis where the stocks volume can be made visible or not visible.

import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter, WeekdayLocator, 
DayLocator, MONDAY
from mpl_finance import candlestick_ohlc




def quotes_info():
    return [(737042.0, 2.72, 2.78, 2.6815, 2.74, 414378.0),
            (737045.0, 2.71, 2.77, 2.57, 2.63, 578841.0),
            (737046.0, 2.64, 2.64, 2.4228, 2.47, 1451450.0),
            (737047.0, 2.9, 3.15, 2.7, 2.96, 7230260.0),
            (737048.0, 2.92, 3.29, 2.67, 2.83, 2784110.0),
            (737049.0, 2.78, 2.82, 2.4701, 2.51, 822776.0),
            (737052.0, 2.56, 2.6344, 2.49, 2.5, 278883.0),
            (737054.0, 2.5, 2.619, 2.34, 2.6, 606002.0),
            (737055.0, 2.57, 2.63, 2.45, 2.57, 1295820.0),
            (737056.0, 2.57, 2.75, 2.51, 2.65, 435838.0)]





def ohlc_daily_date_axis_w_vol():
    mondays = WeekdayLocator(MONDAY)        
    alldays = DayLocator()              
    weekFormatter = DateFormatter('%b %d %Y')  
    dayFormatter = DateFormatter('%d')      

    quotes = quotes_info()
    dates_pos = []
    dates_neg = []
    vols_pos = []
    vols_neg = []
    for i in range(len(quotes)):
        if quotes[i][1] - quotes[i][4] <= 0:
            dates_pos.append(quotes[i][0])
            vols_pos.append(quotes[i][5])
        if quotes[i][1] - quotes[i][4] > 0:
            dates_neg.append(quotes[i][0])
            vols_neg.append(quotes[i][5])



    fig = plt.figure(figsize=(18,5))
    ax = plt.subplot2grid((5, 4), (0, 0), rowspan=4, colspan=4)
    plt.subplots_adjust(bottom=0.2)
    ax.xaxis.set_major_locator(mondays)
    ax.xaxis.set_minor_locator(alldays)
    ax.xaxis.set_major_formatter(weekFormatter)
    ax.set_ylabel('Share Price ($)', size=10)


    # begin volume code
    ax2 = plt.subplot2grid((5, 4), (4, 0), sharex=ax, rowspan=1, 
colspan=4)

    #ax2.bar(dates, vols)
    ax2.bar(dates_pos, vols_pos, color='green', width=1, 
align='center')
    ax2.bar(dates_neg, vols_neg, color='red', width=1, align='center')
    labels = [int(l) for l in ax2.get_yticks()]
    ax2.axes.yaxis.set_ticklabels(labels)

    yticks = ax2.get_yticks()
    ax2.yaxis.tick_right()
    ax2.set_yticks(yticks)

    ax2.yaxis.set_label_position("right")
    ax2.set_ylabel('Volume', size=10)

    candlestick_ohlc(ax, quotes, width=0.6)

    ax.xaxis_date()
    ax.autoscale_view()
    plt.setp(plt.gca().get_xticklabels(), rotation=45, 
horizontalalignment='right')

    # these next 2 lines are vol lines
    plt.setp(ax.get_xticklabels(), visible=False)
    plt.subplots_adjust(hspace=0)



    plt.show()




if __name__ == '__main__':
    ohlc_daily_date_axis_w_vol()

Image of graph two - candlestick chart with volume overlay

See

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Alright, I followed you here. I'm not sure if this is your desired effect, so I'm attaching the picture to see what you say. Don't know what any of the data means (or what volume overlay means) so please check the image below and let me know... Basically I moved more things into the config_window() method and tried to see if we can do things without creating another axes in self.ax2. Maybe that messes up your graph with volume overlay totally...

import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from tkinter import *
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.backend_bases import key_press_handler
# from SQL_code import connectToSQL
from matplotlib.dates import date2num, num2date
from matplotlib.dates import DateFormatter, WeekdayLocator, DayLocator, MONDAY
from mpl_finance import candlestick_ohlc
from datetime import datetime

# Separated out config of plot to just do it once
def config_plot():
    fig, ax = plt.subplots(figsize=(18, 5))
    #ax.set(xlabel='time (s)', ylabel='voltage (mV)', title='Graph One')
    return (fig, ax)

class matplotlibStock:
    def __init__(self, master):
        self.master = master
        self.frame = Frame(self.master)
        self.fig, self.ax = config_plot()
        self.graphIndex = 0
        self.canvas = FigureCanvasTkAgg(self.fig, self.master)
        self.config_window()
        self.ohlc_daily_date_axis()
        self.frame.pack(expand=YES, fill=BOTH)

    def quotes_info(self):
        return [(737042.0, 2.72, 2.78, 2.6815, 2.74, 414378.0),
                  (737045.0, 2.71, 2.77, 2.57, 2.63, 578841.0),
                  (737046.0, 2.64, 2.64, 2.4228, 2.47, 1451450.0),
                  (737047.0, 2.9, 3.15, 2.7, 2.96, 7230260.0),
                  (737048.0, 2.92, 3.29, 2.67, 2.83, 2784110.0),
                  (737049.0, 2.78, 2.82, 2.4701, 2.51, 822776.0),
                  (737052.0, 2.56, 2.6344, 2.49, 2.5, 278883.0),
                  (737054.0, 2.5, 2.619, 2.34, 2.6, 606002.0),
                  (737055.0, 2.57, 2.63, 2.45, 2.57, 1295820.0),
                  (737056.0, 2.57, 2.75, 2.51, 2.65, 435838.0)]

    def config_window(self):
        self.canvas.mpl_connect("key_press_event", self.on_key_press)
        toolbar = NavigationToolbar2Tk(self.canvas, self.master)
        toolbar.update()
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
        self.button = Button(self.master, text="Quit", command=self._quit)
        self.button.pack(side=BOTTOM)
        self.button_switch = Button(self.master, text="Switch Graphs", command=self.switch_graphs)
        self.button_switch.pack(side=BOTTOM)
        plt.subplots_adjust(bottom=0.2)

        # Moved to config
        mondays = WeekdayLocator(MONDAY)  # major ticks on the mondays
        alldays = DayLocator()  # minor ticks on the days
        weekFormatter = DateFormatter('%b %d %Y')  # e.g., Jan 12 2018
        dayFormatter = DateFormatter('%d')  # e.g., 12
        self.ax.xaxis.set_major_locator(mondays)
        self.ax.xaxis.set_minor_locator(alldays)
        self.ax.xaxis.set_major_formatter(weekFormatter)
        # ax.xaxis.set_minor_formatter(dayFormatter)
        self.ax.set_ylabel('Share Price ($)', size=10)


    def ohlc_daily_date_axis(self):
        plt.title('Without Volume Overlay')
        quotes = self.quotes_info()

        #self.fig, self.ax = plt.subplots(figsize=(18, 5))
        self.ax.clear()  # clear current axes

        # plot_day_summary(ax, quotes, ticksize=3)
        candlestick_ohlc(self.ax, quotes, width=0.6)
        self.ax.xaxis_date()
        self.ax.autoscale_view()
        plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')

        #plt.show()
        self.canvas.draw()

    def ohlc_daily_date_axis_w_vol(self):
        plt.title('With Volume Overlay')
        quotes = self.quotes_info()

        dates_pos = []
        dates_neg = []
        vols_pos = []
        vols_neg = []
        for i in range(len(quotes)):
            if quotes[i][1] - quotes[i][4] <= 0:
                dates_pos.append(quotes[i][0])
                vols_pos.append(quotes[i][5])
            if quotes[i][1] - quotes[i][4] > 0:
                dates_neg.append(quotes[i][0])
                vols_neg.append(quotes[i][5])


        self.ax.clear()  # clear current axes
        # self.fig = plt.figure(figsize=(18, 5))
        # self.ax = plt.subplot2grid((5, 4), (0, 0), rowspan=4, colspan=4)

        # begin volume code
        # self.ax2 = plt.subplot2grid((5, 4), (4, 0), sharex=self.ax, rowspan=1, colspan=4)

        self.ax.bar(dates_pos, vols_pos, color='green', width=1, align='center')
        self.ax.bar(dates_neg, vols_neg, color='red', width=1, align='center')
        labels = [int(l) for l in self.ax.get_yticks()]
        self.ax.axes.yaxis.set_ticklabels(labels)

        yticks = self.ax.get_yticks()
        self.ax.yaxis.tick_right()
        self.ax.set_yticks(yticks)

        self.ax.yaxis.set_label_position("right")
        self.ax.set_ylabel('Volume', size=10)

        candlestick_ohlc(self.ax, quotes, width=0.6)

        self.ax.xaxis_date()
        self.ax.autoscale_view()
        plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')

        # these next 2 lines are vol lines
        plt.setp(self.ax.get_xticklabels(), visible=False)
        plt.subplots_adjust(hspace=0)

        #plt.show()
        self.canvas.draw()


    def on_key_press(event):
        print("you pressed {}".format(event.key))
        key_press_handler(event, canvas, toolbar)

    def _quit(self):
        self.master.quit()  # stops mainloop

    def switch_graphs(self):
        # Need to call the correct draw, whether we're on graph one or two
        self.graphIndex = (self.graphIndex + 1 ) % 2
        if self.graphIndex == 0:
            self.ohlc_daily_date_axis()
        else:
            self.ohlc_daily_date_axis_w_vol()



def main():
    root = Tk()
    matplotlibStock(root)
    root.mainloop()

if __name__ == '__main__':
    main()

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...