How can I make a python candlestick chart clickable in matplotlib
<p>I am trying to make a OHLC graph plotted with matplotlib interactive upon the user clicking on a valid point. The data is stored as a pandas dataframe of the form  </p>

<pre><code>index       PX_BID  PX_ASK  PX_LAST  PX_OPEN  PX_HIGH  PX_LOW
2016-07-01  1.1136  1.1137   1.1136   1.1106   1.1169  1.1072
2016-07-04  1.1154  1.1155   1.1154   1.1143   1.1160  1.1098
2016-07-05  1.1076  1.1077   1.1076   1.1154   1.1186  1.1062
2016-07-06  1.1100  1.1101   1.1100   1.1076   1.1112  1.1029
2016-07-07  1.1062  1.1063   1.1063   1.1100   1.1107  1.1053
</code></pre>

<p>I am plotting it with matplotlib's candlestick function:</p>

<pre><code>candlestick2_ohlc(ax1, df['PX_OPEN'],df['PX_HIGH'],df['PX_LOW'],df['PX_LAST'],width=1)
</code></pre>

<p>When plotted it looks somthing like this:</p>

<p><a href="https://pythonprogramming.net/static/images/matplotlib/candlestick-ohlc-graphs-matplotlib-tutorial.png" rel="nofollow">https://pythonprogramming.net/static/images/matplotlib/candlestick-ohlc-graphs-matplotlib-tutorial.png</a></p>

<p>I want the console to print out the value of the point clicked, the date and whether it is an open, high low or close. So far I have something like:</p>

<pre><code>fig, ax1 = plt.subplots()

ax1.set_title('click on points', picker=True)
ax1.set_ylabel('ylabel', picker=True, bbox=dict(facecolor='red'))
line = candlestick2_ohlc(ax1, df['PX_OPEN'],df['PX_HIGH'],df['PX_LOW'],df['PX_LAST'],width=0.4)

def onpick1(event):
    if isinstance(event.artist, (lineCollection, barCollection)):
        thisline = event.artist
        xdata = thisline.get_xdata()
        ydata = thisline.get_ydata()
        ind = event.ind
        #points = tuple(zip(xdata[ind], ydata[ind]))
        #print('onpick points:', points)
        print( 'X='+str(np.take(xdata, ind)[0]) ) # Print X point
        print( 'Y='+str(np.take(ydata, ind)[0]) ) # Print Y point

fig.canvas.mpl_connect('pick_event', onpick1)
plt.show()
</code></pre>

<p>This code however does not print anything when ran and points are clicked. When I look at examples of interactive matplotlib graphs, they tend to have an argument in the plot function such as:</p>

<pre><code>line, = ax.plot(rand(100), 'o', picker=5)
</code></pre>

<p>However, candlestick2_ohlc does not take a 'picker' arg. Any tips on how I can get around this?</p>

<p>Thanks</p>

<p>You need to set <code>set_picker(True)</code> to enable a pick event  or give a tolerance in points as a float (see <a href="http://matplotlib.org/api/artist_api.html#matplotlib.artist.Artist.set_picker" rel="nofollow">http://matplotlib.org/api/artist_api.html#matplotlib.artist.Artist.set_picker</a>).</p>

<p>So in your case <code>ax1.set_picker(True)</code> if you want  pick event to be fired whenever if mouseevent is over <code>ax1</code>.</p>

<p>You can enable pick events on the elements of the candlestick chart. I read the documentation and <a href="http://matplotlib.org/api/finance_api.html#matplotlib.finance.candlestick2_ohlc" rel="nofollow"><code>candlestick2_ohlc</code></a> returns a tuple of two objects: a <code>LineCollection</code> and a <code>PolyCollection</code>. So you can name these objects and set the picker to true on them</p>

<pre><code>(lines,polys) = candlestick2_ohlc(ax1, ...)
lines.set_picker(True) # collection of lines in the candlestick chart
polys.set_picker(True) # collection of polygons in the candlestick chart
</code></pre>

<p>The index of the event <code>ind = event.ind[0]</code> will tell you which element in the collection contained the mouse event (<code>event.ind</code> returns a list of indices since a mouse event might pertain more than one item).</p>

<p>Once you trigger a pick event on a candlestick you can print the data from the original dataframe.</p>

<p>Here's some working code</p>

<pre><code>import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection, PolyCollection
from matplotlib.text import Text
from matplotlib.finance import candlestick2_ohlc
import numpy as np
import pandas as pd

np.random.seed(0)
dates = pd.date_range('20160101',periods=7)
df = pd.DataFrame(np.reshape(1+np.random.random_sample(42)*0.1,(7,6)),index=dates,columns=["PX_BID","PX_ASK","PX_LAST","PX_OPEN","PX_HIGH","PX_LOW"])
df['PX_HIGH']+=.1
df['PX_LOW']-=.1

fig, ax1 = plt.subplots()

ax1.set_title('click on points', picker=20)
ax1.set_ylabel('ylabel', picker=20, bbox=dict(facecolor='red'))

(lines,polys) = candlestick2_ohlc(ax1, df['PX_OPEN'],df['PX_HIGH'],df['PX_LOW'],df['PX_LAST'],width=0.4)
lines.set_picker(True)
polys.set_picker(True)

def onpick1(event):
    if isinstance(event.artist, (Text)):
        text = event.artist
        print 'You clicked on the title ("%s")' % text.get_text()
    elif isinstance(event.artist, (LineCollection, PolyCollection)):   
        thisline = event.artist
        mouseevent = event.mouseevent
        ind = event.ind[0]
        print 'You clicked on item %d' % ind
        print 'Day: ' + df.index[ind].normalize().to_datetime().strftime('%Y-%m-%d')
        for p in ['PX_OPEN','PX_OPEN','PX_HIGH','PX_LOW']:
            print p + ':' + str(df[p][ind])    
        print('x=%d, y=%d, xdata=%f, ydata=%f' %
          ( mouseevent.x, mouseevent.y, mouseevent.xdata, mouseevent.ydata))



fig.canvas.mpl_connect('pick_event', onpick1)
plt.show()
</code></pre>

python pandas matplotlib graph interactive