4

I have a stacked bar plot of analytics data embedded in my GUI which I would like to be more interactive. When the user hovers or clicks on a bar the plotted value should appear. Can this be done? I haven't been able to find anything about it in the documentation. Alternatively I could use something like PyGal but I don't know how to embed it into PyQt. Advice on either would be appreciated.

Sadie LaBounty
  • 379
  • 1
  • 5
  • 23

3 Answers3

3

The easiest solution is to use matplotlib events. They work the same whether you use a standalone plotting window or embed into a GUI.

A good introduction can be found in the matplotlib manual's event handling page.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Do you know how this would be used with [this](http://matplotlib.org/examples/pylab_examples/bar_stacked.html) to achieve the result described in the question? – Sadie LaBounty Mar 30 '17 at 10:31
  • I would first suggest you update your question with an actual problem description. A problem description includes the aim (what you want to achieve), the current state (what have you done to achieve this aim), and the problem itself (what hinders you to achieve the goal). Once you've done that I (or someone else) can provide an actual answer. – ImportanceOfBeingErnest Mar 30 '17 at 10:39
1

Yes they definitely can be. The matplotlib documentation has some useful code (https://matplotlib.org/users/event_handling.html#object-picking) that you can implement in an interactive way in a qt, tk, wx etc... interface by using %matplotlib qt #tk, wx, inline#(for notebook) etc... if you run this code, i think it does something quite close to what you're after (i'm using tk... so change to qt and i'd imagine it still works). run it and then click on a point on the scatterplot to trigger the event "onpick" and show that 'point' history:

"""
compute the mean and stddev of 100 data sets and plot mean vs stddev.
When you click on one of the mu, sigma points, plot the raw data from
the dataset that generated the mean and stddev
"""
import numpy as np
import matplotlib.pyplot as plt
%matplotlib tk

X = np.random.rand(100, 1000)
xs = np.mean(X, axis=1)
ys = np.std(X, axis=1)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title('click on point to plot time series')
line, = ax.plot(xs, ys, 'o', picker=5)  # 5 points tolerance


def onpick(event):

    if event.artist!=line: return True

    N = len(event.ind)
    if not N: return True


    figi = plt.figure()
    for subplotnum, dataind in enumerate(event.ind):
        ax = figi.add_subplot(N,1,subplotnum+1)
        ax.plot(X[dataind])
        ax.text(0.05, 0.9, 'mu=%1.3f\nsigma=%1.3f'%(xs[dataind], ys[dataind]),
                transform=ax.transAxes, va='top')
        ax.set_ylim(-0.5, 1.5)
    figi.show()
    return True

fig.canvas.mpl_connect('pick_event', onpick)

plt.show()

I don't have much experience with qt at all, but for tk it seems you can just send matplotlib figures to the canvas and they work quite well - so I assume something similar is possible in qt, but based on your question you already have it embedded and are just after the interactivity.


Head's up I ran into an issue that took a while to figure out and I don't know if it's the same in qt (maybe someone else can confirm)... but just a head's up that you may need to explicitly set picker=True when plotting. Again, I don't know really anything about qt, but here is an implementation in tk of the above, but on a custom gui where without picker=True would not be interactive:

import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure

import Tkinter as tk #for Python 3.x use import tkinter as tk
import ttk #for Python 3.x use from tkinter import ttk

class My_GUI:

    def __init__(self,master):
        self.master=master
        master.title("samplegui")
        f = Figure(figsize=(5,5), dpi=100)
        a = f.add_subplot(111)
        a.scatter(np.random.normal(size=100),np.random.normal(size=100),picker=True)
        canvas1=FigureCanvasTkAgg(f,master)
        canvas1.show()
        canvas1.get_tk_widget().pack(side="top",fill='x',expand=True)
        f.canvas.mpl_connect('pick_event',self.onpick)

        toolbar=NavigationToolbar2TkAgg(canvas1,master)
        toolbar.update()
        toolbar.pack(side='top',fill='x')

    def onpick(self,event):
        #do stuff
        print "My OnPick Event Worked!"
        return True

root=tk.Tk()
gui=My_GUI(root)
root.mainloop()
Vlox
  • 717
  • 8
  • 18
-2

To my best knowledge, not by default.

I fear, you have to work a bit for yourself, as I dont know a common widget for that. There are other QT designers which already offer more interactive plots, like: http://www.taurus-scada.org/en/latest/devel/designer_tutorial.html But, as far as I remember, it does not offer what you want. I would rather think about to create you own widget.

Marcus
  • 85
  • 9