Skip to main content

No project description provided

Project description

Logo of the project

Real Time Plotting with pyqtgraph and ZMQ

The point of this module is to be able to plot remotely over socket protocols using the ZMQ library. The use cases that I have in mind is plotting information from the raspberry pi to a host computer so that they can plot the data. This is very useful for setting up real time plots given pyqtgraph's performance. This can also be used to plot local information in real time by using the localhost as the address to publish/subscribe data from.

The main highlight in this plotter are the following:

  • Fast Performance. Can do 500+ fps on one trace using an i7-9750H processor
  • Remote Plot Customizability. The plot configuration is defined by the provider of the data. E.g. if you are using a pi to collect data, the plot configuration is also stored on the pi so you only have to change code in one location
  • Save data. Once you plot the data, you can save it locally by clicking one button.

Install

pip install better-rtplot

If you are using WSL, you need to install an xorg server such as vcXsrv

How to use

Step 1: On the computer that will be used to plot run:

For local plots: python3 server.py -l

To plot from a raspberry pi: python3 server.py -p xxx.xxx.xxx.xxx

Where the xxx.xxx.xxx.xxx represents the pi's ip address (note, you must be on the same network)

Step 2: On the script that provides data, add the plotting library

In order to use this library, you must have installed the library and import the rtplot.client module into your code. The two main steps are to initialize the plotter and then to send data as seen in the following example:

#Load plotting library
from rtplot import client 

#Common import
import numpy as np

#Initialize one plot with 5 traces
client.initialize_plots(5)

#Send 1000 datapoints
for i in range(1000):

    #Send random data
    client.send_array(np.random.randn(5,1))

In the simplest plot configuration, you only need to indicate the amount of traces that you want (if you leave it empty, it will default to 1 trace). Then you need to send the data. The data must be either a list or a numpy array. More examples can be seen in the example code

:cherry_blossom: Make pretty plots :cherry_blossom:

You can control the following things when calling client.initialize_plots() by passing in a dictionary:

  • 'names' - This defines the names of the traces. The plot will have as many traces as names.

  • 'colors' - Defines the colors for each trace. Follow documentation on how to specify color. Should have at least the same length as the number of traces.

  • 'line_style' - Defines wheter or not a trace is dashed or not.

    • '-' - represents dashed line
    • "" - emptry string (or any other string) represents a normal line
  • 'line_width' - Defines how thick the plot lines are. Expects an integer

  • 'title' - Sets the title to the plot

  • 'ylabel' - Sets the y label of the plot

  • 'xlabel' - Sets the x label of the plot

  • 'yrange' - Sets the range of values of y. This provides a performance boost to the plotter

    • Expects values as a iterable in the order [min, max]. Example: [-2,2]
  • 'xrange' - Sets the number of datapoints that will be in the real time plotter at a given time.

    • Expects values as a integer that describes how many datapoints are in the subplot. Default is 200 datapoints

You only need to specify the things that you want, if the dictionary element is left out then the default value is used.

How to send data

Once the plot has been configured, the data is sent as a numpy array. The order of the data in the array is very important and it MUST be sent where the rows have data that corresponds to the same order that the trace names were defined in.

#Load plotting library
from rtplot import client 

#Common import
import numpy as np

#Let's create two subplots
#First, define a dictionary of items for each plot

#First plot will have three traces: phase, phase_dot, stride_length
plot_1_config = {'names': ['phase', 'phase_dot', 'stride_length'],
                 'title': "Phase, Phase Dot, Stride Length",
                 'ylabel': "reading (unitless)",
                 'xlabel': 'test 1'}

#Second plot will have five traces: gf1, gf2, gf3, gf4, gf5
plot_2_config = {'names': ["gf1","gf2","gf3","gf4","gf5"],
                 'colors' : ["r","b","g","r","b"],
                 'line_style' : ['-','','-','','-'],
                 'title': "Phase, Phase Dot, Stride Length",
                 'ylabel': "reading (unitless)",
                 'xlabel': 'test 2'}

#Aggregate into list  
plot_config = [plot_1_config,plot_2_config]

#Tell the server to initialize the plot
client.initialize_plots(plot_config)

#Create plotter array with random data
plot_data_array = [np.random.randn(), #phase
                   np.random.randn(), #phase_dot
                   np.random.randn(), #stride_length
                   np.random.randn(), #gf1
                   np.random.randn(), #gf2
                   np.random.randn(), #gf3
                   np.random.randn(), #gf4
                   np.random.randn()  #gf5
                   ]

#Send data to server to plot
client.send_array(plot_data_array)

Additional networking configurations

There are two main ways that you can connect to transmit information. Either the computer that runs the server knows what IP the client is (server connects to client), or the client knows which IP the server has (server connects to client). For either option, follow the steps bellow:

Server connects to client

This is accomplished by running the server with the IP address of the pi as an argument.

python3 server.py -p xxx.xxx.xxx.xxx

Where xxx.xxx.xxx.xxx is the IP address of the pi. No additional configuration is needed on the client side.

Client connects to server

This is done by setting up the server with the static ip flag.

python3 server.py -s

The client then needs to specify the ip of the plotter by running:

client.configure_ip("xxx.xxx.xxx.xxx")

Where xxx.xxx.xxx.xxx is the IP address of the server.

Plotter too slow?

The performance of the plotter is mostly impacted by the amount of traces that you want to plot (this is due to multiple calls to the line drawing algorithms in pyqtgraph). However, sending over multiple datapoints to plot at once is not expensive since there is essentially only the added overhead of receiving the data (the plotter redraws the entire line anyways). Therefore to get the most performance you should have as little traces as possible and send over as much datapoints at once before the plot updates look ugly.

Fix y range

To get the most performance out of the system, you want to set the 'yrange' configuration of the plot. This has resulted in a 100FPS increase for my testing.

Example Code

Example Image

alt text

alt text

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

better_rtplot-0.1.2.tar.gz (28.1 kB view details)

Uploaded Source

Built Distribution

better_rtplot-0.1.2-py3-none-any.whl (28.0 kB view details)

Uploaded Python 3

File details

Details for the file better_rtplot-0.1.2.tar.gz.

File metadata

  • Download URL: better_rtplot-0.1.2.tar.gz
  • Upload date:
  • Size: 28.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.5.1 CPython/3.9.16 Linux/5.4.0-148-generic

File hashes

Hashes for better_rtplot-0.1.2.tar.gz
Algorithm Hash digest
SHA256 8c12a57020f97e0b13ec5218ae3ff016c76a6f051414f9ba2e75e0ee3dbc660a
MD5 3a07bb4c073cc2010fc8217754fd71b8
BLAKE2b-256 743dc44d6909c36d079e42f92d9208e13a43b0fd9dd61d94f5130fbedff81209

See more details on using hashes here.

File details

Details for the file better_rtplot-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: better_rtplot-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 28.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.5.1 CPython/3.9.16 Linux/5.4.0-148-generic

File hashes

Hashes for better_rtplot-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 2ee1a8e8335edf4125d7bb981722db4d20b00d922503e26fb93f2fdb9a13d8f1
MD5 92cf1457341dd7a4cb94c9f2fd15ae01
BLAKE2b-256 bf14b27725843b11b834522aa78d96e2ad6d7e47ba51a5d116c17146d911ee1a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page