Skip to content

Commit

Permalink
Heatmap plot (#44)
Browse files Browse the repository at this point in the history
feat: add heatmap live plot
  • Loading branch information
domarm-comat authored Nov 18, 2024
1 parent 7988273 commit 9667104
Show file tree
Hide file tree
Showing 82 changed files with 468 additions and 4 deletions.
Empty file modified .github/FUNDING.yml
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ Pglive supports four plot types: `LiveLinePlot`, `LiveScatterPlot`, `LiveHBarPlo
![All plot types](https://i.postimg.cc/637CsKRC/pglive-allplots.gif)
![CandleStick plot](https://i.postimg.cc/0QcmMMb0/plot-candlestick.gif)
![live-categorized-bar.gif](https://i.postimg.cc/xqrwXXjY/live-categorized-bar.gif)
![heatmap.gif](https://i.postimg.cc/B6JR6qGF/heatmap.gif)

# Plot speed optimizations #

Expand Down
Empty file modified pglive/__init__.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/__init__.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/all_plot_types.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/axis.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/candlestick_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/categorized_bar_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/crop_offset_to_data.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/crosshair.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/designer_example/__init__.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/designer_example/main_example.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/designer_example/win_template.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/designer_example/win_template.ui
100644 → 100755
Empty file.
98 changes: 98 additions & 0 deletions pglive/examples_pyqt5/heatmap_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import signal
import time
from threading import Thread
import pglive.examples_pyqt5 as examples
import numpy.random
import pyqtgraph as pg
from PyQt5.QtWidgets import QWidget, QGridLayout


from pglive.kwargs import Axis
from pglive.sources.data_connector import DataConnector
from pglive.sources.live_HeatMap import LiveHeatMap
from pglive.sources.live_axis import LiveAxis
from pglive.sources.live_plot_widget import LivePlotWidget

"""
HeatMap is displayed in this example.
"""
# Get color map
cmap = pg.colormap.get("CET-D1")
# Create Heat map plot item
# grid_pen is used to draw a grid, remove if you don't want any grid
# counts_pen is used to draw point counts, remove if you don't want any grid
plot = LiveHeatMap(colormap=cmap, grid_pen=pg.mkPen("red"), counts_pen=pg.mkPen("white"))

resolution = 10 # 10 x 10 pixels
left_labels = [f"Y{i}" for i in range(resolution)]
bottom_labels = [f"X{i}" for i in range(resolution)]

# Set Axis.SHOW_ALL_CATEGORIES: True if you want to always show all category ticks
left_axis = LiveAxis("left", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels, Axis.SHOW_ALL_CATEGORIES: True})
right_axis = LiveAxis("right", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels,
Axis.SHOW_ALL_CATEGORIES: False})
top_axis = LiveAxis("top", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels,
Axis.SHOW_ALL_CATEGORIES: True})
bottom_axis = LiveAxis("bottom", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels,
Axis.SHOW_ALL_CATEGORIES: False})

view_1 = LivePlotWidget(title="Heat map plot with counts and grid @ 1Hz",
axisItems={'top': top_axis, 'bottom': bottom_axis, 'left': left_axis, 'right': right_axis})
view_1.addItem(plot)

# Get color map
cmap_2 = pg.colormap.get("plasma")
# Create Heat map plot item
plot_2 = LiveHeatMap(colormap=cmap_2)

resolution_2 = 20 # 20 x 20 pixels
left_labels_2 = [f"Y{i}" for i in range(resolution_2)]
bottom_labels_2 = [f"X{i}" for i in range(resolution_2)]

# Set Axis.SHOW_ALL_CATEGORIES: True if you want to always show all category ticks
left_axis_2 = LiveAxis("left", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels_2,
Axis.SHOW_ALL_CATEGORIES: True})
right_axis_2 = LiveAxis("right", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels_2,
Axis.SHOW_ALL_CATEGORIES: False})
top_axis_2 = LiveAxis("top", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels_2,
Axis.SHOW_ALL_CATEGORIES: True})
bottom_axis_2 = LiveAxis("bottom", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels_2,
Axis.SHOW_ALL_CATEGORIES: False})

view_2 = LivePlotWidget(title="Heat map plot @ 10Hz",
axisItems={'top': top_axis_2, 'bottom': bottom_axis_2, 'left': left_axis_2,
'right': right_axis_2})
view_2.addItem(plot_2)

# Setup layout to display all plots and histograms
plots_view = QWidget()
plots_view.setContentsMargins(0, 0, 0, 0)
plots_view.setLayout(QGridLayout())
plots_view.layout().setSpacing(0)
plots_view.layout().addWidget(view_1, 0, 0)
plots_view.layout().addWidget(plot.histogram, 0, 1)
plots_view.layout().addWidget(view_2, 1, 0)
plots_view.layout().addWidget(plot_2.histogram, 1, 1)
plots_view.show()
data_connector = DataConnector(plot)
data_connector_2 = DataConnector(plot_2)


def heatmap_generator(data_connector, resolution, bottom_labels, left_labels, timeout=1):
while examples.running:
heatmap = []
for i in range(resolution):
heatmap.append(numpy.random.randint(0, 1000, resolution))
data_connector.cb_set_data(bottom_labels, left_labels, heatmap=heatmap)
time.sleep(timeout)


Thread(target=heatmap_generator, args=(data_connector, resolution, bottom_labels, left_labels)).start()
Thread(target=heatmap_generator, args=(data_connector_2, resolution_2, bottom_labels_2, left_labels_2, 0.1)).start()
signal.signal(signal.SIGINT, lambda sig, frame: examples.stop())
examples.app.exec()
examples.stop()
Empty file modified pglive/examples_pyqt5/horizontal_bar_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/leading_line.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/line_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/live_plot_range.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/one_plot_multiple_plot_rates.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/pause_resume.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/plot_rate.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/scatter_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/update_rate.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/vertical_bar_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt5/vertical_bar_plot_color.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/__init__.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/all_plot_types.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/axis.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/candlestick_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/categorized_bar_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/crop_offset_to_data.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/crosshair.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/designer_example/__init__.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/designer_example/main_example.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/designer_example/win_template.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/designer_example/win_template.ui
100644 → 100755
Empty file.
98 changes: 98 additions & 0 deletions pglive/examples_pyqt6/heatmap_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import signal
import time
from threading import Thread

import numpy.random
import pyqtgraph as pg
from PyQt6.QtWidgets import QWidget, QGridLayout

import pglive.examples_pyqt6 as examples
from pglive.kwargs import Axis
from pglive.sources.data_connector import DataConnector
from pglive.sources.live_HeatMap import LiveHeatMap
from pglive.sources.live_axis import LiveAxis
from pglive.sources.live_plot_widget import LivePlotWidget

"""
HeatMap is displayed in this example.
"""
# Get color map
cmap = pg.colormap.get("CET-D1")
# Create Heat map plot item
# grid_pen is used to draw a grid, remove if you don't want any grid
# counts_pen is used to draw point counts, remove if you don't want any grid
plot = LiveHeatMap(colormap=cmap, grid_pen=pg.mkPen("red"), counts_pen=pg.mkPen("white"))

resolution = 10 # 10 x 10 pixels
left_labels = [f"Y{i}" for i in range(resolution)]
bottom_labels = [f"X{i}" for i in range(resolution)]

# Set Axis.SHOW_ALL_CATEGORIES: True if you want to always show all category ticks
left_axis = LiveAxis("left", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels, Axis.SHOW_ALL_CATEGORIES: True})
right_axis = LiveAxis("right", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels,
Axis.SHOW_ALL_CATEGORIES: False})
top_axis = LiveAxis("top", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels,
Axis.SHOW_ALL_CATEGORIES: True})
bottom_axis = LiveAxis("bottom", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels,
Axis.SHOW_ALL_CATEGORIES: False})

view_1 = LivePlotWidget(title="Heat map plot with counts and grid @ 1Hz",
axisItems={'top': top_axis, 'bottom': bottom_axis, 'left': left_axis, 'right': right_axis})
view_1.addItem(plot)

# Get color map
cmap_2 = pg.colormap.get("plasma")
# Create Heat map plot item
plot_2 = LiveHeatMap(colormap=cmap_2)

resolution_2 = 20 # 20 x 20 pixels
left_labels_2 = [f"Y{i}" for i in range(resolution_2)]
bottom_labels_2 = [f"X{i}" for i in range(resolution_2)]

# Set Axis.SHOW_ALL_CATEGORIES: True if you want to always show all category ticks
left_axis_2 = LiveAxis("left", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels_2,
Axis.SHOW_ALL_CATEGORIES: True})
right_axis_2 = LiveAxis("right", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels_2,
Axis.SHOW_ALL_CATEGORIES: False})
top_axis_2 = LiveAxis("top", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels_2,
Axis.SHOW_ALL_CATEGORIES: True})
bottom_axis_2 = LiveAxis("bottom", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels_2,
Axis.SHOW_ALL_CATEGORIES: False})

view_2 = LivePlotWidget(title="Heat map plot @ 10Hz",
axisItems={'top': top_axis_2, 'bottom': bottom_axis_2, 'left': left_axis_2,
'right': right_axis_2})
view_2.addItem(plot_2)

# Setup layout to display all plots and histograms
plots_view = QWidget()
plots_view.setContentsMargins(0, 0, 0, 0)
plots_view.setLayout(QGridLayout())
plots_view.layout().setSpacing(0)
plots_view.layout().addWidget(view_1, 0, 0)
plots_view.layout().addWidget(plot.histogram, 0, 1)
plots_view.layout().addWidget(view_2, 1, 0)
plots_view.layout().addWidget(plot_2.histogram, 1, 1)
plots_view.show()
data_connector = DataConnector(plot)
data_connector_2 = DataConnector(plot_2)


def heatmap_generator(data_connector, resolution, bottom_labels, left_labels, timeout=1):
while examples.running:
heatmap = []
for i in range(resolution):
heatmap.append(numpy.random.randint(0, 1000, resolution))
data_connector.cb_set_data(bottom_labels, left_labels, heatmap=heatmap)
time.sleep(timeout)


Thread(target=heatmap_generator, args=(data_connector, resolution, bottom_labels, left_labels)).start()
Thread(target=heatmap_generator, args=(data_connector_2, resolution_2, bottom_labels_2, left_labels_2, 0.1)).start()
signal.signal(signal.SIGINT, lambda sig, frame: examples.stop())
examples.app.exec()
examples.stop()
Empty file modified pglive/examples_pyqt6/horizontal_bar_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/leading_line.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/line_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/live_plot_range.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/one_plot_multiple_plot_rates.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/pause_resume.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/plot_rate.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/scatter_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/update_rate.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/vertical_bar_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyqt6/vertical_bar_plot_color.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/__init__.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/all_plot_types.py
100644 → 100755
Empty file.
4 changes: 1 addition & 3 deletions pglive/examples_pyside6/axis.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
from math import sin
from threading import Thread
from time import sleep

import pyqtgraph as pg # type: ignore

import pglive.examples_pyside6 as examples
import pyqtgraph as pg # type: ignore
from pglive.kwargs import Axis
from pglive.sources.data_connector import DataConnector
from pglive.sources.live_axis import LiveAxis
Expand Down
Empty file modified pglive/examples_pyside6/candlestick_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/categorized_bar_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/crop_offset_to_data.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/crosshair.py
100644 → 100755
Empty file.
98 changes: 98 additions & 0 deletions pglive/examples_pyside6/heatmap_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import signal
import time
from threading import Thread
import pglive.examples_pyside6 as examples
import numpy.random
import pyqtgraph as pg
from PySide6.QtWidgets import QWidget, QGridLayout


from pglive.kwargs import Axis
from pglive.sources.data_connector import DataConnector
from pglive.sources.live_HeatMap import LiveHeatMap
from pglive.sources.live_axis import LiveAxis
from pglive.sources.live_plot_widget import LivePlotWidget

"""
HeatMap is displayed in this example.
"""
# Get color map
cmap = pg.colormap.get("CET-D1")
# Create Heat map plot item
# grid_pen is used to draw a grid, remove if you don't want any grid
# counts_pen is used to draw point counts, remove if you don't want any grid
plot = LiveHeatMap(colormap=cmap, grid_pen=pg.mkPen("red"), counts_pen=pg.mkPen("white"))

resolution = 10 # 10 x 10 pixels
left_labels = [f"Y{i}" for i in range(resolution)]
bottom_labels = [f"X{i}" for i in range(resolution)]

# Set Axis.SHOW_ALL_CATEGORIES: True if you want to always show all category ticks
left_axis = LiveAxis("left", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels, Axis.SHOW_ALL_CATEGORIES: True})
right_axis = LiveAxis("right", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels,
Axis.SHOW_ALL_CATEGORIES: False})
top_axis = LiveAxis("top", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels,
Axis.SHOW_ALL_CATEGORIES: True})
bottom_axis = LiveAxis("bottom", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels,
Axis.SHOW_ALL_CATEGORIES: False})

view_1 = LivePlotWidget(title="Heat map plot with counts and grid @ 1Hz",
axisItems={'top': top_axis, 'bottom': bottom_axis, 'left': left_axis, 'right': right_axis})
view_1.addItem(plot)

# Get color map
cmap_2 = pg.colormap.get("plasma")
# Create Heat map plot item
plot_2 = LiveHeatMap(colormap=cmap_2)

resolution_2 = 20 # 20 x 20 pixels
left_labels_2 = [f"Y{i}" for i in range(resolution_2)]
bottom_labels_2 = [f"X{i}" for i in range(resolution_2)]

# Set Axis.SHOW_ALL_CATEGORIES: True if you want to always show all category ticks
left_axis_2 = LiveAxis("left", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels_2,
Axis.SHOW_ALL_CATEGORIES: True})
right_axis_2 = LiveAxis("right", tick_angle=0,
**{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: left_labels_2,
Axis.SHOW_ALL_CATEGORIES: False})
top_axis_2 = LiveAxis("top", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels_2,
Axis.SHOW_ALL_CATEGORIES: True})
bottom_axis_2 = LiveAxis("bottom", tick_angle=0, **{Axis.TICK_FORMAT: Axis.CATEGORY, Axis.CATEGORIES: bottom_labels_2,
Axis.SHOW_ALL_CATEGORIES: False})

view_2 = LivePlotWidget(title="Heat map plot @ 10Hz",
axisItems={'top': top_axis_2, 'bottom': bottom_axis_2, 'left': left_axis_2,
'right': right_axis_2})
view_2.addItem(plot_2)

# Setup layout to display all plots and histograms
plots_view = QWidget()
plots_view.setContentsMargins(0, 0, 0, 0)
plots_view.setLayout(QGridLayout())
plots_view.layout().setSpacing(0)
plots_view.layout().addWidget(view_1, 0, 0)
plots_view.layout().addWidget(plot.histogram, 0, 1)
plots_view.layout().addWidget(view_2, 1, 0)
plots_view.layout().addWidget(plot_2.histogram, 1, 1)
plots_view.show()
data_connector = DataConnector(plot)
data_connector_2 = DataConnector(plot_2)


def heatmap_generator(data_connector, resolution, bottom_labels, left_labels, timeout=1):
while examples.running:
heatmap = []
for i in range(resolution):
heatmap.append(numpy.random.randint(0, 1000, resolution))
data_connector.cb_set_data(bottom_labels, left_labels, heatmap=heatmap)
time.sleep(timeout)


Thread(target=heatmap_generator, args=(data_connector, resolution, bottom_labels, left_labels)).start()
Thread(target=heatmap_generator, args=(data_connector_2, resolution_2, bottom_labels_2, left_labels_2, 0.1)).start()
signal.signal(signal.SIGINT, lambda sig, frame: examples.stop())
examples.app.exec()
examples.stop()
Empty file modified pglive/examples_pyside6/horizontal_bar_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/leading_line.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/line_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/live_plot_range.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/one_plot_multiple_plot_rates.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/pause_resume.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/plot_rate.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/scatter_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/update_rate.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/vertical_bar_plot.py
100644 → 100755
Empty file.
Empty file modified pglive/examples_pyside6/vertical_bar_plot_color.py
100644 → 100755
Empty file.
Empty file modified pglive/kwargs.py
100644 → 100755
Empty file.
Empty file modified pglive/sources/__init__.py
100644 → 100755
Empty file.
Empty file modified pglive/sources/data_connector.py
100644 → 100755
Empty file.
Loading

0 comments on commit 9667104

Please sign in to comment.