Comments (4)
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) forAnalogData
,SpectralData
,SpikeData
andEventData
(?) objectsft_multiplot
: plot data of multiple channels in a single trial (or average across trials) forAnalogData
,SpectralData
,SpikeData
andEventData
(?) 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.
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.
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.
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)
- Create stand alone synthetic data modul
- Creating a dummy dataset using snp.AnalogData does not create a data set with desired name of the channels HOT 2
- Handling of NaNs during FIR filtering
- Continuous data time axis not editable HOT 1
- Redesign `time` property
- Better MNE-Integration: live conversion between our and their data classes HOT 1
- Nonparametric permutation tests
- Long waiting times after computation finished for specific datasets HOT 4
- Performance monitoring over time: Implement some airspeed velocity performance tests HOT 4
- Add `cfg.montage` to `preprocessing`
- Write a short tutorial starting from a FT data file HOT 1
- Use pynwb to read/write Neurodata Without Borders (NWB) files HOT 4
- Rewrite parallel doc chapter
- String representation of EventData with trialdefinition raises Exception
- Running spy.cleanup twice in a row crashes Syncopy.
- Write short `SpikeData` guide/tutorial
- pynwb not available for powerlinux on conda-forge HOT 1
- Adding a `.pre-commit-config.yaml` file HOT 2
- Add `channelcmb` parameter to `connectivityanalysis` frontend HOT 1
- `info` property does not get copied with selections
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from syncopy.