Ripyl plotting tutorial

This tutorial provides an overview of plotting with Ripyl.

The Ripyl library comes with a demo program that can plot examples of each supported protocol. It is possible to use the same plotting facilities to plot your own data if needed. The optional matplotlib library must be installed to plot waveforms with Ripyl.

Get sampled data

For this example we will generate some synthesized I2C waveforms to plot with. This step can be skipped if you already have sampled waveforms ready to plot.

import ripyl.sigproc as sigp
import ripyl.streaming as stream
import ripyl.protocol.i2c as i2c

def sim_i2c():
    # I2C params
    clock_freq = 100.0e3

    # Sampled waveform params
    sample_rate = clock_freq * 100.0
    rise_time = sigp.min_rise_time(sample_rate) * 10.0 # 10x min. rise time
    noise_snr = 30.0

    message = 'foobar'
    byte_msg = bytearray(message.encode('latin1')) # Get raw bytes as integers

    transfers = [i2c.I2CTransfer(i2c.I2C.Read, 0x42, byte_msg)]

    # Synthesize the waveform edge stream
    scl, sda = i2c.i2c_synth(transfers, clock_freq, idle_start=3.0e-5, idle_end=3.0e-5)

    # Convert to a sample stream with band-limited edges and noise
    cln_scl_it = sigp.synth_wave(scl, sample_rate, rise_time, tau_factor=0.7)
    cln_sda_it = sigp.synth_wave(sda, sample_rate, rise_time, tau_factor=1.5)

    # Add noise and gain
    noisy_scl_it = sigp.amplify(sigp.noisify(cln_scl_it, snr_db=noise_snr), gain=3.3, offset=0.0)
    noisy_sda_it = sigp.amplify(sigp.noisify(cln_sda_it, snr_db=noise_snr), gain=3.3, offset=0.0)

    # Capture the samples from the iterator
    noisy_scl = list(noisy_scl_it)
    noisy_sda = list(noisy_sda_it)

    return (noisy_scl, noisy_sda)

The Ripyl Plotter object needs sample streams as the waveform source(s). If you are getting samples from an external source you must convert them to a sample stream with the samples_to_sample_stream() function.

# Get scl_samples and sda_samples from external source
noisy_scl = stream.samples_to_sample_stream(scl_samples, sample_period)
noisy_sda = stream.samples_to_sample_stream(sda_samples, sample_period)

Plot waveforms

Once the sample streams are prepared you are ready to plot. The StreamRecords produced by the protocol decoders contain annotation information useful for plotting. Ripyl provides a Plotter class that encapsulates a matplotlib figure and handles layout and annotation formatting. You prepare a plot with the plot() method, providing a dict of channel definitions with the waveform samples, any decoded records for annotation, and the title for the plot. Once the Plotter object is prepared you can either show the result in a matplotlib window or save it to a file.

import matplotlib
import ripyl.util.plot as rplot
from collections import OrderedDict

noisy_scl, noisy_sda = sim_i2c() # Generate simulated sample streams

# The decoded records contain annotation information
records = list(i2c.i2c_decode(iter(noisy_scl), iter(noisy_sda)))

# Define the channels ordered from top to bottom with the y-axis labels
channels = OrderedDict([('SCL (V)', noisy_scl), ('SDA (V)', noisy_sda)])
title = 'I2C plot example'

# The Plotter object formats the samples and annotations into plotted waveforms
plotter = rplot.Plotter()
plotter.plot(channels, records, title, label_format=stream.AnnotationFormat.Text)
plotter.show() # Show the plot in a matplotlib window

This produces an interactive plot window:

../_images/plotting_tut1.png

You can save the plot to a file instead:

# Write PNG image of 8x4 inches (800x400 @ 100dpi)
plotter.save_plot('i2c.png', (8.0, 4.0))
../_images/plotting_tut2.png

The plot() method has a label_format parameter that controls the default format for the annotation text labels. The available formats are defined in the AnnotationFormat enum:

Hidden
Invisible text label. Only the colored rectangle is drawn
Invisible
Invisible text label and rectangle
String
Record data attribute is treated as a string
Text
Record data attribute is a sequence of characters
Int
Label as integers (default)
Hex
Label as hexadecimal
Bin
Label as binary
Small
Same as String but with smaller text

The label_format parameter only affects fields that have been annotated to have a general purpose format. Changing the format to Hex produces the following result. Note that the address portion and the ack bits retain their formatting as String and Hidden.

plotter.plot(channels, records, title, label_format=stream.AnnotationFormat.Hex)
../_images/plotting_tut3.png