# Create plots

SLiCAP output displayed on this manual page, is generated with the script: `plots.py`, imported by `Manual.py`.

     1#!/usr/bin/env python3
     2# -*- coding: utf-8 -*-
     3"""
     4plots.py: SLiCAP scripts for the HTML help file
     5"""
     6import SLiCAP as sl
     7from copy import deepcopy
     8import numpy as np
     9
    10cir = sl.makeCircuit("kicad/myPassiveNetwork/myPassiveNetwork.kicad_sch")

SLiCAP provides a number of plot functions for pre-formatted plotting of instruction results. Plot types, axis types, trace colors, markers, labels and plot legends are automatically selected from the instruction settings.

Plot functions are collected in the SLiCAP module SLiCAPplots.py.

SLiCAP plots are hierarchically structured:

- A figure object is the main object that can be plotted using its `.plot()` method.

- The figure’s `.axis` attribute is a list of lists with axis objects for each row, from left to right.

- The `.traces` attribute of each `axis` object is a list with trace objects that will be plotted the axis. Trace xdata, ydata, lables, colors, markers, etc, are all attributes of a `trace` object.

SLiCAP built-in figures are single-axis figures.

SLiCAP has three built-in plot functions:

- plotSweep()

- plotPZ()

- plot()

SLiCAP plot functions use the Python module matplotlib. When using SLiCAP built-in plot functions, knowledge about matplotlib is not required.

## Built-in plot types

### plotSweep()

plotSweep() displays traces from expressions with one symbolic variable. It can be used for plotting time-domain responses, frequency-domain responses and swept parameter plots.

### plotPZ()

plotPZ() displays X-Y scatter plots. These plots are configured for plotting the results of pole-zero analysis.

### plot()

plot() generates X-Y line plots from a dictionary with traces. Such dictionaries can be generated from data from other applications, such as, LTspice, SImetrix, NGspice, or Cadence, or from `.csv` files.

## Plot settings

Plot settings are found in the [plot] section of the `SLiCAP.ini` file in the project directory. These settings can be changed from within the Python environment.

    >>> import SLiCAP as sl
    >>> sl.ini.dump("plot")

    PLOT
    ----
    ini.gain_colors_gain       = b
    ini.gain_colors_loopgain   = k
    ini.gain_colors_asymptotic = r
    ini.gain_colors_servo      = m
    ini.gain_colors_direct     = g
    ini.gain_colors_vi         = c
    ini.axis_height            = 5
    ini.axis_width             = 7
    ini.line_width             = 2
    ini.line_type              = -
    ini.plot_fontsize          = 12
    ini.marker_size            = 7
    ini.legend_loc             = best
    ini.default_colors         = ['r', 'b', 'g', 'c', 'm', 'y', 'k']
    ini.default_markers        = ['']
    ini.plot_file_type         = svg
    ini.svg_margin             = 1

note

Pole-zero plots are square plots: the axis width is set to the axis height.

### Creating and updating plots

The three built-in plot functions create a figure object. After creation, traces can be added to a plot and the figure objects needs to be updated. The method `figure.plot()` recreates the plot.

### Showing plots

All plot functions have a keyword argument `show=False` by default. In this way they don’t pop up running a script blocking further execution of the script during pop-up.

### Saving plots

All plot functions by default store a `.pdf` graphics file and a graphics file of the type set by `ini.plot_file_type` in the project image folder set by `ini.img_path`:

    >>> import SLiCAP as sl
    >>> sl.ini.dump("paths")

    ini.project_path           = /home/USR/DATA/SLiCAP/SLiCAP_github/SLiCAP_python/docs/
    ini.html_path              = html/
    ini.cir_path               = cir/
    ini.img_path               = img/
    ini.csv_path               = csv/
    ini.txt_path               = txt/
    ini.tex_path               = tex/
    ini.user_lib_path          = lib/
    ini.sphinx_path            = sphinx/
    ini.tex_snippets           = tex/SLiCAPdata/
    ini.html_snippets          = sphinx/SLiCAPdata/
    ini.rst_snippets           = sphinx/SLiCAPdata/
    ini.myst_snippets          = sphinx/SLiCAPdata/
    ini.md_snippets            = sphinx/SLiCAPdata/

Important

Plots are always saved, independent of the value of the keyword argument `show`.

## Frequency-characteristics

    12# Swept variable plots
    13# Laplace analysis
    14laplaceResult = sl.doLaplace(cir, pardefs="circuit", numeric=True)

### Magnitude

    16# Magnitude
    17f_mag = sl.plotSweep("f_mag", "Magnitude plot", laplaceResult, 0.01, 100, 500,
    18                     sweepScale="M", yUnits="V")

### dB Magnitude

    20# dB Magnitude
    21f_dBm = sl.plotSweep("f_dBm", "dB magnitude plot", laplaceResult, 0.01, 100,
    22                     500, sweepScale="M", yUnits="V", funcType="dBmag")

### Phase

    24# Phase
    25f_phs = sl.plotSweep("f_phs", "Phase plot", laplaceResult, 0.01, 100, 500,
    26                     sweepScale="M", yUnits="V", funcType="phase")

### Group delay

    28# Group delay
    29f_del = sl.plotSweep("f_del", "Group delay plot", laplaceResult, 0.01, 100,
    30                     500, sweepScale="M", yUnits="V", yScale="u",
    31                     funcType="delay")

### Polar Magnitude-phase

    33# Magnitude-polar
    34p_mag = sl.plotSweep("p_mag", "Magnitude-phase plot", laplaceResult, 0.01, 100,
    35                     500, axisType="polar", sweepScale="M", yUnits="V")

### Polar dB magnitude-phase

    37# dB magnitude-polar
    38p_dBm = sl.plotSweep("p_dBm", "dB magnitude-phase plot", laplaceResult, 0.01,
    39                     100, 500, axisType="polar", sweepScale="M", yUnits="V",
    40                     funcType="dBmag")

## Time-domain plots

### Unit impulse response

    44# Impulse
    45impulseResp = sl.doImpulse(cir, pardefs="circuit", numeric=True)
    46delta_t = sl.plotSweep("delta_t", "Unit-impulse response", impulseResp,
    47                       0, 5, 500, sweepScale="u", yScale="M")

### Unit Step response

    49# Step
    50stepResp = sl.doStep(cir, pardefs="circuit", numeric=True)
    51mu_t = sl.plotSweep("mu_t", "Unit-step response", stepResp, 0, 5, 500,
    52                     sweepScale="u")

### Time-domain response

    54# Time
    55timeResp = sl.doTime(cir, pardefs="circuit", numeric=True)
    56v_time = sl.plotSweep("v_time", "Time-domain response", timeResp, 0, 5, 500,
    57                      sweepScale="u")

### Periodic pulse response

#### Modify trace data and label

    59# Periodic pulse
    60stepResp.stepResp = sl.step2PeriodicPulse(stepResp.stepResp, 20e-9, 1e-6, 3)
    61stepResp.label    = "3 Pulses response"
    62pp_time = sl.plotSweep("pp_time", "Periodic pulse response", stepResp, 0, 5,
    63                       1000, sweepScale="u")

## Noise spectrum

### Detector-referred noise

    65# Noise spectrum
    66noiseResult  = sl.doNoise(cir, pardefs="circuit", numeric=True)
    67onoise_f     = sl.plotSweep("onoise_f", "Detector-referred noise spectrum",
    68                            noiseResult, 0.01, 100, 500, funcType="onoise",
    69                            sweepScale="M", yUnits="$V^2/Hz$")

### Contributions to detector-referred noise

    71all_onoise_f = sl.plotSweep("all_onoise_f", "Contributions to detector-referred noise",
    72                            noiseResult, 0.01, 100, 500, funcType="onoise",
    73                            sweepScale="M", yUnits="$V^2/Hz$",
    74                            noiseSources="all")

### Source-referred noise

    76inoise_f     = sl.plotSweep("inoise_f", "Source-referred noise spectrum",
    77                            noiseResult, 0.01, 100, 500, funcType="inoise",
    78                            sweepScale="M", yUnits="$V^2/Hz$")

## Swept parameter plots

In the circuit model used for this page the parameter \(C_b\) is defined as a function of the frequency \(f_s\).

This function can be plotted using a swept parameter plot.

    79
    80# Swept parameter plots
    81# Create an instruction result object for plotting
    82parResult = sl.doParams(cir)
    83# Create the swept-parameter plot
    84Cb_fs = sl.plotSweep("Cb_fs", "$C_b$ versus $f_s$", parResult, 1, 5, 100,
    85                     axisType="semilogy", funcType="param", sweepVar="f_s",
    86                     sweepScale="M", xUnits="Hz", yVar="C_b", yScale="n",

## Pole-zero plots

### Poles

    90# Plot the poles
    91polesResult = sl.doPoles(cir, pardefs="circuit", numeric=True)
    92p_plot = sl.plotPZ("p_plot", "Poles", polesResult, xscale="M", yscale="M")

### Zeros

    94# Plot the zeros
    95zerosResult = sl.doZeros(cir, pardefs="circuit", numeric=True)
    96z_plot = sl.plotPZ("z_plot", "Zeros", zerosResult, xscale="M", yscale="M")

### Observable and controllable poles and zeros

     98# Only observable and controllable
     99pzResult = sl.doPZ(cir, pardefs="circuit", numeric=True)
    100pz_plot = sl.plotPZ("pz_plot", "Observable and controllable poles and zeros",
    101                    pzResult, xscale="M", yscale="M", xmin=-11, xmax=1,
    102                    ymin=-6, ymax=6)

## Multiple results in one plot

    104# Multiple results in one plot
    105all_pz = sl.plotPZ("ppzz_plot", "All poles and zeros",
    106                    [polesResult, zerosResult], xscale="M", yscale="M",
    107                    xmin=-11, xmax=1, ymin=-6, ymax=6)

## Parameter stepping

    109# Parameter stepping
    110# Define the step parameters
    111step_dict = {"params": "f_s",
    112             "method": "lin",
    113             "start":  "1M",
    114             "stop":   "5M",
    115             "num": 5}

### Stepped plotSweep()

    117# dB Magnitude stepped
    118laplaceStepped = sl.doLaplace(cir, pardefs="circuit", stepdict=step_dict,
    119                              numeric=True)
    120f_dBmStepped = sl.plotSweep("f_dBmStepped", "dB magnitude plot", laplaceStepped,
    121                            0.01, 100, 500, sweepScale="M", yUnits="V",
    122                            funcType="dBmag")

### Stepped plotPZ(): root locus plots

    124# Root-locus plots
    125pzStepped  = sl.doPZ(cir, pardefs="circuit", stepdict=step_dict,
    126                              numeric=True)
    127pz_stepped = sl.plotPZ("pzStepped", "Stepped PZ plot", pzStepped, xscale="M",
    128                      yscale="M", xmin=-11, xmax=1, ymin=-6, ymax=6)

A stepped pole-zero plot shows:

- The start end en locations of poles as \(\times\) and \(+\), respectively

- For each step value a dot at the pole location

- The start end en locations of zeros as \(\circ\) and \(\square\), respectively

- For each step value a dot at the zero location

### Stepped parameter sweep

    130# Stepped parameter sweep
    131# Define the step parameters
    132step_dict = {"params": "L",
    133             "method": "lin",
    134             "start":  "1u",
    135             "stop":   "5u",
    136             "num": 5}
    137# Create an instruction result object for plotting with parameter stepping
    138parResult = sl.doParams(cir, stepdict=step_dict)
    139Cb_fs_L = sl.plotSweep("Cb_fs_L", "$C_b$ versus $f_s$", parResult, 1, 5, 100,
    140                       axisType="semilogy", funcType="param", sweepVar="f_s",
    141                       sweepScale="M", xUnits="Hz", yVar="C_b", yScale="n",
    142                       yUnits="F")

## Work with traces

### Extract traces from a figure

    144# Extract traces from plots
    145onoise_trace = onoise_f.traceDict

### Add a dictionary with traces to an existing plot

The function traces2fig() adds traces to a figure.

    147# Add onoise_trace to a copy of all_onoise_f
    148# Create a deepcopy of the figure
    149all_oonoise_f = deepcopy(all_onoise_f)
    150# Change the file name so we don't overwrite the original
    151all_oonoise_f.fileName = "all_onoise"
    152# Add the onoise trace to the new figure
    153sl.traces2fig(onoise_trace, all_oonoise_f)
    154# Don't show it, just save the figure
    155all_oonoise_f.show = False
    156# Generate and save the figure
    157all_oonoise_f.plot()

### Create and plot a dictionary with traces

    159# Create traces
    160x        = np.linspace(-1, 1, 100)
    161
    162y1       = sl.trace([x, x])
    163y1.label = "$y=x$"
    164
    165y2       = sl.trace([x, x**2])
    166y2.label = "$y=x^2$"
    167
    168y3       = sl.trace([x, x**3])
    169y3.label = "$y=x^3$"
    170
    171y4       = sl.trace([x, x**4])
    172y4.label = "$y=x^4$"
    173
    174trc_dict = {"y1": y1, "y2": y2, "y3": y3, "y4": y4}
    175
    176# Plot a dictionary with traces
    177
    178pwrs_x   = sl.plot("powers_x", "Powers of $x$", "lin", trc_dict,
    179                   xName = "x", yName="y")