Configuring LabVIEW Waveform Graphs for 1-64 Channels

Daniel Price17 min read
Other ManufacturerOther TopicTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

A file holding 1 to 64 channels, with one graph required per channel and no overlaid plots allowed, cannot be served by creating Waveform Graph objects at run time in a deployed LabVIEW application. Open VI Reference will not do it either, because it opens a VI file, not a front-panel control. There are three workable paths: an array of graph clusters, a fixed set of pre-placed graphs addressed through a reference array, or one VI Server-spawned window per channel. The right one depends on whether each graph needs its own zoom, scaling, and plot style.

Where does channel data travel between the file and the graph?

Trace the path before choosing a display strategy. It has four hops, and the failure described here sits at the last one.

Hop Carrier What it holds Where it can stop
1. File read File I/O primitive Raw channel data, N = 1 to 64 Channel orientation: rows or columns
2. In-memory array 2D DBL array One row per channel (N x samples) Transposed if the file stores channels as columns
3. Channel selection Index Array / For Loop 1D DBL array for one channel Index is 0-based; channel 1 in the file is row 0
4. Display object Graph terminal, graph-in-cluster array element, or control refnum Plot data plus display properties A front-panel object must already exist; the diagram cannot create one in a built application

A Waveform Graph terminal takes a 1D array of doubles by default. Right-click a graph on the panel and create a constant, and the diagram produces a 1D DBL array constant. A 2D array wired to the same terminal draws as multiple plots, one per row. That multi-plot behavior is what makes a single-graph overlay trivial, and it is also why a 2D array cannot be passed straight to one graph when overlaying is not allowed. Each channel has to be split out at hop 3 and routed to its own object at hop 4.

Hops 1 through 3 are ordinary array handling and work the same for N = 1 or N = 64. Every design decision below concerns hop 4: how many display objects exist, who owns their properties, and how data reaches each one.

Can Open VI Reference place a Waveform Graph on the running front panel?

No. Check this first, because it rules out the approach the question starts from.

Open VI Reference is a VI Server function. Its path input points to a .vi file on disk, or to a VI already in memory, and it returns a reference to that VI as a whole: its front panel, block diagram, and execution. A Waveform Graph is a front-panel control class, not a VI, so there is no built-in path that returns a graph. What the function can do is open a reference to a VI you write whose panel contains one graph, then run and display that VI. That is the spawned-window branch covered later.

Adding new controls to an existing front panel requires VI Scripting. Scripting edits VIs as an editor operation and is not available in a built executable. Anything that has to ship as an EXE therefore works from a fixed pool of front-panel objects. "Dynamic instantiation" becomes one of these:

  • Changing how many elements an array of graphs displays.
  • Hiding and showing pre-placed graphs.
  • Launching additional VI instances, each with its own panel.
Reading Meaning Next check
Application runs only in the development environment and may use scripting Run-time object creation is technically possible, but the code cannot move to an EXE Treat it as a deployment risk and go to the property-independence check anyway
Application ships as an EXE or run-time deployment No new controls can be created on a panel Property-independence check

Does each channel graph need its own zoom, scaling, or plot style?

This is the branch point. The answer decides whether an array of graphs is acceptable.

Requirement Array of graph clusters Pre-placed graphs + refnum array VI Server window per channel Single overlay graph
Independent zoom / axis scaling No, shared by all elements Yes Yes No, one set of axes
Independent plot color / point style No, shared Yes Yes Yes, per plot
Works in a built EXE Yes Yes Yes Yes
Displayed count set at run time Yes, via NumCols / array size Up to the number placed, via Visible Unbounded by panel layout N/A: any subset overlaid
All channels in one window Yes Yes No, separate windows Yes
Meets "no overlapping" rule Yes Yes Yes No
Build effort Lowest Medium: one graph placed per channel slot Medium-high: instance VI plus data transport Low

If identical axes and styling across all channels are acceptable, and the operator never needs to zoom one channel alone, use the cluster array. If zoom, autoscale, or cursors must act per channel inside one window, use pre-placed graphs with a refnum array. If separate windows are acceptable, or the channel count may exceed any sensible panel layout, spawn instance VIs through VI Server. If the requirement against overlapping can be renegotiated, a single overlay graph or a small fixed set of graphs is the least work and usually the most readable.

Why can't a Waveform Graph go directly into an array, and what does the cluster wrapper change?

Dropping a Waveform Graph into an empty array shell is refused in current LabVIEW versions. An array shell accepts a Boolean, numeric, or cluster element, so the workaround is one level of nesting:

  1. Place an empty cluster shell on the front panel.
  2. Drop a Waveform Graph inside the cluster.
  3. Place an empty array shell and drag the cluster into it.
  4. Resize the array display to show the required number of elements, or set it programmatically.

This explains why an array of toggles and a cluster of graphs are both legal while a bare array of graphs is not. The cluster is the permitted element type, and the graph rides inside it.

The data type changes too. The array terminal is now a 1D array of clusters, and each cluster holds one element: the graph's data type, a 1D DBL array by default. Index the array and you get a cluster. Probe that cluster and you see a single array, which looks like "an array of one element" but is the graph's plot data inside the cluster. To reach the plot data, add an Unbundle after Index Array. To write a channel into element k, Bundle the 1D channel array into the cluster, then build or replace the array element.

2D DBL [N x S]  --For Loop (auto-index rows)--> 1D DBL row
     row --> Bundle (cluster of 1 graph) --> auto-indexed output tunnel
     --> 1D array of clusters --> Array-of-graphs indicator terminal

How do you resize the graph array at run time, and where does independence stop?

The number of visible columns in the array display is set by the array's NumCols property. When first created, the property node reads the value. Right-click the property node and choose Change To Write to set it. The property is writable, and it is the correct one for adjusting how many array columns show programmatically. Pair it with the data length: wire an array of exactly N clusters so unused visible cells do not show default or stale data.

Symptom Cause Fix
NumCols property node has a read-only output Property node created in read mode Right-click > Change To Write
Index Array output looks like a one-element array, not a graph Element is a cluster whose only field is the graph's 1D DBL data Add Unbundle; the output is the plot data
Zooming one graph zooms all of them All array elements share one set of display properties Move to pre-placed graphs or spawned VIs
Changing plot color on element 3 recolors every element Same shared-property mechanism Accept uniform styling, or change architecture

The limitation comes from how LabVIEW stores arrays. An array control holds data per element, but only one set of appearance and configuration properties, attached to the model element. A reference to the array element refers to that model element's data type, not to an individual cell. Any property change on any element applies to all of them, whether you make it by hand on the front panel or through a property node. Examples include axis range, autoscale, zoom from the graph palette, plot color, and point style. Uniform plot color is often desirable. Uniform axis scaling and zoom usually are not, and that alone disqualifies this branch when operators need to inspect one channel closely.

How do pre-placed graphs and a refnum array simulate run-time instantiation?

This is the resolving branch for the stated requirements: one graph per channel, all in one window, independent zoom, and an EXE-compatible build. The mechanism is simple. Every graph exists at edit time as its own front-panel object with its own property set. A 1D array of control references gives the diagram array-style iteration over those objects. The Visible property makes the unused ones disappear, so from the operator's side the panel appears to create N graphs.

Sizing the pool is a design decision, not a run-time one. The panel must carry as many graphs as the largest N you intend to support. Place the number needed now, 12 in the immediate case, and extend toward 64 later. Every slot costs panel real estate and edit-time placement, which is the practical argument for capping on-screen graphs and paging through channels, covered further down.

Two data paths reach each graph, and they behave differently:

Write path How Behavior
Terminal write Wire data to each graph's own terminal Fastest; no array iteration possible, since each terminal is wired individually
Value property via refnum For Loop over the refnum array, property node writes Value Iterable and scales to any pool size; each write runs through the user-interface thread and is slower than a terminal write

For a file that is read once and then displayed, the property-node path is fast enough. For live updating at a high rate across many graphs, set the front panel's Defer Panel Updates property to TRUE before the loop and back to FALSE after it, so the panel redraws once rather than once per graph.

When should each channel get its own window through VI Server instead?

Here Open VI Reference earns its place. Write one small VI, a graph instance VI whose front panel holds a single graph plus whatever controls a channel needs. Then have a main VI open N independent copies of it. Each copy has its own panel and its own property set, so zoom, scaling, and styling are fully independent. The channel count is not limited by how many graphs were placed at edit time.

The call chain for each instance runs like this:

  1. The main VI calls Open VI Reference with the path to the instance VI. Open it as a reentrant clone, or from a VI template, so each call yields a separate data space and panel rather than the same VI N times.
  2. The main VI sets the instance's inputs, such as channel number and title, through the reference.
  3. The main VI opens the instance's front panel and invokes Run VI with wait-until-done set to FALSE. The main VI continues immediately instead of blocking.
  4. Data reaches the instance through a queue, notifier, or user event created by the main VI and passed in at launch. Alternatively, the instance reads its own channel from the file.
  5. On shutdown, the main VI signals each instance to stop, then closes every reference it opened.

Step 3 is where designs commonly stall. A subVI configured to show its front panel when called does display, but the caller waits for that subVI to finish before proceeding, so a For Loop that "opens 12 graph subVIs" shows them one at a time. Launching through VI Server with wait-until-done FALSE is what lets the top-level VI keep running while every instance stays open. The same pattern works for a datalogging VI that writes a file periodically, with a separate viewer VI opened on demand to graph that file, both running independently of the top-level VI.

For the top-level VI, use a producer/consumer architecture. An event structure in the producer loop handles operator actions such as "load file" or "show channel k". It posts commands to a queue that a consumer loop services, and the consumer does the launching and data distribution. The UI never freezes while instances start.

Deployment checks for this branch: the instance VI must be included in the build specification, because it is loaded by path rather than as a statically linked subVI. The path must also be built relative to the application, not hard-coded to a development drive. Demonstration code that expects its VIs and data file at the root of C: will fail everywhere else.

Can one overlay graph or a tab control replace 64 separate panels?

Check this before committing to 64 panels. Sixty-four simultaneous graphs on one screen leave each plot too small to read. A fixed layout of a few large graphs, four for example, each able to show any selected channel, is usually more usable. It is also far less panel work. Two variants stay within the no-code-generation limit:

  • Tab control: put different numbers and sizes of graphs on separate tab pages, and switch the active page programmatically or let the operator pick a layout. Graphs on hidden pages keep their own properties.
  • Channel selectors per graph: each of a few large graphs gets a numeric channel selector, or an on/off Boolean plus selector for up to eight overlaid traces. The operator reassigns channels instead of scrolling through 64 panels.

Moving graphs on-screen and off-screen by writing their position is also possible. It is the most tedious option and the easiest to break when the window is resized. Graph cursors add close inspection of a data section without a separate zoom-per-graph requirement.

If the operator group accepts overlays at all, one large graph showing any chosen subset of the 64 channels removes the hop-4 problem entirely. The multi-plot 2D input does the work. Where the existing interface has to be reproduced exactly, these options serve as a later improvement rather than the first delivery.

How is the channel-selection loop wired for the overlay or selector graphs?

The same selection loop feeds either one overlay graph or each of the few selector graphs. It relies on four LabVIEW mechanisms: event-driven execution, auto-indexing, shift registers, and dataflow.

While Loop
  Event Structure
    [Channel array: Value Change] / [On-Off array: Value Change]
      For Loop  (count = size of channel array)
        auto-indexed in: channel number (I16), on/off Boolean
        non-indexed in:  full 2D data array
        shift register:  2D array of selected rows (init empty)
        Case (Boolean)
          TRUE : extract row [channel] from 2D data -> Build Array with SR -> SR
          FALSE: pass SR through unchanged
      SR output -> Waveform Graph (2D = one plot per row)
    [Stop: Value Change]
      TRUE -> While Loop conditional
      NOT(TRUE) -> Stop.Value property (reset button)

Mechanics that matter when building it:

  • Auto-indexing: the bracketed input tunnels on the channel and on/off arrays make the For Loop take one element per iteration. The loop count comes from the array size. The 2D data tunnel has indexing disabled, so every iteration sees the whole data set.
  • Row extraction: the I16 channel number drives the row index input of the array function that pulls out one channel. Channels are 0-based, so an entry of 9 selects the tenth row.
  • Shift register: accumulates selected rows across iterations. A FALSE Boolean passes it through untouched, so disabled plot slots contribute nothing.
  • Event trigger: both the channel numerics and the on/off Booleans fire Value Change events. Any edit reparses the full array and rewrites the graph. That is acceptable for medium arrays and wasteful for very large ones; cache the extracted rows if redraw lag appears.
  • Stop handling: the Stop event passes TRUE to the While Loop conditional. The inverted value is written back to the Stop button's Value property so the button is reset for the next run.
  • Dataflow: a node executes only when all its inputs have arrived and completes only when all its outputs are produced. Use execution highlighting (the light-bulb button) to watch each iteration move through the case structure while debugging.

How do you build and verify the refnum-array graph pool?

Build procedure for the resolving branch: independent graphs, one window, EXE-compatible.

  1. Place the maximum number of Waveform Graphs the panel must support (12 now, up to 64 later). Give each a unique label and set its axes, autoscale, and styling individually.
  2. On the diagram, right-click each graph and choose Create > Reference. Wire all references in panel order into Build Array to form a 1D array of graph refnums. Keep the order identical to the intended channel order.
  3. Read the file into a 2D DBL array with one row per channel. Transpose it if the file stores channels in columns. Read N from the row count.
  4. Coerce N to the pool size so a file with more channels than placed graphs does not index past the refnum array.
  5. In a For Loop auto-indexed over the refnum array, set Visible to TRUE when the iteration index is less than N and FALSE otherwise. For visible graphs, index row i from the 2D array and write it to the graph's Value.
  6. Wrap the loop in Defer Panel Updates TRUE/FALSE writes to the front panel so the layout changes in one redraw.
  7. Optionally write each graph's position in the same loop to close gaps left by hidden graphs, tiling the first N in a grid.
  8. Build the executable and repeat the checks below in the run-time build, not only in the development environment.

Verification, in order:

  1. Load a 1-channel file and confirm exactly one graph is visible and all others are hidden.
  2. Load a file whose channel count equals the pool size and confirm every graph is visible and none is empty.
  3. Load a file with more channels than the pool and confirm no error is raised and the excess channels are handled per the coercion rule in step 4.
  4. Write a known pattern into one channel, such as a ramp on row 0 and a constant on row 1. Confirm graph 1 shows the ramp and graph 2 the constant, which proves the 0-based row-to-refnum mapping.
  5. Zoom graph 1 with its graph palette and change its Y-axis range. Confirm graphs 2 through N keep their original scaling. This is the check that fails on the cluster-array branch and must pass here.
  6. Reload a file with a smaller N than the previous file and confirm the graphs that are now hidden do not reappear later with stale data. Clear their Value when hiding them if they do.

FAQ

Why does LabVIEW not let me put a Waveform Graph directly into an array?

The array shell does not accept a graph as its element in current versions. Place the graph inside a cluster, then drag that cluster into the array. The result is an array of clusters, each holding one graph's 1D DBL data.

Why does zooming one graph in an array of graphs zoom all of them?

An array control keeps separate data per element but only one set of display properties, belonging to the model element. Zoom, axis scaling, plot color, and point style therefore apply to every element. Use separately placed graphs with a refnum array, or spawned instance VIs, when each channel needs its own zoom.

Why does Open VI Reference ask for a file path instead of a graph?

Open VI Reference returns a reference to a VI, not to a front-panel control, so it needs the path to a VI on disk. Write your own VI with one graph on its panel, then open and run multiple independent instances of it through VI Server.

How do I change the number of visible graphs in the array at run time?

Create an array property node for NumCols, right-click it and choose Change To Write, then wire the channel count. Also wire an array of exactly N elements so unused cells do not display default data.

Back to blog