diff --git a/Accordion_Plugin.md b/Accordion_Plugin.md new file mode 100644 index 0000000..047d161 --- /dev/null +++ b/Accordion_Plugin.md @@ -0,0 +1,214 @@ +# Accordion Plugin + +The `AccordionPlugin` adds a resizable band or region selection to your SigPlot plots. +Unlike paired sliders, an accordion is a single control with a center line and two edges +that can be dragged to adjust the width of the selection. Accordions are commonly used +to select frequency bands, time windows, or amplitude ranges. + +## Creating a Vertical Accordion + +To add an accordion, create an `AccordionPlugin` instance and add it to the plot. Use +`set_center` and `set_width` to position and size it in real units. By default, the +accordion is vertical and shades the selected region. + +```javascript +var accordion = new sigplot.plugins.AccordionPlugin({ + direction: "vertical", + shade_area: true +}); +plot.add_plugin(accordion); +accordion.set_center(500); +accordion.set_width(100); +``` + +```html +/*vue*/ + +A sine wave with a vertical accordion selecting a frequency band + + + + + + + +``` + +## Horizontal Accordion + +A horizontal accordion selects a range along the y-axis. This is useful for marking +amplitude thresholds or selecting a value band on a plot. Set the `direction` option +to `"horizontal"` and use `set_center` and `set_width` to control its position. + +```javascript +var accordion = new sigplot.plugins.AccordionPlugin({ + direction: "horizontal", + shade_area: true, + draw_center_line: true, + draw_edge_lines: true +}); +plot.add_plugin(accordion); +accordion.set_center(0); +accordion.set_width(0.5); +``` + +```html +/*vue*/ + +A sine wave with a horizontal accordion selecting an amplitude range + + + + + + + +``` + +## Constrained Accordion + +You can constrain the minimum and maximum width of an accordion using `min_width` and +`max_width`. You can also prevent the user from moving or resizing it using +`prevent_move` and `prevent_resize`. This is useful when you want to allow adjustment +within certain bounds. + +```javascript +var accordion = new sigplot.plugins.AccordionPlugin({ + direction: "vertical", + shade_area: true, + min_width: 50, + max_width: 300 +}); +plot.add_plugin(accordion); +accordion.set_center(512); +accordion.set_width(100); +``` + +```html +/*vue*/ + +Accordion constrained to a minimum width of 50 and maximum width of 300 + + + + + + + +``` diff --git a/Annotations_Plugin.md b/Annotations_Plugin.md new file mode 100644 index 0000000..bfba8d4 --- /dev/null +++ b/Annotations_Plugin.md @@ -0,0 +1,279 @@ +# Annotations Plugin + +The `AnnotationPlugin` lets you add text labels, images, or other HTML elements to +specific positions on a SigPlot plot. Annotations are placed in real plot coordinates +and move with the data when the plot is zoomed or panned. They can also respond to +hover and click events. + +## Adding Text Annotations + +To annotate a plot, create an `AnnotationPlugin` instance, add it to the plot, and call +`add_annotation` with an object describing the position and content. The `x` and `y` +values are in real plot units, and `value` is the text to display. + +```javascript +var annot = new sigplot.plugins.AnnotationPlugin(); +plot.add_plugin(annot); + +annot.add_annotation({ + x: 256, + y: 1.0, + value: "Peak", + color: "red", + font: "bold 16px Arial" +}); +``` + +```html +/*vue*/ + +A sine wave with text annotations marking peaks and troughs + + + + + + + +``` + +## Annotations with Popups + +Annotations can display a popup with additional detail when the user hovers over them. +Set the `popup` property to a string and the `highlight_color` property to change the +annotation color on hover. + +```javascript +annot.add_annotation({ + x: 512, + y: 0.8, + value: "★", + color: "yellow", + font: "bold 20px Arial", + highlight_color: "orange", + popup: "This is a point of interest at sample 512" +}); +``` + +```html +/*vue*/ + +Annotations with popup text shown on hover + + + + + + + +``` + +## Clickable Annotations + +Annotations can respond to click events via the `onclick` callback. This is useful for +building interactive plots where clicking on a label opens details, navigates to another +view, or triggers an action. + +```javascript +annot.add_annotation({ + x: 256, + y: 1.0, + value: "Click Me", + color: "lime", + font: "bold 16px Arial", + onclick: function() { + alert("You clicked the annotation at sample 256!"); + } +}); +``` + +```html +/*vue*/ + +Clickable annotations that display information when clicked + + + + + + + +``` diff --git a/Basic_IQ_Plots.md b/Basic_IQ_Plots.md new file mode 100644 index 0000000..e033e36 --- /dev/null +++ b/Basic_IQ_Plots.md @@ -0,0 +1,198 @@ +# Basic I/Q Plots + +I/Q (In-phase/Quadrature) data is a common representation of complex signals used in +signal processing and software-defined radio. The data consists of interleaved real (I) +and imaginary (Q) pairs: `[I0, Q0, I1, Q1, I2, Q2, ...]`. A complex sinusoid, for example, +is represented as cosine values for the I component and sine values for the Q component. + +To plot I/Q data in SigPlot, you use `overlay_array` with the `format` field set to `"CF"` +(complex float) in the data header. This tells SigPlot that the array contains interleaved +I,Q pairs. + +First, let's generate a simple complex sinusoid: + +```javascript +var data = []; +var npts = 1024; +var freq = 0.1; +for (var i = 0; i < npts; i++) { + data.push(Math.cos(2 * Math.PI * freq * i)); // real/I + data.push(Math.sin(2 * Math.PI * freq * i)); // imaginary/Q +} +``` + +By default, SigPlot will display complex data as magnitude. The `cmode` plot option controls +how complex data is displayed: + +| cmode | Display Mode | +|-------|-------------| +| 1 | Magnitude (Mag) | +| 2 | Phase | +| 3 | Real | +| 4 | Imaginary | +| 5 | Imaginary vs Real | +| 6 | Magnitude (20·log10) | +| 7 | Magnitude (10·log10) | + +Here is our complex sinusoid plotted as magnitude (the default): + +```html +/*vue*/ + +I/Q Data - Magnitude (Default) + + + + + + + +``` + +Since our signal is a pure complex sinusoid with unit amplitude, the magnitude is a constant +value of 1.0 across all samples. To see the actual waveform shape, we can use `cmode: 3` +to display just the real (I) part of the data. + +```javascript +var plot = new sigplot.Plot(document.getElementById('plot2'), { + autohide_readout: true, + autohide_panbars: true, + no_legend_button: true, + legend: true, + cmode: 3 // display real part +}); +``` + +```html +/*vue*/ + +I/Q Data - Real Part (cmode 3) + + + + + + + +``` + +Now you can see the cosine waveform of the real component. + +Finally, `cmode: 5` plots Imaginary vs Real, which produces a constellation-like display. +For a pure complex sinusoid, this traces out a circle. This view is commonly used in +communications to visualize signal modulation (e.g., QPSK, QAM constellations). + +```javascript +var plot = new sigplot.Plot(document.getElementById('plot3'), { + autohide_readout: true, + autohide_panbars: true, + no_legend_button: true, + legend: true, + cmode: 5 // Imaginary vs Real +}); +``` + +```html +/*vue*/ + +I/Q Data - Imaginary vs Real (cmode 5) + + + + + + + +``` diff --git a/Basic_Raster_Plots.md b/Basic_Raster_Plots.md index fa3acd6..0362ad5 100644 --- a/Basic_Raster_Plots.md +++ b/Basic_Raster_Plots.md @@ -1,26 +1,11 @@ -# Basic Line Plots +# Basic Raster Plots -A simple raster plot (also known as Layer2D) is created from a series of values where -each value is separated by a constant delta. For example, if you measured the temperatue -in a room every hour from 9AM to 9PM, you would have a list of values like this: +A raster plot (also known as Layer2D) displays two-dimensional data as a grid of colored +cells, similar to a heatmap or spectrogram. Each value in the data is mapped to a color +based on its magnitude. Raster plots are commonly used in signal processing to visualize +spectrograms, waterfall displays, or any data that has two independent axes. -``` -[70.3, 71.1, 71.7, 72.3, 72.1, 72.2, 72.0, 71.6, 71.1, 71.2, 71.4, 71.7] -``` - -If you wanted to plot these in SigPlot, you would use the `overlay_array` method. - - -```javascript -plot.overlay_array(data, { - xstart: 32400, - xdelta: 3600, - xunits: "Time code format", - yunits: ["Temperature", "F"] -}); -``` - -The simplest way to plot a raster is by passing a 2D array to `overlay_array`. Below is our basic raster +The simplest way to create a raster is by passing a 2D array to `overlay_array`. Below is our basic raster plot. ```html @@ -59,21 +44,27 @@ SigPlot Basic Raster Plot ``` -Alternatively, you can plot rasters by providing a `subsize` parameter. +Alternatively, you can plot rasters by providing a flat array with a `subsize` parameter. The `subsize` +tells SigPlot how many values make up each row of the raster. ```javascript -var plot = new sigplot.Plot(document.getElementById('plot'), { - autohide_readout: true, // only show readout when mouse is over plot - autohide_panbars: true, // only show panbars if the plot has been zoomed - no_legend_button: true, // turn of the legend button in the upper right - legend: true // show a legend by default (can be toggled by pressing 'L') -}); +var data = [ + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, +]; +plot.overlay_array(data, { subsize: 5 }); ``` +We will also clean up the plot by enabling auto-hiding of extra UI elements. + ```html /*vue*/ -SigPlot Basic Line Plot With Improved Looks +SigPlot Basic Raster Plot With Subsize + + + + +``` + +## Multiple Colored Regions + +You can add multiple boxes to a single plot to mark different regions. Each box can have +its own color and style, making it easy to visually distinguish between areas like signal +bands, noise floors, and guard bands. + +```javascript +boxesPlugin.add_box({ + x: 0, y: -1.2, w: 200, h: 2.4, + fillStyle: "rgba(0, 128, 255, 0.2)", + strokeStyle: "dodgerblue", fill: true +}); +boxesPlugin.add_box({ + x: 400, y: -1.2, w: 200, h: 2.4, + fillStyle: "rgba(255, 0, 0, 0.2)", + strokeStyle: "red", fill: true +}); +boxesPlugin.add_box({ + x: 800, y: -1.2, w: 200, h: 2.4, + fillStyle: "rgba(0, 200, 0, 0.2)", + strokeStyle: "limegreen", fill: true +}); +``` + +```html +/*vue*/ + +Multiple colored boxes marking Signal, Noise, and Guard Band regions + + + + + + + +``` + +## Boxes with Labels + +Boxes support a `text` property that renders a label inside the box. Use the `font` +property to control the text style. This is useful for labeling regions directly on +the plot without needing a separate annotation plugin. + +```javascript +boxesPlugin.add_box({ + x: 200, + y: -0.5, + w: 100, + h: 1.0, + fillStyle: "rgba(255, 165, 0, 0.3)", + strokeStyle: "orange", + fill: true, + text: "Region of Interest", + font: "bold 14px Arial" +}); +``` + +```html +/*vue*/ + +Labeled boxes marking different regions on a sine wave + + + + + + + +``` diff --git a/Changing_Settings.md b/Changing_Settings.md new file mode 100644 index 0000000..594fe41 --- /dev/null +++ b/Changing_Settings.md @@ -0,0 +1,291 @@ +# Changing Settings + +SigPlot allows you to change plot settings at runtime using the `change_settings` method. +This is useful for building interactive controls that let users customize the plot +appearance without recreating it. + +## Changing Colors + +You can change the foreground and background colors of a plot by passing `fg` and `bg` +properties to `change_settings`. This immediately redraws the plot with the new colors. + +```javascript +// Switch to a light theme +plot.change_settings({ bg: "#FFFFFF", fg: "#000000" }); + +// Switch to a dark theme +plot.change_settings({ bg: "#000000", fg: "#00FF00" }); +``` + +In this example, buttons let you switch between different color themes. + +```html +/*vue*/ + +Use the buttons to change the plot color theme + + + + + + + +``` + +## Changing Colormaps on Raster Plots + +For raster plots, the `cmap` setting controls the colormap used to render data. SigPlot +ships with several built-in colormaps. You can switch between them dynamically to +find the best visualization for your data. + +| Index | Colormap | +|-------|---------------| +| 0 | Greyscale | +| 1 | Ramp Colormap | +| 2 | Color Wheel | +| 3 | Spectrum | +| 4 | CaleWhite | +| 5 | HotDesat | + +```javascript +// Switch to the Spectrum colormap +plot.change_settings({ cmap: 3 }); +``` + +```html +/*vue*/ + +Use the buttons to change the raster plot colormap + + + + + + + +``` + +## Toggling Crosshairs, Legend, and Grid + +Several display features can be toggled on or off at runtime via `change_settings`. + +```javascript +// Toggle crosshairs: 0=off, 1=vertical, 2=horizontal, 3=both +plot.change_settings({ xcnt: 3 }); + +// Show or hide the legend +plot.change_settings({ legend: true }); + +// Show or hide the grid +plot.change_settings({ grid: true }); +``` + +In this example, buttons let you toggle crosshairs, the legend, and the grid. + +```html +/*vue*/ + +Toggle crosshairs, legend, and grid with the buttons below + + + + + + + +``` + +## Settings Reference + +| Setting | Type | Description | +|-----------|---------------|--------------------------------------------------| +| `bg` | String | Background color (e.g. `"#000000"`) | +| `fg` | String | Foreground color (e.g. `"#FFFFFF"`) | +| `cmap` | Number | Colormap index for raster plots (0–5+) | +| `autol` | Number | Auto-level for raster plots (0=off, 1–100=level) | +| `xcnt` | Number | Crosshair mode (0=off, 1=vert, 2=horiz, 3=both) | +| `legend` | Boolean | Show or hide the legend | +| `grid` | Boolean | Show or hide the grid | +| `xlab` | String/Number | X-axis label | +| `ylab` | String/Number | Y-axis label | diff --git a/Menu.md b/Menu.md new file mode 100644 index 0000000..c035ded --- /dev/null +++ b/Menu.md @@ -0,0 +1,216 @@ +# Menu + +SigPlot includes a built-in context menu and a comprehensive set of keyboard shortcuts +that give users quick access to common plot operations. + +## Right-Click Context Menu + +Right-clicking on a SigPlot plot opens a context menu with options for controlling the +display. The menu includes sections for: + +- **Zoom** — zoom in, unzoom, or full unzoom +- **Scaling** — adjust x-axis and y-axis scaling modes (linear, log, etc.) +- **Grid** — toggle the grid overlay +- **Crosshairs** — enable or change crosshair modes +- **Legend** — show or hide the legend +- **Traces** — show, hide, or modify individual data layers + +Try right-clicking on the plot below to explore the available menu options. + +```html +/*vue*/ + +Right-click on the plot to open the context menu + + + + + + + +``` + +## Keyboard Shortcuts + +SigPlot provides keyboard shortcuts for the most common operations. These work whenever +the mouse is over the plot. + +| Key | Action | +|-----|-----------------------------------------------------| +| `M` | Unzoom one level | +| `F` | Full unzoom (return to original view) | +| `L` | Toggle the legend on/off | +| `G` | Toggle the grid overlay on/off | +| `X` | Toggle crosshairs | +| `T` | Toggle traces (show/hide data layers) | +| `C` | Toggle continuous scrolling (raster plots) | +| `Y` | Auto-scale the y-axis | +| `A` | Auto-scale the y-axis (same as Y) | + +Try using these shortcuts on the plot below. Press `L` to toggle the legend, `G` for the +grid, or `X` to turn on crosshairs. + +```html +/*vue*/ + +Try keyboard shortcuts: L=legend, G=grid, X=crosshairs, M=unzoom + + + + + + + +``` + +## The Menu Event + +You can listen for the `showmenu` event to detect when the user opens the context menu. +This can be useful for analytics, or for customizing behavior when the menu is shown. + +```javascript +plot.addListener("showmenu", function(evt) { + console.log("Context menu opened"); +}); +``` + +## Menu on Raster Plots + +Raster plots have additional menu options beyond what line plots offer. These include +colormap selection, auto-leveling controls, and continuous scrolling mode. + +Try right-clicking on the raster plot below to see the additional options available for +2D data. + +```html +/*vue*/ + +Right-click on this raster plot to see additional menu options for 2D data + + + + + + + +``` + +## Quick Reference + +| Feature | How to Access | +|------------------|----------------------------------------| +| Context menu | Right-click on the plot | +| Zoom in | Left-click and drag, or use menu | +| Unzoom | Press `M`, middle-click, or use menu | +| Full unzoom | Press `F` or use menu | +| Toggle legend | Press `L` or use menu | +| Toggle grid | Press `G` or use menu | +| Toggle crosshairs| Press `X` or use menu | +| Auto-scale Y | Press `Y` or `A` | +| Toggle traces | Press `T` | +| Continuous scroll| Press `C` (raster plots only) | diff --git a/Mouse_Events.md b/Mouse_Events.md new file mode 100644 index 0000000..3f1af3c --- /dev/null +++ b/Mouse_Events.md @@ -0,0 +1,267 @@ +# Mouse Events + +SigPlot provides a powerful event system that allows you to respond to mouse interactions +on the plot. You can listen for clicks, mouse movement, and other events using the +`addListener` method. + +## Listening for Clicks with `mtag` + +The most common mouse event is `mtag`, which fires when the user clicks on the plot. The +event callback receives an object with both real-world coordinates (`x`, `y`) and pixel +coordinates (`xpos`, `ypos`). + +```javascript +plot.addListener("mtag", function(evt) { + console.log("Clicked at x=" + evt.x + ", y=" + evt.y); + console.log("Pixel position: " + evt.xpos + ", " + evt.ypos); +}); +``` + +In this first example, we plot a sine wave and display the clicked coordinates in a +status area below the plot. Try clicking on different parts of the plot. + +```html +/*vue*/ + +Click on the plot to see real-world coordinates + + + + + + + +``` + +## Real-Time Mouse Tracking with `mmove` + +The `mmove` event fires continuously as the mouse moves over the plot. This is useful +for building real-time coordinate displays or crosshair-style overlays. + +```javascript +plot.addListener("mmove", function(evt) { + // evt.x and evt.y are real-world coordinates + // evt.xpos and evt.ypos are pixel coordinates +}); +``` + +In this example, the status area updates in real time as you move the mouse. + +```html +/*vue*/ + +Move the mouse over the plot to track coordinates in real time + + + + + + + +``` + +## Marking Points on Click + +You can combine mouse events with plot operations to create interactive experiences. +In this example, each time you click on the plot, a new annotation layer is added +at that position, visually marking where you clicked. We use `overlay_array` to add a +short vertical impulse at each clicked x-position. + +```javascript +plot.addListener("mtag", function(evt) { + // Add a vertical marker at the clicked x position + plot.overlay_array([evt.y], { + xstart: evt.x, + xdelta: 1 + }, { + color: "red", + symbol: 6, + radius: 5, + name: "Marker" + }); +}); +``` + +```html +/*vue*/ + +Click on the plot to place markers at those positions + + + + + + + +``` + +## Removing Listeners + +When you no longer need to listen for an event, you can remove the listener with +`removeListener`. Be sure to keep a reference to the callback function so you can +pass it to `removeListener`. + +```javascript +var myCallback = function(evt) { + console.log("Clicked at x=" + evt.x); +}; + +// Add the listener +plot.addListener("mtag", myCallback); + +// Later, remove it +plot.removeListener("mtag", myCallback); +``` + +## Event Reference + +| Event | Description | +|--------------|------------------------------------------------| +| `mtag` | Fired when the user clicks on the plot | +| `mmove` | Fired as the mouse moves over the plot | +| `mdown` | Fired when a mouse button is pressed | +| `mup` | Fired when a mouse button is released | +| `mclick` | Fired on a mouse click | +| `showmenu` | Fired when the right-click menu is shown | +| `sigplotexit`| Fired when a zoom box selection is completed | diff --git a/Playback_Plugin.md b/Playback_Plugin.md new file mode 100644 index 0000000..fbfc19f --- /dev/null +++ b/Playback_Plugin.md @@ -0,0 +1,187 @@ +# Playback Controls Plugin + +The `PlaybackControlsPlugin` adds a play/pause button to a SigPlot plot. This is +especially useful for streaming or animated plots where you want to give the user +control over whether data continues to flow. Clicking the button toggles between +`"playing"` and `"paused"` states. + +## Streaming Plot with Playback Controls + +In this example we create a streaming pipe plot that pushes a new row of data at +regular intervals. A `PlaybackControlsPlugin` is added so the user can pause and +resume the data stream. We listen for the `"playbackevt"` event to know when the +state changes. + +```javascript +var playback = new sigplot.plugins.PlaybackControlsPlugin({ + size: 30, + strokeStyle: "white" +}); +plot.add_plugin(playback); + +var playing = true; +playback.addListener("playbackevt", function(evt) { + playing = (evt.state === "playing"); +}); + +var pipe = plot.overlay_pipe({ type: 2000, subsize: 1024 }); +setInterval(function() { + if (!playing) return; + var data = []; + for (var i = 0; i < 1024; i++) { + data.push(Math.random()); + } + plot.push(pipe, data); +}, 100); +``` + +```html +/*vue*/ + +A streaming raster plot with play/pause controls + + + + + + + +``` + +## Custom-Styled Playback Button + +You can customize the appearance of the playback button by setting `size`, `strokeStyle`, +`fillStyle`, and `lineWidth`. You can also position the button at a specific location +using the `position` option. + +```javascript +var playback = new sigplot.plugins.PlaybackControlsPlugin({ + size: 40, + strokeStyle: "cyan", + fillStyle: "rgba(0, 255, 255, 0.2)", + lineWidth: 3 +}); +plot.add_plugin(playback); +``` + +```html +/*vue*/ + +A streaming plot with a custom-styled playback button + + + + + + + +``` diff --git a/Plotting_Audio_Buffers.md b/Plotting_Audio_Buffers.md new file mode 100644 index 0000000..f3c360e --- /dev/null +++ b/Plotting_Audio_Buffers.md @@ -0,0 +1,302 @@ +# Plotting Audio Buffers + +SigPlot is well suited for visualizing audio data in real-time. The Web Audio API +provides access to microphone input and audio file decoding, producing `Float32Array` +buffers that can be plotted directly with SigPlot. + +## Web Audio API Basics + +The Web Audio API uses an `AudioContext` to manage audio processing. Audio data flows +through a graph of nodes — sources, processors, and destinations. To visualize audio, +you tap into this graph and feed the sample buffers to SigPlot. + +```javascript +var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); +var analyser = audioCtx.createAnalyser(); +analyser.fftSize = 2048; +``` + +## Plotting a Synthetic Audio Signal + +Before dealing with real microphone input, let's generate a synthetic 440 Hz tone +(the standard A4 pitch) at a 44,100 Hz sample rate and plot a 50 ms window of it. +This demonstrates the waveform shape you would see from a real audio source. + +```javascript +var sampleRate = 44100; +var duration = 0.05; // 50ms +var freq = 440; // A4 +var npts = Math.floor(sampleRate * duration); +var data = []; +for (var i = 0; i < npts; i++) { + data.push(Math.sin(2 * Math.PI * freq * i / sampleRate)); +} +plot.overlay_array(data, { + xstart: 0, + xdelta: 1.0 / sampleRate, + xunits: 1, // Time (sec) + yunits: 20 // Amplitude +}); +``` + +The `xdelta` of `1 / 44100` tells SigPlot that each sample is separated by one sample +period, so the x-axis displays time in seconds. + +```html +/*vue*/ + +Synthetic 440 Hz Tone (50 ms window) + + + + + + + +``` + +## Plotting a Multi-Tone Signal + +Real audio signals contain many frequencies. Here we combine a 440 Hz tone with a +880 Hz harmonic to create a more complex waveform. + +```javascript +for (var i = 0; i < npts; i++) { + data.push( + 0.7 * Math.sin(2 * Math.PI * 440 * i / sampleRate) + + 0.3 * Math.sin(2 * Math.PI * 880 * i / sampleRate) + ); +} +``` + +```html +/*vue*/ + +Multi-Tone Audio Signal (440 Hz + 880 Hz) + + + + + + + +``` + +## Streaming Audio with overlay_pipe + +For real-time audio visualization, you need to continuously push new buffers into +SigPlot. The `overlay_pipe` method creates a streaming layer that accepts new data +as it arrives. This is ideal for microphone input or live audio streams. + +First, create a pipe with parameters matching your audio source: + +```javascript +var pipe = plot.overlay_pipe({ + type: 1000, // 1D data + subsize: 2048, // samples per buffer + xstart: 0, + xdelta: 1.0 / 44100, + xunits: 1 // Time (sec) +}); +``` + +Then push data into the pipe whenever a new audio buffer is available: + +```javascript +plot.push(pipe, data); +``` + +Below is a simulation that generates and pushes new buffers on a timer, mimicking +the behavior of a real audio source. Each buffer contains a 440 Hz tone with added +noise. + +```html +/*vue*/ + +Streaming Audio Pipe (Simulated) + + + + + + + +``` + +## Connecting to the Web Audio API + +In a real application, you would connect SigPlot to actual audio hardware. There are +two common approaches: + +### Using ScriptProcessorNode (deprecated but widely supported) + +```javascript +var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + +navigator.mediaDevices.getUserMedia({ audio: true }).then(function(stream) { + var source = audioCtx.createMediaStreamSource(stream); + var processor = audioCtx.createScriptProcessor(2048, 1, 1); + + var pipe = plot.overlay_pipe({ + type: 1000, + subsize: 2048, + xstart: 0, + xdelta: 1.0 / audioCtx.sampleRate, + xunits: 1 + }); + + processor.onaudioprocess = function(event) { + var audioData = event.inputBuffer.getChannelData(0); + plot.push(pipe, audioData); + }; + + source.connect(processor); + processor.connect(audioCtx.destination); +}); +``` + +### Using AnalyserNode for Frequency Domain + +The `AnalyserNode` provides frequency-domain data via FFT, which is useful for +spectrum displays: + +```javascript +var analyser = audioCtx.createAnalyser(); +analyser.fftSize = 2048; +source.connect(analyser); + +var pipe = plot.overlay_pipe({ + type: 1000, + subsize: analyser.frequencyBinCount, + xstart: 0, + xdelta: audioCtx.sampleRate / analyser.fftSize, + xunits: 3 // Frequency (Hz) +}); + +var dataArray = new Float32Array(analyser.frequencyBinCount); +function draw() { + analyser.getFloatFrequencyData(dataArray); + plot.push(pipe, dataArray); + requestAnimationFrame(draw); +} +draw(); +``` + +> **Note:** The examples above require microphone access and will prompt the user +> for permission. They cannot run inside this documentation but serve as templates +> for your own applications. diff --git a/Plotting_Blue_Files.md b/Plotting_Blue_Files.md new file mode 100644 index 0000000..c798185 --- /dev/null +++ b/Plotting_Blue_Files.md @@ -0,0 +1,283 @@ +# Plotting BLUE Files + +BLUE files (also known as Platinum files) are a binary data format widely used in +signal processing and software-defined radio. SigPlot has native support for BLUE +files — it can read the embedded header to automatically determine data type, sample +rate, units, and more. + +## What Is a BLUE File? + +A BLUE file consists of two parts: + +1. **Header** (512 bytes) — contains metadata such as data type, number of points, + sample delta, start value, and units +2. **Data** — the raw binary samples immediately following the header + +Because the header carries all the metadata, SigPlot can plot a BLUE file with a +single call and no additional options. + +## Loading a BLUE File + +The simplest way to plot a BLUE file is with `overlay_href`. SigPlot reads the +header automatically. + +```javascript +plot.overlay_href("path/to/file.tmp"); +``` + +You can also pass layer options to customize the display: + +```javascript +plot.overlay_href("path/to/file.tmp", null, { + color: "red", + name: "My Signal" +}); +``` + +> **Note:** `overlay_href` loads files via HTTP, so the file must be served by a web +> server. You cannot load local filesystem paths directly in a browser. + +## Simulating a Type 1000 (1D) BLUE File + +Type 1000 BLUE files contain one-dimensional data and are displayed as line plots. +Below we use `overlay_array` to demonstrate what a loaded BLUE file looks like. +The data represents a chirp signal — a sine wave whose frequency increases over time. + +```javascript +var npts = 1024; +var data = new Float32Array(npts); +for (var i = 0; i < npts; i++) { + var t = i / npts; + data[i] = Math.sin(2 * Math.PI * (10 + 200 * t) * t); +} +plot.overlay_array(data, { + xstart: 0, + xdelta: 1.0 / 1024 +}); +``` + +```html +/*vue*/ + +Type 1000 BLUE File (1D Chirp Signal) + + + + + + + +``` + +## Loading Multiple BLUE Files + +You can overlay multiple BLUE files on the same plot. Each call to `overlay_href` +returns the layer index, which you can use later to remove or modify the layer. + +```javascript +var layer1 = plot.overlay_href("signal_a.tmp", null, { + color: "cyan", + name: "Signal A" +}); +var layer2 = plot.overlay_href("signal_b.tmp", null, { + color: "yellow", + name: "Signal B" +}); +``` + +To remove a layer: + +```javascript +plot.deoverlay(layer1); // remove a specific layer +plot.deoverlay(); // remove all layers +``` + +Below we simulate two overlaid BLUE files using `overlay_array`: + +```html +/*vue*/ + +Multiple Overlaid BLUE Files + + + + + + + +``` + +## Type 2000 (2D) BLUE Files — Raster Plots + +Type 2000 BLUE files contain two-dimensional data and are displayed as raster +(waterfall) plots. Each row of the raster represents one frame of data. Below +we simulate a Type 2000 file by generating a 2D dataset. + +```html +/*vue*/ + +Type 2000 BLUE File (2D Raster) + + + + + + + +``` + +## Overriding Header Values with headermod + +Sometimes you need to override values in a BLUE file's header without modifying the +file itself. The `headermod` option lets you do this: + +```javascript +plot.overlay_href("file.tmp", null, { + headermod: { + xstart: 100, // override the start value + xdelta: 0.002, // override the sample delta + xunits: 3 // override units to Frequency (Hz) + } +}); +``` + +This is useful when you have a file whose header contains default or placeholder +values that need adjustment for your display. + +## BLUE File Type Codes Reference + +| Type Code | Description | Plot Type | +|---|---|---| +| 1000 | 1D scalar data | Line plot | +| 1001 | 1D complex data | Line plot (I/Q) | +| 2000 | 2D scalar data | Raster plot | +| 2001 | 2D complex data | Raster plot (I/Q) | + +## BLUE File Data Format Codes + +The data format in a BLUE header specifies how the binary samples are stored: + +| Format | Description | Bytes per Element | +|---|---|---| +| SF | Scalar Float (32-bit) | 4 | +| SD | Scalar Double (64-bit) | 8 | +| SI | Scalar Integer (16-bit) | 2 | +| SL | Scalar Long (32-bit int) | 4 | +| SB | Scalar Byte (8-bit) | 1 | +| CF | Complex Float (32-bit per component) | 8 | +| CD | Complex Double (64-bit per component) | 16 | diff --git a/Plotting_Matlab_Files.md b/Plotting_Matlab_Files.md new file mode 100644 index 0000000..11d3697 --- /dev/null +++ b/Plotting_Matlab_Files.md @@ -0,0 +1,257 @@ +# Plotting MATLAB Files + +SigPlot does not natively load `.mat` files, but there are several straightforward +ways to get MATLAB data into SigPlot. This tutorial covers the most common approaches. + +## Approach 1: Export Data as JSON from MATLAB + +The simplest approach is to export your data as JSON in MATLAB and then load it in +JavaScript. + +In MATLAB: +```matlab +x = linspace(0, 2*pi, 256); +y = sin(x) .* exp(-x/5); +json_str = jsonencode(y); +fid = fopen('signal.json', 'w'); +fprintf(fid, '%s', json_str); +fclose(fid); +``` + +In JavaScript, you would fetch and parse the JSON, then pass the array to SigPlot. +Below we simulate this by using inline data that represents the output of +`jsonencode()`. + +```javascript +// Data that would come from MATLAB's jsonencode() +var matlabData = [...]; // array of numbers +plot.overlay_array(matlabData, { + xstart: 0, + xdelta: 2 * Math.PI / 256 +}); +``` + +```html +/*vue*/ + +Simulated MATLAB JSON Export (Damped Sine) + + + + + + + +``` + +## Fetching a JSON File at Runtime + +In a real application, you would fetch the JSON file from your server: + +```javascript +fetch("signal.json") + .then(function(response) { return response.json(); }) + .then(function(data) { + plot.overlay_array(data, { + xstart: 0, + xdelta: 0.001 + }); + }); +``` + +## Approach 2: Export as Raw Binary from MATLAB + +For large datasets, binary files are more efficient than JSON. In MATLAB, you can +write raw binary data: + +```matlab +y = sin(linspace(0, 4*pi, 1024)); +fid = fopen('signal.raw', 'w'); +fwrite(fid, y, 'float32'); +fclose(fid); +``` + +Then load the binary file in SigPlot using `overlay_href`. You must specify the data +format since a raw file has no header. + +```javascript +plot.overlay_href("signal.raw", null, { + format: "SF", // Scalar Float (32-bit) + xstart: 0, + xdelta: 4 * Math.PI / 1024 +}); +``` + +Below we simulate this result using `overlay_array`: + +```html +/*vue*/ + +Simulated MATLAB Raw Binary Export + + + + + + + +``` + +## Approach 3: Convert .mat to BLUE Format + +The BLUE (or Platinum) file format is natively supported by SigPlot. If you have +access to the MIDAS toolset or compatible utilities, you can convert `.mat` files to +BLUE format. + +In MATLAB with the appropriate toolbox: +```matlab +% Using MIDAS M-file utilities +y = sin(linspace(0, 2*pi, 512)); +write_bluefile('signal.tmp', y, 'xdelta', 0.001, 'xstart', 0); +``` + +Once converted, loading in SigPlot is straightforward because BLUE files contain +their own header metadata: + +```javascript +plot.overlay_href("signal.tmp"); +``` + +## Plotting Multiple MATLAB Variables + +A common MATLAB workflow involves exporting multiple variables. You can overlay them +on the same SigPlot instance to compare signals. + +```javascript +plot.overlay_array(signal1, { xdelta: 0.001 }, { name: "Channel 1", color: "red" }); +plot.overlay_array(signal2, { xdelta: 0.001 }, { name: "Channel 2", color: "blue" }); +``` + +```html +/*vue*/ + +Multiple MATLAB Signals Overlaid + + + + + + + +``` + +## Summary of Approaches + +| Approach | MATLAB Command | JavaScript Load Method | Best For | +|---|---|---|---| +| JSON export | `jsonencode()` + `fprintf()` | `fetch()` → `overlay_array()` | Small to medium datasets | +| Raw binary | `fwrite(fid, y, 'float32')` | `overlay_href()` with format | Large datasets | +| BLUE conversion | `write_bluefile()` | `overlay_href()` | Full metadata preservation | diff --git a/Plotting_Raw_Files.md b/Plotting_Raw_Files.md new file mode 100644 index 0000000..0b8de47 --- /dev/null +++ b/Plotting_Raw_Files.md @@ -0,0 +1,278 @@ +# Plotting Raw Files + +Raw binary files contain only data — no header, no metadata. To plot a raw file in +SigPlot, you must tell it the data format, sample spacing, and any other parameters +that would normally come from a file header. + +## Loading a Raw File with overlay_href + +Use `overlay_href` with the `format` option to specify the binary data type: + +```javascript +plot.overlay_href("path/to/raw_data.bin", null, { + format: "SF", // Scalar Float (32-bit) + xstart: 0, + xdelta: 0.001 // 1 ms between samples +}); +``` + +Without the `format` parameter, SigPlot would try to interpret the file as a BLUE +file and read the first 512 bytes as a header, which would produce incorrect results. + +## Plotting a Simulated Raw File + +Below we generate a test signal — a noisy sine wave — and plot it using `overlay_array`. +This is equivalent to what you would see after loading a raw binary file containing +32-bit float samples. + +```javascript +var npts = 2048; +var data = new Float32Array(npts); +for (var i = 0; i < npts; i++) { + data[i] = Math.sin(2 * Math.PI * 10 * i / npts); + data[i] += (Math.random() - 0.5) * 0.3; +} +plot.overlay_array(data, { + xstart: 0, + xdelta: 0.001 +}); +``` + +```html +/*vue*/ + +Simulated Raw Float Data (Noisy Sine) + + + + + + + +``` + +## Loading Raw Data with the Fetch API + +If you have a raw binary file on a server, you can use the Fetch API to download it +as an `ArrayBuffer`, create the appropriate typed array, and then pass it to SigPlot. +This gives you full control over how the binary data is interpreted. + +```javascript +fetch("data.bin") + .then(function(response) { return response.arrayBuffer(); }) + .then(function(buffer) { + var data = new Float32Array(buffer); + plot.overlay_array(data, { + xstart: 0, + xdelta: 0.001 + }); + }); +``` + +For different data types, use the corresponding typed array: + +```javascript +// 64-bit double +var data = new Float64Array(buffer); + +// 16-bit signed integer +var data = new Int16Array(buffer); + +// 8-bit unsigned byte +var data = new Uint8Array(buffer); +``` + +Below we simulate a Fetch-based workflow by building a `Float32Array` from scratch +and plotting it: + +```html +/*vue*/ + +Simulated Fetch + ArrayBuffer Workflow + + + + + + + +``` + +## Comparing Different Data Types + +When a raw file uses integer or byte formats, the sample values may need scaling. +The choice of format affects both precision and file size. + +```html +/*vue*/ + +Comparing Float vs Integer Representations + + + + + + + +``` + +## Format Codes Reference + +When using `overlay_href` to load raw files, specify the `format` option with one of +these codes: + +| Format Code | Description | Typed Array | Bytes per Element | +|---|---|---|---| +| SB | Scalar Byte (8-bit signed) | `Int8Array` | 1 | +| SI | Scalar Integer (16-bit signed) | `Int16Array` | 2 | +| SL | Scalar Long (32-bit signed int) | `Int32Array` | 4 | +| SF | Scalar Float (32-bit) | `Float32Array` | 4 | +| SD | Scalar Double (64-bit) | `Float64Array` | 8 | +| CF | Complex Float (32-bit per component) | `Float32Array` (interleaved I/Q) | 8 | +| CD | Complex Double (64-bit per component) | `Float64Array` (interleaved I/Q) | 16 | + +## Byte Order and Endianness + +Raw binary files may use either big-endian or little-endian byte order. By default, +SigPlot assumes the system's native byte order for raw files. + +If your file uses a different byte order, you can use a `DataView` to read the data +with explicit endianness before passing it to SigPlot: + +```javascript +fetch("big_endian_data.bin") + .then(function(response) { return response.arrayBuffer(); }) + .then(function(buffer) { + var view = new DataView(buffer); + var npts = buffer.byteLength / 4; // 4 bytes per float32 + var data = new Float32Array(npts); + for (var i = 0; i < npts; i++) { + data[i] = view.getFloat32(i * 4, false); // false = big-endian + } + plot.overlay_array(data, { + xstart: 0, + xdelta: 0.001 + }); + }); +``` + +When using `overlay_href`, BLUE files handle endianness automatically via their +header. For raw files loaded with `overlay_href`, SigPlot assumes little-endian on +most platforms. If your data is big-endian, the `DataView` approach above is +recommended. diff --git a/Slider_Plugin.md b/Slider_Plugin.md new file mode 100644 index 0000000..cc02d25 --- /dev/null +++ b/Slider_Plugin.md @@ -0,0 +1,233 @@ +# Slider Plugin + +The `SliderPlugin` adds interactive line markers to your SigPlot plots. Sliders can be +dragged by the user to select specific values along the x or y axis. They are commonly +used to mark frequencies, time positions, or threshold levels. + +## Creating a Basic Slider + +To add a slider to a plot, create a `SliderPlugin` instance and add it to the plot using +`add_plugin`. By default, sliders are vertical (i.e. they mark a position along the x-axis). +Use `set_position` to place the slider at a specific value in real units. + +```javascript +var slider = new sigplot.plugins.SliderPlugin({ + direction: "vertical", + name: "Marker" +}); +plot.add_plugin(slider); +slider.set_position(512); +``` + +```html +/*vue*/ + +A sine wave with a vertical slider positioned at sample 512 + + + + + + + +``` + +## Listening for Slider Events + +You can listen for the `"slidertag"` event, which fires when the user releases the slider +at a new position. The callback receives an event object with `.x` and `.y` properties +that contain the slider's position in real units. This is useful for displaying the +selected position in a separate element. + +```javascript +slider.addListener("slidertag", function(evt) { + document.getElementById('info').textContent = + "Position: x=" + evt.x.toFixed(2); +}); +``` + +```html +/*vue*/ + +Slider with event listener that displays position below the plot + + + + + + + +``` + +## Paired Sliders for Range Selection + +Two sliders can be paired together using the `pair` method. This is useful for selecting +a range along the x-axis—for example, marking the start and end of a region of interest. +When sliders are paired, SigPlot draws a shaded region between them. + +```javascript +var sliderLeft = new sigplot.plugins.SliderPlugin({ + direction: "vertical", + name: "Start" +}); +var sliderRight = new sigplot.plugins.SliderPlugin({ + direction: "vertical", + name: "End" +}); +plot.add_plugin(sliderLeft); +plot.add_plugin(sliderRight); + +sliderLeft.set_position(300); +sliderRight.set_position(700); +sliderLeft.pair(sliderRight); +``` + +```html +/*vue*/ + +Two paired sliders selecting a range on a sine wave + + + + + + + +``` diff --git a/Streaming_Line_Plots.md b/Streaming_Line_Plots.md new file mode 100644 index 0000000..b923203 --- /dev/null +++ b/Streaming_Line_Plots.md @@ -0,0 +1,236 @@ +# Streaming Line Plots + +SigPlot supports real-time streaming data through the concept of a **pipe**. A pipe is a +layer that you can continuously push new data into, causing the plot to update live. This +is useful for displaying data from sensors, radios, or simulations in real time. + +To create a pipe, use `overlay_pipe` which returns a layer index (the pipe handle). You +then call `plot.push(layerIndex, data)` to send new data into the pipe, and SigPlot will +redraw automatically. + +```javascript +var layerIndex = plot.overlay_pipe({ + type: 1000, // 1D data (line plot) + subsize: 1024, // number of points per frame + xstart: 0, + xdelta: 1 +}); +``` + +The pipe header takes the same fields as an `overlay_array` header. The `type` field is set +to `1000` to indicate 1D data (a line plot), and `subsize` specifies how many points are in +each frame of data pushed to the pipe. + +## Basic Streaming Sine Wave + +In this first example, we create a pipe and use `setInterval` to push a phase-shifting sine +wave every 100ms. Each push replaces the previous frame, so the plot shows a continuously +moving waveform. + +```javascript +var layerIndex = plot.overlay_pipe({ + type: 1000, + subsize: 1024, + xstart: 0, + xdelta: 1 +}); + +var phase = 0; +setInterval(function() { + var data = []; + for (var i = 0; i < 1024; i++) { + data.push(Math.sin(2 * Math.PI * i / 1024 + phase)); + } + plot.push(layerIndex, data); + phase += 0.1; +}, 100); +``` + +```html +/*vue*/ + +Streaming Line Plot - Phase-Shifting Sine Wave + + + + + + + +``` + +## Streaming Noise + +This example pushes random noise into the pipe every 100ms. Each frame is entirely new +random data, simulating a live noise signal. + +```javascript +setInterval(function() { + var data = []; + for (var i = 0; i < 1024; i++) { + data.push(Math.random() - 0.5); + } + plot.push(layerIndex, data); +}, 100); +``` + +```html +/*vue*/ + +Streaming Line Plot - Random Noise + + + + + + + +``` + +## Multiple Streaming Pipes + +You can create multiple pipes on the same plot. Each call to `overlay_pipe` returns a +separate layer index, and you push data to each pipe independently. Here we show a sine +wave and a cosine wave streaming simultaneously. + +```javascript +var layer1 = plot.overlay_pipe({ + type: 1000, subsize: 1024, xstart: 0, xdelta: 1 +}); +var layer2 = plot.overlay_pipe({ + type: 1000, subsize: 1024, xstart: 0, xdelta: 1 +}); + +var phase = 0; +setInterval(function() { + var sine = [], cosine = []; + for (var i = 0; i < 1024; i++) { + sine.push(Math.sin(2 * Math.PI * i / 1024 + phase)); + cosine.push(Math.cos(2 * Math.PI * i / 1024 + phase)); + } + plot.push(layer1, sine); + plot.push(layer2, cosine); + phase += 0.1; +}, 100); +``` + +```html +/*vue*/ + +Streaming Line Plot - Multiple Pipes + + + + + + + +``` diff --git a/Streaming_Raster_Plots.md b/Streaming_Raster_Plots.md new file mode 100644 index 0000000..ea9d8d2 --- /dev/null +++ b/Streaming_Raster_Plots.md @@ -0,0 +1,164 @@ +# Streaming Raster Plots + +A streaming raster plot (also known as a falling raster or waterfall display) builds up a +2D image row by row. Each time you push a new row of data, SigPlot scrolls the display +and adds the new row, creating a spectrogram-like visualization. This is commonly used to +display spectrum data over time, where each row represents a single spectrum and the color +indicates signal intensity. + +To create a streaming raster, use `overlay_pipe` with `type: 2000` to indicate 2D data. +The `subsize` field specifies how many columns (points) are in each row. + +```javascript +var layerIndex = plot.overlay_pipe({ + type: 2000, // 2D data (raster) + subsize: 128, // number of columns per row + xstart: 0, + xdelta: 1, + ydelta: 1 // spacing between rows +}); +``` + +Each call to `plot.push(layerIndex, row)` adds one row to the raster. SigPlot automatically +scrolls the display as new rows arrive. + +## Basic Streaming Raster + +In this first example, we push rows of random data into a raster pipe every 100ms. You will +see a continuously scrolling noise pattern. + +```javascript +var layerIndex = plot.overlay_pipe({ + type: 2000, + subsize: 128, + xstart: 0, + xdelta: 1, + ydelta: 1 +}); + +setInterval(function() { + var row = []; + for (var i = 0; i < 128; i++) { + row.push(Math.random()); + } + plot.push(layerIndex, row); +}, 100); +``` + +```html +/*vue*/ + +Streaming Raster Plot - Random Noise + + + + + + + +``` + +## Simulated Spectrogram + +A more realistic example is a simulated spectrogram display. Here we generate each row as a +noise floor with a Gaussian-shaped peak that drifts across the frequency axis over time. This +simulates a signal whose frequency is slowly changing, which is a common pattern in spectrum +analysis. + +```javascript +var center = 64; // starting center bin +setInterval(function() { + var row = []; + for (var i = 0; i < 256; i++) { + // noise floor + Gaussian peak + var signal = Math.exp(-0.5 * Math.pow((i - center) / 5, 2)); + row.push(signal + 0.1 * Math.random()); + } + plot.push(layerIndex, row); + center = center + 0.5; // drift the peak + if (center > 200) { center = 56; } +}, 100); +``` + +```html +/*vue*/ + +Streaming Raster Plot - Simulated Spectrogram + + + + + + + +``` diff --git a/Zoom.md b/Zoom.md new file mode 100644 index 0000000..47aaf4b --- /dev/null +++ b/Zoom.md @@ -0,0 +1,232 @@ +# Zoom + +SigPlot has built-in support for zooming into regions of a plot. You can zoom using +mouse interactions or programmatically through the API. + +## Mouse-Based Zooming + +The simplest way to zoom is with the mouse: + +1. **Zoom in**: Left-click and drag to draw a zoom box around the region of interest +2. **Unzoom one level**: Middle-click on the plot, or press the `M` key +3. **Full unzoom**: Press the `F` key to return to the original view + +Try it on the plot below. Left-click and drag to zoom into a portion of the sine wave, +then press `M` to unzoom or `F` to fully unzoom. + +```html +/*vue*/ + +Try zooming: left-click and drag to zoom, press M to unzoom, F for full unzoom + + + + + + + +``` + +## Programmatic Zooming + +You can also zoom programmatically using the `zoom` method. This is useful when you want +to focus the user on a specific region of the data, for example in response to a button +click or an external event. + +```javascript +// Zoom to a specific region +plot.zoom({ x: 200, y: -0.5 }, { x: 600, y: 0.5 }); + +// Unzoom one level +plot.unzoom(); + +// Full unzoom (reset to original view) +plot.unzoom(0); +``` + +In this example, buttons below the plot let you jump to specific regions or reset the +view. + +```html +/*vue*/ + +Use the buttons to zoom to different regions of the plot + + + + + + + +``` + +## Zoom Events + +When the user completes a zoom box selection, SigPlot fires the `sigplotexit` event. +You can listen for this event to perform custom actions whenever the user zooms, such as +loading higher-resolution data for the zoomed region. + +```javascript +plot.addListener("sigplotexit", function(evt) { + console.log("Zoom completed"); + console.log("New x-range: " + evt.xmin + " to " + evt.xmax); + console.log("New y-range: " + evt.ymin + " to " + evt.ymax); +}); +``` + +In this example, the status area displays the zoom region each time you zoom in. + +```html +/*vue*/ + +Draw a zoom box to see the zoom event details below the plot + + + + + + + +``` + +## Zoom Summary + +| Action | Method | +|--------------------|--------------------------------------------------| +| Mouse zoom in | Left-click and drag a box | +| Mouse unzoom | Middle-click or press `M` | +| Full unzoom | Press `F` | +| Programmatic zoom | `plot.zoom({x: xmin, y: ymin}, {x: xmax, y: ymax})` | +| Programmatic unzoom| `plot.unzoom()` (one level) or `plot.unzoom(0)` (full) | +| Zoom event | `plot.addListener("sigplotexit", callback)` |