GithubHelp home page GithubHelp logo

Comments (4)

pantaray avatar pantaray commented on June 14, 2024

Right now, it seems to me, that as a first step, we might want to mimic FieldTrip's

  • ft_singleplot: plot data of a single channel (or average across channels) in a single trial (or average across trials) for AnalogData, SpectralData,SpikeData and EventData(?) objects
  • ft_multiplot: plot data of multiple channels in a single trial (or average across trials) for AnalogData, SpectralData, SpikeData and EventData(?) objects. Right now, we don't support channel layout information, so just use a simple subplot grid.
  • ft_databrowser: a simple GUI to quickly inspect data in a Syncopy object. As a first approximation, this GUI should be completely "passive", i.e., no support for artifact rejection, data concatenation etc.

Looking at the respective performance requirements, it seems practicable to build both ft_singleplot as well as ft_multiplot upon matplotlib.

However, ft_databrowser might call for a faster visualization framework. After experimenting with and researching various tools (including matplotlib's animation package and some blit pixel magic), it seems to me that pyqtgraph might be our best option here. It is lightning fast, easy to install (conda install pyqtgraph), requires "only" pyqt and is specifically tailored to realtime scientific data visualizations. It seems very mature (first release in 2013) and was written by some of the VisPy authors, who say "[VisPy] is presently in early development and has a narrower scope than PyQtGraph--it will focus on visualization without the GUI toolkit features provided by PyQtGraph." Since we specifically want a GUI toolkit, pyqtgraph seems like the more straight forward choice for us.

To get an idea what pyqtgraph code looks like, here an example stolen from https://stackoverflow.com/a/40139416

import sys
import time
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import pyqtgraph as pg


class App(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(App, self).__init__(parent)

        #### Create Gui Elements ###########
        self.mainbox = QtGui.QWidget()
        self.setCentralWidget(self.mainbox)
        self.mainbox.setLayout(QtGui.QVBoxLayout())

        self.canvas = pg.GraphicsLayoutWidget()
        self.mainbox.layout().addWidget(self.canvas)

        self.label = QtGui.QLabel()
        self.mainbox.layout().addWidget(self.label)

        self.view = self.canvas.addViewBox()
        self.view.setAspectLocked(True)
        self.view.setRange(QtCore.QRectF(0,0, 100, 100))

        #  image plot
        self.img = pg.ImageItem(border='w')
        self.view.addItem(self.img)

        self.canvas.nextRow()
        #  line plot
        self.otherplot = self.canvas.addPlot()
        self.h2 = self.otherplot.plot(pen='y')


        #### Set Data  #####################

        self.x = np.linspace(0,50., num=100)
        self.X,self.Y = np.meshgrid(self.x,self.x)

        self.counter = 0
        self.fps = 0.
        self.lastupdate = time.time()

        #### Start  #####################
        self._update()

    def _update(self):

        self.data = np.sin(self.X/3.+self.counter/9.)*np.cos(self.Y/3.+self.counter/9.)
        self.ydata = np.sin(self.x/3.+ self.counter/9.)

        self.img.setImage(self.data)
        self.h2.setData(self.ydata)

        now = time.time()
        dt = (now-self.lastupdate)
        if dt <= 0:
            dt = 0.000000000001
        fps2 = 1.0 / dt
        self.lastupdate = now
        self.fps = self.fps * 0.9 + fps2 * 0.1
        tx = 'Mean Frame Rate:  {fps:.3f} FPS'.format(fps=self.fps )
        self.label.setText(tx)
        QtCore.QTimer.singleShot(1, self._update)
        self.counter += 1


if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    thisapp = App()
    thisapp.show()
    sys.exit(app.exec_())

@joschaschmiedt What do you think? Unless you have any objections, I'd go forward and start drafting our singleplot and multiplot analogues. As soon as that's done, I'd start putting together our version of databrowser.

from syncopy.

joschaschmiedt avatar joschaschmiedt commented on June 14, 2024

Sounds reasonable to me. I'd be happy if we could avoid enforcing a Qt dependency. Since we want to support both notebook and desktop workflows, a backend-agnostic solution would be great, e.g.

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button
 
freqs = np.arange(2, 20, 3)
 
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.2)
t = np.arange(0.0, 1.0, 0.001)
s = np.sin(2*np.pi*freqs[0]*t)
l, = plt.plot(t, s, lw=2)
 
 
class Index(object):
    ind = 0
 
    def next(self, event):
        self.ind += 1
        i = self.ind % len(freqs)
        ydata = np.sin(2*np.pi*freqs[i]*t)
        l.set_ydata(ydata)
        plt.draw()
 
    def prev(self, event):
        self.ind -= 1
        i = self.ind % len(freqs)
        ydata = np.sin(2*np.pi*freqs[i]*t)
        l.set_ydata(ydata)
        plt.draw()
 
callback = Index()
axprev = plt.axes([0.7, 0.05, 0.1, 0.075])
axnext = plt.axes([0.81, 0.05, 0.1, 0.075])
bnext = Button(axnext, 'Next')
bnext.on_clicked(callback.next)
bprev = Button(axprev, 'Previous')
bprev.on_clicked(callback.prev)
 
plt.show()

I suspect that for massive multi-channel data browsing there's no way around a backend-specific solution. @pantaray, do you know whether other web-based plotting libraries are good enough (plotly, ...)?

from syncopy.

pantaray avatar pantaray commented on June 14, 2024

Sounds reasonable to me. I'd be happy if we could avoid enforcing a Qt dependency.

Yes, 100% agree. Especially on more "exotic" HPC configurations, getting QT to work might not be trivial. We could use matplotlib as "fallback" in the databrowser in case QT is not available and, e.g., have databrowser_plt and databrowser_pyqt helper functions, that are called by the actual user-exposed databrowser method with the _pyqt one superseding the _plt-version upon availability of QT.

I suspect that for massive multi-channel data browsing there's no way around a backend-specific solution. @pantaray, do you know whether other web-based plotting libraries are good enough (plotly, ...)?

I've played around a little with bokeh and I've used plotly regularly. In my tests, bokeh wasn't dramatically faster than matplotlib (things chugging in matplotlib, stuttered in bokeh as well). With plotly, data-streaming is the bottle neck: plotly adds "traces" to its layout objects that contain copies of the data to be rendered. This works surprisingly well for datasets containing up to 1 million points, but "real-time" interactivity takes its toll through plotly's relentless copying of more and more data.

from syncopy.

pantaray avatar pantaray commented on June 14, 2024

Framework layout and reference implementations of both singleplot and multiplot for AnalogData objects have been incorporated (cf #78).

Migrated discussion about databrowser to a new issue #92

Each successive singleplot/multiplot feature request should be referenced as stand-alone issue for the respective data class (such as #82)

from syncopy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.