=======================
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 I\ :sup:`2`\ C waveforms to plot with. This step can be skipped if you already have sampled waveforms ready to plot.
.. code-block:: python
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 :ref:`sample stream ` with the :func:`~.streaming.samples_to_sample_stream` function.
.. code-block:: python
# 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 :class:`~.Plotter` class that encapsulates a matplotlib figure and handles layout and annotation formatting. You prepare a plot with the :meth:`~.Plotter.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.
.. code-block:: python
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:
.. image:: ../image/plotting_tut1.png
:scale: 75%
You can save the plot to a file instead:
.. code-block:: python
# Write PNG image of 8x4 inches (800x400 @ 100dpi)
plotter.save_plot('i2c.png', (8.0, 4.0))
.. image:: ../image/plotting_tut2.png
:scale: 60%
The :meth:`~.Plotter.plot` method has a ``label_format`` parameter that controls the default format for the annotation text labels. The available formats are defined in the :class:`~.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.
.. code-block:: python
plotter.plot(channels, records, title, label_format=stream.AnnotationFormat.Hex)
.. image:: ../image/plotting_tut3.png
:scale: 60%