Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simple fastplotlib example #88

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ on:
jobs:
test:

runs-on: ubuntu-latest
runs-on: ${{matrix.os}}
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
os: [ubuntu-latest, macos-latest] # [ubuntu-latest, macos-latest, windows-latest]

steps:
- uses: actions/checkout@v3
Expand All @@ -28,7 +30,19 @@ jobs:
run: |
python -m pip install --upgrade pip build
pip install flake8 pytest
pip install -e .
- name: Install package (Ubuntu)
if: startsWith(matrix.os, 'ubuntu')
run: |
pip install -e .[tests] --no-binary pyzmq
- name: Install package (Mac)
if: startsWith(matrix.os, 'macos')
run: |
pip install -e .[tests]

- name: Test with pytest
run: |
python -m pytest pytest
python -m pytest --cov=improv pytest

- name: Coveralls
uses: coverallsapp/github-action@v2

39 changes: 39 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: deploy

on:
# Trigger the workflow on push to main branch
push:
branches:
- main

# This job installs dependencies, build the book, and pushes it to `gh-pages`
jobs:
build-and-deploy-book:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
python-version: [3.8]
steps:
- uses: actions/checkout@v2

# Install dependencies
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install -r docs/requirements.txt

# Build the book
- name: Build the book
run: |
jupyter-book build docs

# Deploy the book's HTML to gh-pages branch
- name: GitHub Pages action
uses: peaceiris/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/_build/html
19 changes: 10 additions & 9 deletions demos/basic/actors/front_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ def __init__(self, visual, comm, parent=None):
self.rawplot_2.getImageItem().mouseClickEvent = self.mouseClick #Select a neuron
self.slider.valueChanged.connect(_call(self.sliderMoved)) #Threshold for magnitude selection

self.update()

def update(self):
''' Update visualization while running
'''
t = time.time()
#start looking for data to display
self.visual.getData()
#logger.info('Did I get something:', self.visual.Cx)

if self.draw:
#plot lines
Expand Down Expand Up @@ -116,10 +117,10 @@ def customizePlots(self):
# Add polar grid lines
polar.addLine(x=0, pen=0.2)
polar.addLine(y=0, pen=0.2)
for r in range(0, 4, 1):
circle = pyqtgraph.QtGui.QGraphicsEllipseItem(-r, -r, r*2, r*2)
circle.setPen(pyqtgraph.mkPen(0.1))
polar.addItem(circle)
# for r in range(0, 4, 1):
# circle = pyqtgraph.QtGui.QGraphicsEllipseItem(-r, -r, r*2, r*2)
# circle.setPen(pyqtgraph.mkPen(0.1))
# polar.addItem(circle)
polar.hideAxis('bottom')
polar.hideAxis('left')

Expand All @@ -128,10 +129,10 @@ def customizePlots(self):
self.polar1.setData(x, y)
self.polar2.setData(x, y)

for r in range(2, 12, 2):
circle = pyqtgraph.QtGui.QGraphicsEllipseItem(-r, -r, r*2, r*2)
circle.setPen(pyqtgraph.mkPen(0.1))
polars[2].addItem(circle)
# for r in range(2, 12, 2):
# circle = pyqtgraph.QtGui.QGraphicsEllipseItem(-r, -r, r*2, r*2)
# circle.setPen(pyqtgraph.mkPen(0.1))
# polars[2].addItem(circle)
self.polar3 = polars[2].plot()

#sliders
Expand Down
3 changes: 2 additions & 1 deletion demos/basic/actors/visual.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ def setup(self):
self.window=500

def run(self):
pass #NOTE: Special case here, tied to GUI
# #NOTE: Special case here, tied to GUI
pass

def getData(self):
t = time.time()
Expand Down
6 changes: 3 additions & 3 deletions demos/basic/basic_demo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ actors:
Acquirer:
package: demos.sample_actors.acquire
class: FileAcquirer
filename: data/Tolias_mesoscope_2.hdf5
filename: demos/basic/data/Tolias_mesoscope_2.hdf5
framerate: 15

Processor:
package: actors.basic_processor
class: BasicProcessor
init_filename: data/Tolias_mesoscope_2.hdf5
config_file: basic_caiman_params.txt
init_filename: demos/basic/data/Tolias_mesoscope_2.hdf5
config_file: demos/basic/basic_caiman_params.txt

Visual:
package: actors.visual
Expand Down
22 changes: 22 additions & 0 deletions demos/fastplotlib/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# fastplotlib demo

This demo consists of a **generator** `actor` that generates random frames of size 512 * 512 that are sent via a queue to a **processor** `actor` that can be used to process the frames and send them via `zmq`. The `fastplotlib.ipynb` notebook then receives the most recent frame via `zmq` and displays it using [`fastplotlib`](https://github.com/kushalkolar/fastplotlib/).

Usage:

```bash
# cd to this dir
cd .../improv/demos/fastplotlib

# start improv
improv run ./fastplotlib.yaml

# call `setup` in the improv TUI
setup

# Run the cells in the jupyter notebook until you receive
# the dark blue square in the plot

# once the plot is ready call `run` in the improv TUI
run
```
47 changes: 47 additions & 0 deletions demos/fastplotlib/actors/sample_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from improv.actor import Actor, RunManager
from datetime import date #used for saving
import numpy as np
import time
import logging; logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class Generator(Actor):
"""
Generate data and puts it in the queue for the processor to take
"""

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.data = None
self.name = "Generator"
self.frame_index = 0

def __str__(self):
return f"Name: {self.name}, Data: {self.data}"

def setup(self):
logger.info('Completed setup for Generator')

def stop(self):
print("Generator stopping")
return 0

def runStep(self):
"""
Generates 512 x 512 frame and puts it in the queue for the processor
"""

data = np.random.randint(0, 255, size=(512 * 512), dtype=np.uint16).reshape(512, 512)

frame_ix = np.array([self.frame_index], dtype=np.uint32)

# there must be a better way to do this
out = np.concatenate(
[data.ravel(), frame_ix],
dtype=np.uint32
)

self.q_out.put(out)

self.frame_index += 1
56 changes: 56 additions & 0 deletions demos/fastplotlib/actors/sample_processor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from improv.actor import Actor, RunManager
import numpy as np
from queue import Empty
import logging; logger = logging.getLogger(__name__)
import zmq
logger.setLevel(logging.INFO)


class Processor(Actor):
"""
Process data and send it through zmq to be be visualized
"""

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def setup(self):
"""
Creates and binds the socket for zmq
"""

self.name = "Processor"

context = zmq.Context()
self.socket = context.socket(zmq.PUB)
self.socket.bind("tcp://127.0.0.1:5555")

self.frame_index = 0

logger.info('Completed setup for Processor')

def stop(self):
logger.info("Processor stopping")
return 0

def runStep(self):
"""
Gets the frame from the queue, take the mean, sends a memoryview
so the zmq subscriber can get the buffer to update the plot
"""

frame = None

try:
frame = self.q_in.get(timeout=0.05)
except Empty:
pass
except:
logger.error("Could not get frame!")

if frame is not None:
self.frame_index += 1
# do some processing
frame.mean()
# send the buffer
self.socket.send(frame)
Loading