User guide
StatDataViewer documentation
A task-oriented reference for moving fast in StatDataViewer. Every action is reachable three ways — a right-click, a single-letter shortcut, or a visible button — so pick whichever fits your hand and keep working.
Getting started#
StatDataViewer is built around the idea of opening a library — a folder of datasets — instead of opening one file at a time. Once a library is open, every action is within one right-click or one keystroke.
60-second quick start
- Open a library. Choose File → Open Folder and point at a folder of datasets. The folder becomes a library in the Workspace, and every supported file in it is listed at once.
- Pick a dataset. Double-click it in the Workspace. The data window opens; its Variables, Frequency and Univariate panels sit in the inspector on the right (View → Dock Windows).
- Filter with one key. Click a value in a column and press D — the dataset is filtered to rows matching that value.
- Count values. With any cell in a column selected, press F to get a frequency table for that variable.
- Jump to a variable. Find it in the Variables panel, press G — the data window scrolls to that column.
- Find anything. Press Q (or Ctrl+P) for Quick Open: type a dataset name to open it, or
?to list every command in the application.
SEX = F cell, the rows counter reads 119/240 and the status bar shows the filter expression.Tip — right-click is the discovery tool
Whenever you are unsure what you can do, right-click. Every menu is context-aware: right-click a cell to filter on it, right-click a column header to reorder or hide it, right-click a library to refresh or rename it. Context menus also show the shortcut key for each action — the fastest way to learn shortcuts.
Keyboard shortcuts#
StatDataViewer shortcuts are intentionally single letters: each letter matches the first letter of the action. Learn these seven and you will rarely need the mouse: D, L, F, N, S, B, G. The single letters work while the data window has the focus; in a text box they type as usual.
| Category | Shortcut | Action |
|---|---|---|
| Filtering | D / = | Dataset filter: keep the rows whose value equals the one under the cursor. |
| Filtering | I | Filter with in (…): hold Ctrl and click several cells in a column, then press I. |
| Filtering | ^ / ~ | Filter with ^= (not equal). |
| Filtering | > / < | Filter with > or < against the value under the cursor. |
| Filtering | Alt+> / Alt+< | Filter with >= or <=: numeric or date thresholds. |
| Filtering | Z / Ctrl+Z | Undo the last dataset filter step. |
| Filtering | C | Clear the dataset filter. |
| Filtering | L | Library filter: apply the same WHERE clause to every dataset in the library. |
| Filtering | Alt+C | Clear the library filter. |
| Frequency | F | Frequency of the selected variable(s). |
| Frequency | N | Number of distinct unique IDs (USUBJID) per value: Freq (UniqueID). |
| Statistics | S | Univariate statistics of the selected numeric variable: N, mean, SD, min, quartiles, max. |
| Variables | G / V | Go to the variable under the cursor: in the data window it shows the variable in the Variables panel, and in the Variables panel it scrolls the data window to that column. |
| Variables | H | Hide the selected variable (column). |
| Variables | Shift+H | Hide all variables (on macOS Option+H works too). |
| Variables | U | Unhide all variables. |
| Variables | Alt+← / Alt+→ | Shift the selected variable left or right. |
| Variables | B | Add the selected variable to the BY list, used by Frequency and Univariate to break the output out by group. |
| Navigation | Q / Ctrl+P | Quick Open: find any dataset across the open libraries, or type ? for every command. |
| Navigation | Ctrl+F | Find in the table (by column or by row). |
| Navigation | Ctrl+O | Open SAS datasets. |
| Navigation | Ctrl+1 | Go to the Workspace: as a tab it switches to the Workspace and back; in the sidebar it opens the Workspace as a tab. |
| Navigation | Ctrl+2 | Show or hide the inspector panel on the right (Variables, Frequency, Univariate, Charts, Code). |
| Navigation | Alt+Shift+L | Locate the active document in the Workspace (macOS: Ctrl+Option+L). |
| Tabs | Ctrl+Tab | Next tab (macOS: Control+Tab). |
| Tabs | W / Ctrl+W | Close the current document. |
| Tabs | Ctrl+Shift+W | Close every open document. |
| Tabs | Ctrl+R / F5 | Reload the active tab's file in place; a dataset keeps its filters, hidden columns and sort. |
| View | Ctrl++ / Ctrl+- | Larger or smaller font in the data window, the Frequency panel and the Variables panel. |
| View | Ctrl+Shift+V | Switch a Markdown document between the rendered view and its source. |
Note
Shortcut keys are shown with Windows names. On macOS, Ctrl means ⌘ (Command) and Alt means Option; the few places where macOS uses a different key are marked in the table. The single-letter shortcuts are identical on both platforms.
Other windows
Each tool window has keys of its own, listed in its section: the Workspace file panels use Total Commander's function keys, the Compare Datasets window takes the same filter letters as a dataset plus N / P for the next and previous difference, the Compare Files window has F7 for the next difference, and the program editor has the run, fold and bookmark keys.
Change a shortcut
Every key in the application can be changed: choose Edit → Options, open the Keyboard Shortcuts tab, pick a command and record a new key. Conflicts are shown as you type. Help → Show Shortcut Keys lists the current keys of every command, grouped by window, and is searchable: type filter to see every filtering key.
→ Blog: 10 Keyboard Shortcuts Every SAS Programmer Should Know
Search & navigation#
Search within a dataset
Press Ctrl+F in a data window to open the Find in table dialog. Type a value and press Enter: the first matching cell is selected and scrolled into view. The search is case-insensitive. By Column searches down the current column first; By Row searches across the current row first. A match in a hidden column is reported as Found, but not visible.
Find Next / Find Previous
In the dialog, Enter or Next goes to the next match and Previous to the one before. Close (or Escape) returns to the table. In text documents and PDFs the find bar is used instead, with Edit → Find Next (Ctrl+G) and Find Previous (Ctrl+Shift+G).
Quick Open: open a dataset or run a command by name
Press Q (or Ctrl+P, or the toolbar's Quick Open button). Start typing a dataset name; the list filters as you type across every open library, and Enter opens the highlighted dataset. Wildcards work: ad* lists every ADaM dataset.
Quick Open is also the command palette. Type ? to list every command in the application, or part of a command's name, such as labels or set by, and press Enter to run it. Commands that are not in any menu, such as Show Variable Labels or Set By Variables, are reached this way.
Tip
Type just a few characters: adsl, ae, lb. Files opened outside the Workspace tree are listed too.
Jump to a row
Open Quick Open and type r followed by the row number, for example r 1200, then press Enter. r 1200 c 5 goes to the fifth column of that row. The same works in the Workspace preview of a dataset (Ctrl+L there opens a Go to Row box).
Jump to a column
Use the Variables panel: click the variable you want, then press G (or right-click → Go to Variable). The data window scrolls horizontally to that column and selects it. From the data window, G or V goes the other way and shows the current column's row in the Variables panel.
Filtering data#
StatDataViewer has two kinds of filter: a dataset filter that applies only to the table in front of you, and a library filter that applies the same WHERE clause to every dataset in the library — ideal for narrowing to one subject or one site across all domains.
Dataset filter
Right-click the cell whose value you want to filter on, then choose one of the IF clauses from the context menu. Repeat to add more conditions; each one is joined with and. The default operator is =. The current filter expression is always visible in the Dataset Filter box on the toolbar and in the status bar.
Shortcut: D — short for Dataset filter.
Filter operators: in, ^=, >, <, >=, <=
Beyond the default = operator (D or =), the right-click menu and the shortcut keys below let you build richer conditions without writing the expression by hand:
- I —
in (…)operator. Hold Ctrl and click several cells in the same column, then press I. The filter becomesSEX in ("F") and AESEV in ("MODERATE","SEVERE")-style. - ^ or ~ — not equal (
^=). Keep every row except the ones with this value. - > / < — greater than / less than the value under the cursor.
- Alt+> — greater than or equal. Press on a numeric or date cell to filter to all rows at or above that value, e.g.
AGE >= 65orAESTDTC >= "2023-06-01". - Alt+< — less than or equal. Mirrors the above for upper bounds.
Tip — chain operators for a real clinical query
Pick any row in ADAE, press Alt+> on an ASTDT value to restrict to on-treatment events, then Ctrl-click two AESEV cells and press I to keep only moderate and severe events. Two keystrokes, no code.
Edit the filter expression manually
Click the Dataset Filter box on the toolbar, type or paste a WHERE expression and press Enter. Any SAS expression works, functions included: AEBODSYS = "INFECTIONS" and AESEV ne "MILD", upcase(AETERM) contains "HEAD", ASTDT >= "01JAN2024"d. The box keeps a history of the expressions you have used; open its drop-down to pick one again. The Library Filter box next to it takes the library-wide clause the same way.
Clearing the dataset filter
Right-click anywhere and choose Clear Dataset Filter, or press C.
Undoing a dataset filter step
Press Z / Ctrl+Z. Each press steps back one filter condition, letting you retrace without starting over.
Library filter (WHERE across the library)
Right-click a value you want to use in the WHERE clause, then choose the WHERE entry from the context menu. The same clause is then applied to every dataset in the library. Shortcut: L — Library filter.
Caution
Only one condition can be defined for the library filter. If you are not seeing the rows you expect, check the Status Bar — an active library filter is shown there so you never accidentally look at a filtered view.
Clearing the library filter
Right-click anywhere in the data and choose Clear Library Filter, or press Alt+C.
Filtering from the Frequency window
Inside the Frequency panel, right-click a row and pick a filter clause to apply it back to the dataset, or use the same keys as in the data window: D, I (several selected values), ^, L, C and Z. Sort the panel by Value to find the entry you want quickly when there are many distinct values.
Frequencies & crosstabs#
Frequency of one variable
Click any cell in a column, then right-click and choose Frequency, or press F. Works on both character and numeric variables. The result opens in the Frequency panel of the inspector and shows Value, Count, and Percent.
USUBJID count — the number you'd put on a safety incidence table.Frequency of multiple variables (crosstabulation)
- Hold Ctrl and click one cell in each variable you want to include (one cell per variable).
- Right-click one of the selected cells and choose Frequency — or press F.
The result is a multi-dimensional frequency combining all selected variables. This is the fastest way to replicate a PROC FREQ TABLES var1*var2 without writing code.
Distinct USUBJIDs for one variable
Click any cell in the target column, right-click, and choose Freq (UniqueID), or press N. The result shows how many distinct subjects (USUBJID) have each value — essential for safety incidence tables.
Distinct USUBJIDs across multiple variables
- Hold Ctrl and click one cell per variable.
- Right-click and choose Freq (UniqueID), or press N.
Break frequency out by a BY variable
To produce a frequency broken out by treatment arm, site, or any other grouping, first add one or more BY variables (press B on a cell in the grouping column). Then press F on the variable you want to tabulate. The Frequency window adds one Count/Percent column per BY-group level.
Clinical example. Open ADAE, click any cell in TRTA and press B. Now click any cell in AEBODSYS and press F — the result is a body-system frequency with one column per treatment arm, the same as PROC FREQ; BY TRTA; TABLES AEBODSYS;. Press N instead of F to get distinct-USUBJID counts per arm — ready for a safety incidence table.
Tip — sort and filter inside the Frequency window
Click any column header in the Frequency panel to sort. Right-click a row to filter the parent dataset on that value. This feedback loop (frequency → filter → frequency) is the fastest way to drill into data. Right-click also offers Copy, Copy as Markdown Table and Copy as SAS Value (the value quoted as a SAS literal, ready for a program).
Descriptive statistics (Univariate)#
The Univariate panel computes N, mean, standard deviation, minimum, maximum, median, and quartiles for numeric variables, the equivalent of PROC MEANS or PROC UNIVARIATE output, with no SAS needed.
Open the Univariate panel
Click any cell in a numeric column and press S, or right-click and choose Univariate. The panel opens in the inspector next to the data window with the summary statistics of that variable. Select cells in several numeric columns with Ctrl-click first to get the statistics of each column side by side.
Shortcut: S, short for statistics. The panel can also be shown from View → Dock Windows → Univariate.
Set BY variables
Press B on a cell of each grouping variable (or right-click → Add By Variable). The variables appear in the By Variables box on the toolbar, and the statistics are then computed separately for each level of the BY group, as with a BY statement in PROC MEANS. To replace the whole list at once, type the variable names into the By Variables box, or run Set By Variables from Quick Open (Q). Clear By Variable on the right-click menu empties the list.
Example: set TRT01A as a BY variable in ADSL, then press S on AGE to get the age summary per treatment arm.
Univariate detail
For a single numeric variable, the panel also shows a histogram and a box plot of the distribution, so the shape is visible at a glance without running PROC UNIVARIATE.
Note
Statistics always reflect the current dataset filter. If a dataset filter is active, statistics are computed on the filtered rows only; the status bar reminds you of the active filter.
Variables & columns#
Hide a variable
Select any cell in the column and press H, or right-click and choose Hide Variable.
Hide all variables
Right-click any cell and choose Hide All Variables, or press Shift+H (on macOS Option+H works too). Start with a blank slate, then unhide only the columns you need. Hide All-Missing Variables on the same menu hides every column that is empty in all rows, which is common in SDTM transfers.
Unhide all variables
Right-click any cell and choose Unhide Variables, or press U.
Jump to a variable
Find the variable in the Variables panel, right-click and choose Go to Variable, or press G. The data window scrolls to that column.
Look up a variable's metadata
Position the cursor in the variable's column and press G or V: the Variables panel shows the variable's row with its label, type, length, format and informat. The panel is part of the inspector (Ctrl+2 shows or hides it; View → Dock Windows → Variables opens it alone). Double-click a cell to open the Cell Inspector, which shows the full value of a long cell together with the variable's attributes.
Reorder variables
Right-click a cell and choose Shift Variable Left or Shift Variable Right, or use Alt+← and Alt+→. The order updates in both the data window and the Variables panel.
Freeze columns or rows
Right-click a cell and choose Freeze Columns Through Here to keep the key columns (for example USUBJID) in view while scrolling to the right, or Freeze Rows Through Here for the rows above. Unfreeze All removes both.
Add a BY variable
Click any cell in the variable you want to group by, then press B, or right-click and choose Add By Variable. The variable is appended to the By Variables box on the toolbar and is used by Frequency and Univariate as a grouping key. Repeat on additional variables to add more BY levels.
To replace the whole BY list in one shot, type the variable names into the By Variables box and press Enter, or run Set By Variables from Quick Open (Q). Clear By Variable on the right-click menu empties the list.
Tip — what BY variables actually do
BY variables change what F (Frequency) and S (Univariate) produce: the output is broken out by each combination of BY-variable values. For example, add TRTA as a BY variable in ADAE, press F on AEBODSYS, and you get one frequency column per treatment arm, the equivalent of PROC FREQ; BY TRTA; TABLES AEBODSYS; without writing code.
Copy & export#
Copy a cell range
Select one or more cells (click and drag, or Shift-click to extend the selection), then press Ctrl+C or right-click → Copy. The values are copied to the clipboard as tab-delimited text, ready to paste into Excel or a SAS editor. Formatted values are copied as you see them.
Copy with the variable names
Right-click the selection and choose Copy (include Var Name). The first row of the clipboard text holds the variable names, useful when pasting into Excel and needing the header row.
Copy as a Markdown table
Right-click the selection and choose Copy as Markdown Table. The cells become a GitHub-style table with the variable names as the header, ready for a README, an issue tracker or a chat message. The Frequency and Univariate panels offer the same.
Copy an entire column
In the Variables panel, right-click the variable and choose Copy, or run Copy Variable Selection from Quick Open (Q). This copies the visible (filtered) values of that column to the clipboard, a fast way to pull a list of subjects, sites, or values into another application.
Tip — copy filtered rows only
If a dataset filter is active, every copy command copies only the rows currently visible. Apply the filter first, then copy, and you get exactly the subset you want without extra steps.
Libraries & workspace#
Every open folder appears as a library in the Workspace. Most library operations live in the right-click menu of the library entry in the Workspace tree.
Add a library
Choose File → Open Folder and select a folder. All supported files inside appear immediately. You can also add one in File → Manage Libraries with Add, where the name, color, file filter and Include subfolder are set at the same time.
Remove a library from the workspace
Open File → Manage Libraries, select the library and click Delete; or run Close Library from Quick Open (Q) while the library is selected. The folder on disk is untouched; only the workspace entry is removed.
Refresh a library
Right-click the library and choose Refresh. Newly created or updated datasets on disk are picked up without restarting.
Set a library name (libname)
- Right-click the library in the Workspace tree.
- Choose Set Library Name.
- Type the name you want (e.g.
SDTM,ADAM,WORK).
The name appears as the library prefix in the Workspace, in tab tooltips and in the StatScript session as a libref, and is remembered across sessions.
Manage all libraries
Choose File → Manage Libraries (also on the library's right-click menu). The dialog lists every library with its name, directory, color, file filter and Include subfolder setting. Add, Edit, Duplicate and Delete act on the selected row; Move Up and Move Down change the order in the Workspace tree.
Pin items you come back to
Right-click any dataset, program or folder in the Workspace tree and choose Pin. Pinned items are listed in the library's dashboard (next section), so the domains and outputs you return to every day are one click away. Locate in Workspace on a document tab also works for pinned files.
Library Dashboard
Right-click a library and choose Open Dashboard. A tab named Dashboard - <library> opens, showing the library's pinned items. Select an item and click Open (or double-click), Open with Default Application, Unpin to remove it, or Refresh to re-scan the library when the folder on disk has changed. Each library has its own dashboard, and pins persist across sessions.
Properties and related files
Right-click a dataset and choose Properties for its file and dataset attributes (size, dates, encoding, observations, variables). Copy File Name and Copy Full Path put the path on the clipboard, and Open Library Folder shows the folder in Finder or File Explorer. Open Related lists the files the file associations link to the dataset, such as the program that made it or its log.
Workspace file manager#
The Workspace is a two-panel file manager in the style of Total Commander: a tree of libraries on the left, and one or two file panels with a path bar, folder tabs, a quick filter and a preview. Click the Workspace toolbar button to move it between the sidebar and a tab of its own; Ctrl+1 switches between the Workspace tab and the document you came from.
Two panels
Click Dual on the Workspace toolbar for a second panel. Tab moves between the panels, Space or Ins marks a file and moves down, and the function keys act on the marked files (or the file under the cursor) towards the other panel:
| Key | Button | Action |
|---|---|---|
| F3 | View | Preview the file full size; Esc returns to the list. Inside the viewer, F7 or Ctrl+F finds text, F3 the next match and Shift+F3 the previous one, as in Total Commander's Lister. |
| F4 | Edit | Open the file in a document tab. In a dataset preview, F4 switches between the Variables and Data pages. |
| F5 | Copy | Copy the marked items to the other panel's folder. |
| F6 | Move | Move the marked items to the other panel's folder. |
| Shift+F6 | Rename | Rename the item in place. |
| F7 | New Folder | Create a folder; a/b creates nested folders. |
| F8 / Del | Delete | Move the marked items to the Trash or Recycle Bin. Shift+F8 deletes permanently. |
| Backspace | Up | Go to the parent folder. Alt+← / Alt+→ walk the folder history. |
| Ctrl+Q | Quick View | Preview the file under the cursor in the other panel (macOS: Control+Q). |
| Ctrl+U | Swap | Exchange the two panels' folders (macOS: Control+U). |
| Ctrl+L | Type a path in the path bar (macOS: ⌘+L). Clicking a folder in the path bar opens it; a middle click opens it in a new tab. | |
| Ctrl+H | Hidden | Show or hide hidden files (macOS: ⌘+Shift+.). |
| Ctrl+R | Refresh | Read the folder again. |
These keys apply while a file panel has the focus; elsewhere F3, F6 and F7 keep their program-editor meanings. Typing letters in a panel filters the list and puts the cursor on the first match; Enter opens it.
Folder tabs per library
Each panel has folder tabs (Ctrl+T new, Ctrl+W close; on macOS Control+T and Control+W). Right-click a tab to Rename Tab, Lock Tab (the tab stays on its folder and anything else opens in another tab; a locked tab is marked *), Lock Tab, Directory Changes Allowed (it returns to its folder when shown again), Duplicate Tab, Copy Tab to Other Panel or Close Other Tabs. Every library keeps its own set of tabs on both sides: moving the tree's cursor into another library brings that library's tabs back.
Synchronized browsing
With two panels, click Sync on the toolbar. Entering a folder or going up in one panel does the same in the other, so two copies of a study tree (a transfer and its predecessor, say) can be walked side by side. Same Folder shows the current folder in the other panel.
Compare from the Workspace
Click Compare with a file chosen on each side (or two marked files in one panel): two datasets open in Compare Datasets with both files filled in, two text files open in Compare Files, and two folders open in Compare Folders.
Preview
Selecting a file shows it in the preview pane: datasets with their Variables and Data pages (the first rows are read in the background; Ctrl+L goes to a row), programs and logs as text, CSV as a table, PDF, DOCX and RTF rendered, Markdown formatted. Go to a column from Quick Open with r 10 c 3.
File associations
Right-click in the Workspace and choose File Associations... (also the File Associations tab in Options) to link files by name pattern: a dataset to the program that creates it, a program to its log and listing, an output to its QC version. The links appear under Open Related on the right-click menu and in File → Open Related, and keys can be assigned to them. Where the pattern names a library, the library's name is used to find the file.
Find duplicate records
Right-click a dataset and choose Find Duplicate Records (or Tools → Duplicate Records…). Pick the key variables, or let the dialog guess them from CDISC naming (USUBJID, --SEQ, --TESTCD), and the rows that share a key are listed for review.
Library settings#
Each library's settings are on its right-click menu in the Workspace tree, and together in File → Manage Libraries.
Set library color
Right-click the library and choose Set Library Color. Pick a color; the library's entries in the Workspace, its document tabs and the accent strip of the active document take that color at once. Useful when you have SDTM, ADaM, and output libraries open at the same time.
Include subfolders
Right-click the library and choose Include Subfolder to toggle whether files in subdirectories appear in the library listing. Useful for studies organized with domain-level subfolders.
Set a library file filter
Right-click → Set File Filter... and type the extensions to show, comma separated: sas7bdat,xpt hides the programs and logs, sas,log,lst hides the data. Leave it empty to show every supported file.
Move a library to a different folder
Open File → Manage Libraries, select the library and click Edit. Change the directory; the name, color and other settings are kept.
Close a library
In Manage Libraries, select the library and click Delete, or run Close Library from Quick Open. The documents from that library stay open until you close them; the library can be re-added at any time.
Tabs#
Each open dataset, program or document lives in its own tab. StatDataViewer can have dozens of tabs open at once; grouping, locating and keyboard navigation keep you oriented. Tabs can also be dragged next to or below each other to show two documents side by side.
Open a dataset in a new tab
Double-click a dataset in the Workspace, or right-click it and choose Open. If the dataset is already open, its tab is activated instead of opening a duplicate. The library's color marks the tab.
Group tabs by library
Right-click a tab and choose Group Tabs by Library to move every tab of the same library next to it, or Group All Tabs by Library to cluster all open tabs by their libraries. Group Tabs by Name, from Quick Open, clusters datasets with similar names (all AE-prefixed domains, say).
Close tabs
Ctrl+W closes the active document (W does too while the focus is in a data window). File → Close All (Ctrl+Shift+W) closes every open document; the Workspace and the library definitions are untouched.
Locate a tab in the workspace
Right-click a tab and choose Locate in Workspace, or press Alt+Shift+L (macOS: Ctrl+Option+L). The Workspace scrolls to and selects the file, and reopens the Workspace if it was closed. Reveal in Finder / Show in File Explorer on the same menu shows the file on disk.
Reload a tab
Right-click a tab and choose Reload, or choose File → Reload (Ctrl+R or F5). The file is read again in place: a dataset keeps its filters, hidden columns, sort and current cell; a program keeps its scroll position (and asks first if it has unsaved changes); a PDF, DOCX or RTF stays on its page. Use it when a job on a network drive has rewritten the file and the tab still shows the old version.
Switch tabs from the keyboard
Ctrl+Tab (macOS: Control+Tab) goes to the next tab, the Workspace included while it is a tab. The Window menu lists every open tab with a number.
Compare a program tab
Right-click a program or text tab and open Compare: With Saved File shows your unsaved edits against the file on disk, With Tab compares with another open tab, With Clipboard with the clipboard text, and With File… with a file you choose. Each opens the Compare Files window.
Sessions#
A session saves the set of datasets you have open, so a review can be picked up where it was left: the same tabs, in the same order, from the same libraries.
Save the current session
Choose File → Save Session... and give the session a descriptive name, such as Study XYZ Safety Review. Sessions are stored locally and persist across application restarts; a name already in use is refused, so rename or delete the old session first.
Open a saved session
Saved sessions are listed under the Sessions node of the Workspace tree. Right-click one and choose Open Session: every dataset it holds is opened in a tab. Right-click the node and choose Refresh if a session saved elsewhere is not shown yet.
Rename a session
Right-click the session in the Workspace tree and choose Rename Session.
Delete a session
Right-click the session and choose Delete Session. The datasets and files themselves are untouched.
Display settings#
Show variable labels in column headers
By default, column headers show the variable name (e.g. AEBODSYS). To show the variable labels instead (e.g. "Body System or Organ Class"), open Quick Open (Q), type labels and run Show Variable Labels. Show Variable Names switches back.
Tip
Label mode is especially helpful when reviewing datasets with cryptic variable names. Name mode is faster for programmers who know the names by heart. The Variables panel always shows both.
Dark mode
Choose View → Toggle Dark Mode. Dark mode reduces eye strain during long review sessions; the preference persists across restarts. The Appearance tab of Options sets the fonts.
Adjust font size
In a data window, the Frequency panel or the Variables panel, press Ctrl++ to make the font larger and Ctrl+- to make it smaller; the size is remembered. Text documents and PDFs zoom with View → Zoom In, Zoom Out and Actual Size (Ctrl+0).
Markdown documents
A .md file opens rendered. Click Source on its toolbar, or press Ctrl+Shift+V, to see or edit the Markdown; Rendered switches back.
Window title
The title bar shows the full path of the active file after the product name, so two files with the same name in different transfers are told apart at a glance.
SDTM tools#
StatDataViewer includes built-in support for CDISC SDTM conventions, reducing the need to write code for common SDTM review tasks.
Join a domain with its supplemental (SUPP__) dataset
Right-click an SDTM domain such as AE in the Workspace tree and choose Join with SUPPAE (the menu names the supplemental dataset it found). StatDataViewer looks for the matching SUPPAE dataset in the same folder, then performs the IDVAR/IDVARVAL pivot and merges the supplemental parameters as new columns. The joined dataset opens in a tab named AE + SUPPAE.
The result is a new transposed view — no code required. The join is non-destructive: the original datasets are unchanged.
SDTM convention handled automatically
StatDataViewer follows the CDISC SDTM IG convention: supplemental datasets are identified by the SUPP prefix followed by the domain code. IDVAR and IDVARVAL are used to match rows. All QNAM values become individual columns in the joined view.
Requirement
The supplemental dataset (SUPP__) must be in the same folder as the parent domain, in the same format (.sas7bdat or .xpt), for the join to be offered. If they are in different folders, copy the supplemental dataset next to its domain first (the Workspace file manager does this with F5).
→ Blog: How to Review SDTM Data Faster — A Clinical Programmer's Guide
Compare datasets#
Compare Datasets is StatDataViewer's replacement for PROC COMPARE. It matches the rows of a base dataset and a compare dataset by their ID variables and shows the differences cell by cell, in an interactive window rather than a listing. It is built for validation, re-run checks and amendment reviews; the comparison itself takes well under a second even on a 600 MB ADaM dataset.
Open the Compare Datasets window
Go to Tools → Compare Datasets. The first row of the window holds the Base and Comp file pickers, the ID button and the Compare button. You can also pick the two files in the Workspace (one on each side, or two marked) and click Compare there, or use Set as Compare Base and Set as Compare Dataset on a dataset's right-click menu.
Set up a comparison
- Base: the reference version (e.g. the previous delivery). Any supported dataset format works, so a SAS dataset can be compared with an
.xpt, an R.rdsor a CSV. - Comp: the dataset you want to compare against the base (e.g. the new delivery). Both files are read in the background as soon as they are chosen.
- ID variables: the variables that identify a row, such as
STUDYID USUBJID AESEQ. The window suggests a key from the CDISC naming (subject, parameter, visit, sequence) and checks it: a✓on the ID button means every row has a key of its own in both datasets, a⚠means duplicate keys, and the tooltip says how many. Click the button to open Select ID Variables and change the list. With no ID variables, rows are matched by position. - Variables: before the comparison runs, the Variables view lists the variables of both datasets side by side, with the type, length, format and label of each, so structural differences show before any value is compared.
Run the comparison
Click Compare. The window switches to the Observations view: three panes, the ID variables on the left, the Base values in the middle and the Comp values on the right, scrolled together. Rows are in key order; cells that differ are highlighted, and the variables with differences come first. The status line counts the rows of each kind: base, comp, matched, equal, different, base-only, comp-only.
The toolbar filters what is shown:
- Variables kinds:
=(same attributes in both),≠(type, length, format, informat or label differ), Base only, Comp only. - Observations kinds: rows whose values are equal, rows whose values differ, rows only the base has, rows only the compare has. Equal rows are hidden automatically after a compare, so the differences are what you see first.
- Columns
≠/=: show only the variables whose values differ in the rows shown, or also the ones that agree. - ◀ Prev and Next ▶ (keys P and N) walk the differences one by one. G jumps between a variable's column and its row in the Variables view.
Filter, frequencies and Go to inside the comparison
The Filter box takes a SAS expression and keeps a row when either side matches it: USUBJID = "01-701-1015" or AVISITN >= 4. The same keys as in a data window build it from a cell: D / = this value, I the selected values, ^ not this value, > / <, C clear, Z undo one step. F opens a Base / Comp frequency of the current column over the rows shown, with the counts that differ marked. Ctrl+L opens Go To: type a row number or a key value.
Options and report
Options opens Comparison Options: Ignore case when comparing text, Treat blanks as missing, and a Numeric tolerance for values that differ only by floating-point noise. Report writes a PROC COMPARE Report in SAS's own layout (data set summary, variables summary, observation summary, value comparison results) that can be filed with the validation.
ECDOSE & ECSTDTC · 1 row in compare only (01-701-1047) · 4 matched rows
STUDYID USUBJID ECSEQ. Cells that differ are highlighted red (base) and green (compare); unmatched rows are flagged separately.Tip — compare across libraries and formats
The base and compare datasets do not need to be in the same library or the same format. Compare the SAS adeff.sas7bdat of a PREV_DELIVERY library against the R adeff.rds of a CURRENT_DELIVERY library, or a transfer's .xpt against the .sas7bdat it was made from.
→ Blog: PROC COMPARE Without SAS — Dataset Comparison in StatDataViewer
Compare files & folders#
Two more compare tools cover the rest of a delivery: programs, logs and listings are compared line by line in the Compare Files window, and two folders are compared file by file in Compare Folders.
Compare two text files
Choose Tools → Compare Files… and pick the left and right files (type a path, pick a recent file, or drop a file on the box). The comparison opens in a window of its own, so it can sit next to the main window: the two files side by side, with bands between them that connect the changed blocks, an overview strip, and the words that changed marked inside each changed line. The files' encoding, line endings and final newline are kept, and a difference only in those is reported as such.
Other ways in: a program tab's right-click Compare submenu (with the saved file, another tab, the clipboard or a file), the Workspace's Compare button with a file chosen on each side, and a double-click on a differing file in Compare Folders.
Walk the differences
| Key | Action |
|---|---|
| F7 / Alt+↓ | Next difference |
| Shift+F7 / Alt+↑ | Previous difference |
| Alt+Home / Alt+End | First / last difference |
| Ctrl+E | Switch editing on; the files are read-only until then |
| Alt+→ / Alt+← | Copy the current difference to the right / to the left (macOS: Ctrl+Option+→ / Ctrl+Option+←) |
| Ctrl+S | Save every changed file; Save Left and Save Right save one side |
| Ctrl+R | Reload both files from disk |
Hide Unchanged shows only the differences with a few lines of context around each; Details shows the current difference in full below the files; Swap exchanges the sides. Under Ignore, Ignore Case, Ignore Blank Lines and Ignore Text Matching Patterns leave out what does not matter, for example the date stamp a SAS log prints on every page (Edit Patterns… holds the patterns, with Restore SAS Defaults).
Compare two folders
Choose Tools → Compare Folders…, or right-click a library or folder in the Workspace and choose Compare Folders…. Choose Directory A and Directory B, tick Include subfolders if needed, and click Compare. Every file is paired by its relative path (case-insensitively on Windows and macOS) and classified Same, Different, Left only or Right only; the Show boxes filter the list, and same files are hidden by default. The default comparison uses size and modification time; tick Compare by content to compare the bytes.
Double-click a Different text file to see it in Compare Files; a left-only or right-only file opens on its own. Synchronize… copies files in the direction of the Sync column (A → B, B → A, or none per row) and asks before it starts; existing files are overwritten and nothing is deleted.
Find in files & regex tester#
Find in Files
Choose Edit → Find in Files (Ctrl+Shift+F). Type the text or pattern, choose the Directory (the Workspace's current folder is offered), the file patterns (*.sas;*.r;*.txt by default) and what to Exclude (.git;output;*.bak), and click Find All. Match case, Whole word and Use regex work as in the editor's own find bar, so a quoted string such as "Demo" is found whole. The search runs in the background; the button becomes Stop while it runs.
Results are a tree, one branch per file and one line per match, with the match highlighted. Double-click a match to open the file at that line. Copy Path, Copy Line and Remove from Results are on the right-click menu; Expand All and Collapse All fold the tree.
Replace in Files
Edit → Replace in Files (Ctrl+Shift+H, Stat Studio) adds a Replace box. Work through the matches one at a time with Replace and Skip, replace the ticked matches of one file with Replace in File, or every ticked match with Replace All. In regex mode \1, \2 stand for the groups. Undo puts back the files the last replace changed. Each file keeps its encoding, BOM and line endings; files with unsaved changes in the editor, and files changed since the search, are left alone and reported.
Regular Expression Tester
Choose Tools → Regular Expression Tester… (or Test Regex… in Find in Files). Type an expression and a text: every match is highlighted, the current match is broken down into its groups, and the Means pane explains each piece of the expression in words, in the style of The Regex Coach. Select a part of the expression to see which part of the match it produced. Two modes:
- Find / Replace (PCRE2): the syntax of the editor's Find, Replace and Find in Files. Use in Find in Files carries the pattern over.
- SAS PRX: a pattern as
PRXPARSEandPRXMATCHtake it (/expr/i), or a substitution forPRXCHANGE(s/expr/replacement/). Each line of the text is one value; the position shown is the byte position PRXMATCH returns, and the SAS Code tab writes the DATA step that applies the pattern.
Search SAS logs for issues
Choose Tools → Search Log Issues in Folder..., pick a folder of .log (and .lst) files, and click Scan. Every ERROR, WARNING and important NOTE (uninitialized variables, merge repeats, format conversions, and so on) is listed with its file and line; the Errors, Warnings and Notes boxes filter the list, the pane on the right previews the log around the selected line, and a double-click opens the log at that line. Configure rules… edits the prefixes and phrases that count as an issue. In an open log tab, F8 and Shift+F8 walk the issues.
External files#
StatDataViewer is not limited to statistical datasets. It opens Excel workbooks, CSV files, PDF, Word and RTF documents, Markdown and plain text directly, so you can keep your entire review in one application: the tables, the programs and logs that made them, and the outputs they went into.
Open an Excel file
Add a folder containing .xlsx files as a library (or use File → Open Excel Files). Excel files appear in the library listing alongside SAS datasets. Double-click to open; the sheets are tabs inside the document. Filtering, frequency, and copy/export work the same as with statistical datasets. The XLSX menu appears while a workbook is active: Show Excel Formatting shows the cells as Excel styles them, Clear Formats shows the raw values, and Auto Fit Columns / Auto Fit Rows size the grid to its contents. Charts embedded in the workbook are shown in the Charts panel.
Supported Excel features
StatDataViewer reads cell values, data types, sheet names, cell formatting and embedded charts. Cell formulas are shown as their computed result. Merged cells are unmerged automatically for clean tabular display. Older .xls workbooks open from the Workspace too.
Open a PDF file
Add a folder containing .pdf files as a library. PDF files appear in the listing. Double-click to open in the built-in PDF viewer. Navigation (N / P for the next and previous page), zoom, bookmarks (B), annotations (A) and text search (Ctrl+F, then Ctrl+G for the next match) are available within the viewer.
Open Word and RTF outputs
.docx and .rtf files, the usual formats of tables, listings and figures, open in a page viewer fitted to the window's width, with the same find keys as the PDF viewer. Text can be selected and copied.
Supported formats summary
| Format | Extension(s) | Notes |
|---|---|---|
| SAS dataset | .sas7bdat | Full support including formats, labels and compressed files |
| SAS transport | .xpt | V5 and V8 transport files |
| R data | .rds, .rdata, .rda | Data frames, tibbles and workspaces; R dates and times |
| SPSS | .sav | Value labels shown |
| Stata | .dta | Stata 12–18 |
| JMP | .jmp | JMP data tables |
| CSV | .csv | Delimiter and types detected; a table and a text view in the Workspace preview |
| Dataset-JSON | .json, .ndjson | CDISC Dataset-JSON 1.1 |
| Define-XML | .xml | Rendered with its style sheet, with a table view of the metadata (File → Open Other Data Files) |
| Excel | .xlsx, .xls | Multi-sheet, formatting and charts, read-only |
.pdf | Built-in viewer with search, bookmarks and annotations | |
| Word, RTF | .docx, .rtf | Page viewer for tables, listings and figures |
| Programs and logs | .sas, .r, .log, .lst, .txt | Syntax highlighting; SAS logs with an issue bar; listings as plain text |
| Markdown | .md, .markdown | Rendered view with a source toggle |
Parquet, Arrow and database connections are not supported.
Options & shortcut keys#
Open the Options dialog
Choose Edit → Options (on macOS the same item sits in the application menu, as Settings…). The dialog is organized into tabs:
- General: the application language, the unique-ID variable that N counts (
USUBJIDby default), and confirmations such as asking before an open dataset is reloaded. - Appearance: the table font and the other fonts of the application; dark mode follows View → Toggle Dark Mode.
- File Associations: the name patterns that link datasets to their programs, logs and outputs (see the Workspace section).
- Keyboard Shortcuts: every command of the application with its keys; change any of them (see below).
- Editor, SAS Format, R and Apps (Stat Studio): auto-indent, completion and the as-you-type check of the program editor; the Format SAS Code sample; the R executable; and the SAS command that apps with ENGINE=SAS run on.
Change the keyboard shortcuts
On the Keyboard Shortcuts tab, find the command with the search box (the list is grouped by window: File, Edit, View, Run, Text Editor, Find Bar, Dataset Window, Frequency Window, Variables Window, PDF, Compare Files Window, Compare Datasets, Workspace, Workspace File Panel), select it, press the new key in the Key box and click Assign Here. A command may have more than one key. The Conflicts column shows a key that another command of the same window already uses; assigning it takes the key from the other command. Reset to Default and Reset All restore the defaults, and Export… / Import… save the keys as a JSON file to carry to another machine. OK applies the change at once, in menus and widgets alike.
Show Shortcut Keys dialog
Choose Help → Show Shortcut Keys. A dialog lists every keyboard shortcut available in the application as it is set now, organized by window, and updates when you change a key. It is searchable: type any action or key to filter the list, for example filter to see every shortcut related to filtering.
Check for updates
Choose Help → Check for Updates. StatDataViewer contacts the update server and shows the installed version alongside the latest available version. Click Download to get the installer. The App Store and Microsoft Store builds update through the store instead. See the Changelog for what changed in each release; Help → About shows the installed version, for example 2.6 (2026.10.11).
Program editor & StatScript#
Stat Studio adds a program editor for SAS and R, and three ways to run what you write: StatScript, the SAS language engine built into StatDataViewer, which runs DATA steps, PROC SQL and the usual reporting and statistical procedures on your own machine with no SAS license; SAS Enterprise Guide through SDVBridge; and SAS Studio through the browser extension. R programs run on a local R or over Rserve. Without Stat Studio, programs and logs still open read-only with syntax highlighting.
Write a program
Choose File → New SAS Program (Ctrl+N), New R Program or New SAS Shiny Program, or double-click a .sas or .r file in the Workspace. A file opened from disk is read-only at first: press I to start editing and Esc to lock it again (the toolbar's Read Only button does the same), so a production program is not changed by accident. Ctrl+S saves, Save As... (Ctrl+Shift+S) saves a copy. The editor keeps the file's encoding, line endings and BOM.
Run it
The program toolbar has Run (F3, the selection if there is one, else the whole program), Run Sel (the selection), and Run Current (Ctrl+Enter): the DATA or PROC step at the cursor, a whole macro definition, or the single statement, found from the program's structure rather than from blank lines. The lines about to run are tinted for a moment so you can see what was sent. The Run menu names the same three commands Submit, Submit Selection and Submit Current Step/Line; Stop Submit (Shift+F3) interrupts a run.
The engine selector next to the Run button chooses where the code runs: StatScript, SAS EG or SAS Studio; the last two show (not connected) until you connect. Each program tab has its own Log (F6) and Output (F7) panels below the editor, with a dashed line where each run begins. In the log, F8 and Shift+F8 jump to the next and previous ERROR or WARNING, and the issue bar above the editor lists them; clicking one goes to the program line that caused it.
The StatScript session
Datasets a StatScript run creates stay in a session shown in the Workspace tree under StatScript Session: WORK, the libraries you assigned with LIBNAME, and the built-in SASHELP members. Double-click one to open it, or press Ctrl+Shift+D on a libref.dataset name in the program (Open SAS Dataset from Selection); with nothing selected it opens the last dataset the run created (Open Last Data Set). The session lives as long as the application, so a later run sees what an earlier one made.
Editing
- Find and replace: Ctrl+F opens the find bar with Match case, Whole word, Use regex and In selection; Ctrl+G / Ctrl+Shift+G go to the next and previous match, Edit → Replace adds the replace row, and Find Next Non-ASCII Char finds the characters SAS will complain about.
- Completion: Ctrl+Space (macOS: Option+Esc) completes keywords, variable and dataset names; hovering a name shows what is known about it.
- Lint: syntax problems are underlined as you type (the check uses StatScript's own parser), and a run's ERRORs are listed in the issue bar above the editor. Both can be turned off on the Editor tab of Options.
- Comment Selection Ctrl+/, Duplicate Line Ctrl+D, Uppercase / Lowercase Selection Ctrl+Shift+U / Ctrl+Shift+L (quoted strings are left as they are), Convert Tabs to Spaces, Remove Trailing Whitespace, Word Wrap Alt+Z, Go to Line Ctrl+L.
- Column selection: Alt+Shift+↓ or Alt-drag selects a rectangle; typing edits every line of it, Esc leaves.
- Bookmarks: Ctrl+F2 toggles one, F2 and Shift+F2 go to the next and previous. They work in datasets too.
Fold by structure
SAS programs fold by their structure: %macro definitions, DATA and PROC steps, do / select / %do blocks, multi-line comments and %* section headers, nested level by level. Click the gutter marker or the … N lines box; Alt+0 folds everything and Alt+Shift+0 unfolds it; Ctrl+Shift+[ / Ctrl+Shift+] (macOS: Ctrl+Option+[ / Ctrl+Option+]) fold and unfold at the cursor; Ctrl+K then 1…9 folds to that level, so Ctrl+K 1 leaves only the steps and macros visible. Folds move with the text as you edit.
Format SAS Code
Choose Edit → Format SAS Code (also in the toolbar's More menu) to lay the program, or the selection, out consistently: indentation, one statement per line, spacing around = and commas, blank lines between steps. The rules are not a list of options: on the SAS Format tab of Options you edit a sample program the way you like it, and the formatter follows the sample. Keyword case and spelling are never changed, and formatting is one undo step.
SDVBridge — SAS Enterprise Guide integration#
SDVBridge is a free custom task for SAS Enterprise Guide that runs a small local web server inside your EG session. StatDataViewer connects to it to browse the SAS servers, libraries, and datasets that EG can see, open those datasets, and submit SAS programs through EG — so you work with your EG session's data and servers without exporting files by hand.
Install SDVBridge
- Download
SDVBridge.zipfrom the Download page and extractSDVBridge.dll. - Close SAS Enterprise Guide.
- Copy
SDVBridge.dllinto%AppData%\SAS\EnterpriseGuide\8\Custom— that is,C:\Users\<you>\AppData\Roaming\SAS\EnterpriseGuide\8\Custom(create theCustomfolder if it does not exist). Alternatively, register the DLL with Tools → Add-In Manager → Browse in EG. - Right-click the copied
SDVBridge.dlland choose Properties. If the General tab shows an Unblock checkbox, tick it and click OK. Windows blocks DLLs downloaded from the internet, and EG will not load a blocked DLL. - Start SAS Enterprise Guide. SDVBridge appears in the Tasks pane under Helper Software → SDVBridge.
Requires SAS Enterprise Guide 8.2 or later on Windows.
Start the bridge in SAS EG
- Open Tasks → Helper Software → SDVBridge. The SDVBridge REST Server dialog appears.
- Keep the default port
17832(or enter another) and click Start. The dialog showsServer running at http://127.0.0.1:17832/. - Click Stop when you are done; the bridge also stops when EG exits.
The optional Server Log Path and Server Output Path fields are for remote SAS servers: when both are set, SDVBridge writes the SAS log and listing to those files on the SAS host and copies them back to your PC. Fill in both or leave both empty; the paths must be writable by your SAS workspace account and are remembered for next time.
Connect from StatDataViewer
- In StatDataViewer, choose File → Connect to SAS EG and accept the default base URL
http://127.0.0.1:17832/(change the port only if you changed it in SDVBridge). - The Workspace tree gains a SAS EG node listing the session's servers. Right-click a library and choose Load Datasets (or Refresh after your code creates new datasets).
- Right-click a dataset to View Columns, Preview its first rows, or Open Dataset — SDVBridge copies the dataset from the SAS server and StatDataViewer opens it.
- Submitting a SAS program with the toolbar engine selector set to SAS EG runs it through EG and returns the log and results. To target a specific server, right-click it and choose Submit Programs to This Server; otherwise EG's default server is used.
Note
SDVBridge listens only on 127.0.0.1, so it cannot be reached from other machines. Datasets you open are copied to %TEMP%\SDVBridge; delete them when you no longer need them. If Windows refuses to start the server, reserve the URL once from a Command Prompt with netsh http add urlacl url=http://127.0.0.1:17832/ user=%USERNAME%. Diagnostics are logged to %TEMP%\SDVBridge\Logs\SDVBridge.log.
SAS Studio Helper — browser extension#
SAS Studio Helper is a Chrome extension that bridges your SAS Studio browser session (for example SAS OnDemand for Academics or a corporate SAS Viya deployment) to StatDataViewer on the same computer. Once connected, StatDataViewer can browse the session's libraries and files, open datasets, and submit SAS programs — every request travels through your existing authenticated browser session, so there are no extra credentials to manage.
Install the extension
- Install SAS Studio Helper from the Chrome Web Store.
- Pin the extension to the toolbar, then open its Options page (right-click the toolbar icon → Options).
- Under SAS Studio hosts, add each SAS Studio deployment you use (e.g.
odamid-usw2.oda.sas.com). Chrome asks permission for that origin. - Under StatDataViewer, keep port
53210unless it clashes with something on your machine.
Connect from StatDataViewer
- In StatDataViewer, choose File → Connect to SAS Studio. Keep the default port
53210; optionally generate a token and enter the same token in the extension's options for authenticated connections. - Open (or reload) a SAS Studio tab in Chrome and sign in. The extension detects the session and connects to StatDataViewer automatically.
- The Workspace tree gains a SAS Studio node with the session's Files and Libraries. Double-click datasets to open them; right-click a library and choose Refresh after your code creates new datasets. Submitting with the engine selector set to SAS Studio runs the program in the browser session and returns the log and results.
Note
The extension and StatDataViewer talk over a local loopback WebSocket (127.0.0.1:53210). Your SAS credentials never pass through StatDataViewer — the browser session remains the only place you are signed in.
Connect to R (Rserve)#
StatDataViewer can run R programs, the R console, and the R-session workspace browser against an Rserve server instead of launching a local R process. In the Mac App Store build this is the way to use R (the sandbox does not allow launching the system R directly), and it also lets you run R on another machine.
Install and start Rserve
On the machine that has R, install the package once:
install.packages("Rserve")
Then start the server (defaults to 127.0.0.1:6311, no authentication):
R -e 'Rserve::Rserve()'
Connect from StatDataViewer
- Choose File → Connect to R (Rserve)… and accept the default host and port. User and password are only needed when the server is configured to require login.
- While connected, R programs, the R console, and the R Session tree all execute on the Rserve session — one shared workspace that persists across submissions.
- Disconnecting (or choosing Stop during a run) falls back to the local R process on the next submission.
Note — Stop drops the connection
The Rserve protocol has no way to interrupt a running command, so Stop disconnects instead. Reconnect to continue; the server-side workspace of that session is discarded.
Tip — remote servers
The connection is plain TCP. For a server on another machine, prefer an SSH tunnel: ssh -L 6311:127.0.0.1:6311 yourserver, then connect StatDataViewer to 127.0.0.1:6311 as usual. Opening data frames from the R Session tree requires the app and the R session to share a filesystem, so it is available for local (127.0.0.1) servers.
SAS Shiny apps (PROC APP)#
SAS Shiny lets you build interactive apps in SAS, in the spirit of R Shiny: you declare inputs (drop-downs, sliders, check boxes…), outputs (tables, graphs, value boxes, downloads), and blocks of ordinary SAS code that fill them. When the viewer changes an input, every block that reads it runs again and its output updates. The whole app is one SAS program with a PROC APP step; StatDataViewer's built-in SAS engine runs it, so no SAS license is needed. With ENGINE=SAS the code can also run on your own SAS 9.4 server (below).
SAS Shiny is part of Stat Studio, from version 2.6 (2026.10.11) on.
Your first app in a minute
- Create it. Choose File → New SAS Shiny Program. An untitled program opens with a complete app: an Iris explorer on
SASHELP.IRIS(built into StatDataViewer, likeSASHELP.CLASS) with inputs in a sidebar, a value box, a scatter plot, a table, and a CSV download. - Run it. Click Run (or press F3). The app opens in an App tab next to the program; the log notes that it is running.
- Use it. Pick another species, other X and Y variables, or drag the sepal length slider: the plot, the table, and the count follow. Hover over a point to see the flower's four measurements.
- Change it. Edit the program and click Reload in the App tab's toolbar (or run the program again). Open in Browser shows the same app in your web browser.
How an app is put together
The smallest app has an input, an output, and the block that fills it:
proc app name=hello title="Hello, PROC APP";
textinput who / label="Your name" value="world";
sliderinput times / label="How many times" min=1 max=5 value=2;
textoutput greeting;
render greeting;
data _null_;
file print;
do i = 1 to ×
put "Hello, &who!";
end;
run;
endrender;
run;
- Each input is a macro variable named by its id. The block reads it as
×or&who, so it reruns when either changes. - Each output needs exactly one
RENDERblock. What the block prints becomes the output: a PROC PRINT, SQL, FREQ or REPORT table becomes a sortable table, a PROC SGPLOT graph becomes the plot,file printtext becomes the text. - The code between
RENDERandENDRENDERis kept as written and runs each time;RUN;inside a block does not end the step. The app ends at the finalRUN;. - Code before the
PROC APPstep (a LIBNAME, a DATA step that prepares data, macro definitions) runs once when the app starts.
Statements at a glance
| Kind | Statements | What they do |
|---|---|---|
| App | PROC APP NAME= TITLE= THEME=(PRIMARY= MODE= DENSITY=) ENGINE= … RUN; |
Names the app; THEME= sets its color (primary=teal), light or dark mode, and spacing. |
| Inputs | SELECTINPUT RADIOINPUT CHECKBOXGROUPINPUT SLIDERINPUT NUMERICINPUT CHECKBOXINPUT TEXTINPUT TEXTAREAINPUT DATEINPUT DATERANGEINPUT FILEINPUT ACTIONBUTTON |
Controls the viewer sets. Common options: LABEL=, VALUE= (the starting value), CHOICES=, MIN=/MAX=, MULTIPLE, HELP=. |
| Outputs | TABLEOUTPUT PLOTOUTPUT TEXTOUTPUT VALUEBOXOUTPUT DOWNLOADBUTTON |
Where results appear. A value box shows the first cell of its block's last table (select count(*) as n label="Subjects"). |
| Blocks | INIT REACTIVE name RENDER output DOWNLOAD output … END…; |
SAS code. INIT runs once per session; REACTIVE name makes the data set WORK.name for other blocks; RENDER fills an output; DOWNLOAD writes a download button's file. |
| Layout | LAYOUT SIDEBAR | TABS | NAVBAR | NAVLIST | COLUMNS | ROWS, CARD, SHOWIF, TEXT, MARKDOWN |
Arranges the page: a sidebar with a main area, tabs, a menu down the side, columns in twelfths (widths=(4 4 4)), framed cards, parts shown only while a condition on the inputs holds. |
| Data | REQUIRE libref.member(variables) |
States the data the app needs and the variables it uses. |
Without a LAYOUT, inputs go in a sidebar and outputs in the main area. Blocks go after the layout. StatDataViewer checks the app when you run it and reports problems in the log with their line numbers, for example an output without a RENDER block or a starting value that is not one of the choices.
Input values in your code
&idis the value as text: a list (a multiple select, a check box group, a range slider) is blank-separated, a check box is 0 or 1, a button its click count, a dateDATE9..%qval(id)is the value as SAS literals, ready for a WHERE clause:where species = %qval(species);or, for a list,where trta in (%qval(arms));. Quotes,&,%and;in a value are always text, never code.- A range slider (
value=(50 70)) gives two numbers:between %scan(&sl, 1, %str( )) and %scan(&sl, 2, %str( )). - Choices can come from data:
choices=(from=sashelp.iris.species)lists the variable's distinct values, andmin=(from=sashelp.iris.sepallength)its smallest value. Naming aREACTIVEblock's data set (choices=(from=work.types.type)) makes the choices follow it, like Shiny'supdateSelectInput: incars_explorer.sasbelow, pick an origin and the type list changes.
When blocks run
A block runs again when an input or a reactive data set it reads changes. Options after a / on the block statement change that:
| Option | Effect |
|---|---|
REQ=id REQMSG="text" | Wait until the input has a value; show the text meanwhile (Shiny's req()). |
EVENT=button | Run only when this input changes, usually an ACTIONBUTTON (eventReactive). IGNORENULL=NO also runs it before the first click. |
ISOLATE=(id …) | Read these inputs without rerunning when they change. |
EVERY=ms | Run again that long after the last run (a live dashboard). |
%appmsg(text) | Inside a block: stop and show the text instead of the output, e.g. after a PROC SQL query: %if &sqlobs = 0 %then %do; %appmsg(No rows match.); %end; |
Inputs that change quickly (sliders, text) wait a moment before the blocks rerun; DEBOUNCE=ms on the input sets how long.
Tables, graphs, and downloads
- Tables:
tableoutput models / pagesize=10 sort=(descending msrp) filter;pages the rows, sets the first sort order, and adds a filter under each heading.HIDE=hides columns,FREEZE=nkeeps the first columns in place. PROC REPORTSTYLE=colors (including traffic lighting by format) are kept. - Graphs: every PROC SGPLOT graph has data tips;
tip=(make model msrp)chooses what they show.plotoutput fig / brush=sel;lets the viewer drag a box on the plot, andwhere %brushed(sel);in another block selects the rows inside it;click=with%nearpoints()does the same for a click. - Selecting rows:
tableoutput subjects / select=pick key=usubjid;turns a click on a row into the inputpick(where usubjid in (%qval(pick))). - Downloads: a
DOWNLOADBUTTONruns itsDOWNLOADblock when clicked, which writes through the filerefDOWNLOAD:proc export data=work.picked outfile=download dbms=csv replace; run;, orods rtf file=download;for a report.FILENAME="iris.csv"names the saved file.
Coming from R Shiny
| R Shiny | PROC APP |
|---|---|
selectInput(), sliderInput(), actionButton() … | SELECTINPUT, SLIDERINPUT, ACTIONBUTTON … |
input$x | &x, %qval(x) |
reactive() | REACTIVE name; … ENDREACTIVE; (makes WORK.name) |
renderTable() / renderPlot() + tableOutput() / plotOutput() | RENDER id; … ENDRENDER; + TABLEOUTPUT / PLOTOUTPUT |
eventReactive(), req(), isolate(), invalidateLater() | EVENT=, REQ=, ISOLATE=, EVERY= |
validate(need(…)) | %appmsg(text) |
updateSelectInput(), updateSliderInput() | CHOICES=(FROM=work.reactive.var), MIN=(FROM=…) |
downloadButton() + downloadHandler() | DOWNLOADBUTTON + DOWNLOAD id; … ENDDOWNLOAD; |
sidebarLayout(), tabsetPanel(), navbarPage(), fluidRow()/column() | LAYOUT SIDEBAR, TABS, NAVBAR, COLUMNS / WIDTHS= |
conditionalPanel(), bslib card(), valueBox() | SHOWIF, CARD, VALUEBOXOUTPUT |
Example apps
Download an example, open it in StatDataViewer, and run it. They use the SASHELP data sets (and simulated data), so they run as they are. Download all examples (.zip).
| Example | What it shows |
|---|---|
| hello_app.sas | The smallest app: a text input, a slider, and a text output. |
| iris_explorer.sas | The app File → New SAS Shiny Program starts with: a sidebar, choices from data, a range slider, a value box, a scatter plot with a fit line and data tips, a sorted table, and a CSV download. |
| cars_explorer.sas | Choices that follow another input (pick an origin and the list of types changes), on SASHELP.CARS. That data set comes with SAS, not with StatDataViewer: add ENGINE=SAS to run it on your SAS server. |
| class_dashboard.sas | A dashboard: a navigation list, three value boxes in columns, cards, and a paged roster. |
| iris_kmeans.sas | Shiny's k-means example: PROC FASTCLUS reruns when Recluster is clicked (EVENT=). |
| ae_explorer.sas | Adverse events by treatment on simulated ADaM-style data: a check box group, REQ= with a message, a clustered bar chart, and a filterable table of preferred terms. |
| on_your_sas.sas | ENGINE=SAS: the same kind of app with its blocks run on your SAS server (needs the SAS command below). |
Run the code on your SAS server (ENGINE=SAS)
When your data and validated code live on a SAS 9.4 server, write proc app name=… engine=sas;. StatDataViewer keeps the app itself (the inputs, what reruns what, the layout) and sends the SAS code to your SAS: the program around the PROC APP step runs there once when the app starts, and every block runs there with the input values as macro variables. Tables and graphs are SAS's own ODS output.
- Open the Settings dialog and go to the Apps tab.
- In SAS command, enter how to start SAS: the path of
saswhen SAS is installed on this computer, or for a SAS server on your networkssh -T -o BatchMode=yes user@sasserver /opt/sas/SASHome/SASFoundation/9.4/sas - Click Test. StatDataViewer starts SAS once, runs a block with a table and a graph, and reports the SAS version and session encoding, how long each part took, and whether the table and the graph came back.
- Run an app with
ENGINE=SAS. Each app session starts its own SAS process and ends it when the App tab closes.
Note — what differs on SAS
SAS draws its own graphs, so a plot or table filled by a block on SAS cannot take CLICK=, BRUSH=, HOVER= or SELECT=; give that block / engine=statscript to run it in StatDataViewer instead (it receives a copy of the reactive data sets SAS made). %appmsg stops a block at the end of the current step. The log's line numbers are those of the SAS session. ENGINE=SAS is not available in the Mac App Store version, whose sandbox cannot start SAS or ssh.
Tip — ssh keys
StatDataViewer never types a password for ssh: set up key-based login to the SAS server first (ssh-keygen, then add your public key to ~/.ssh/authorized_keys on the server), and check that ssh user@sasserver logs in without asking.
Note — PROC APP is a StatDataViewer extension
SAS itself has no PROC APP, so run app programs in StatDataViewer. A program with a PROC APP step opens its App tab whichever engine the toolbar's engine selector names; the app's code runs in StatDataViewer's built-in engine unless the app says ENGINE=SAS.
Data lineage (PROC LINEAGE)#
PROC LINEAGE answers two questions about a SAS program, variable by variable: how was this variable made? and what does it go into? Turn on OPTIONS LINEAGE and run your program. PROC LINEAGE then:
- describes every variable of every data set the program made, in plain English: copied from which variable, computed by which formula, under which conditions, from which records;
- traces any variable up to the raw data it comes from, or down to every data set, table and figure it reaches (impact analysis);
- writes it all as data sets: derivations, value-level metadata and code lists in the form define.xml needs. It can also write the whole model as a JSON file.
The descriptions come from the program's code, not from the rows it happened to process: a branch that no record reaches is still described, with the conditions that lead to it. Macro code is described as the macros generate it, and the JSON file says which %INCLUDE file or macro each line belongs to.
PROC LINEAGE is a StatDataViewer extension: SAS has no procedure like it. SAS's PROC SCAPROC only records which data sets a job reads and writes. PROC LINEAGE runs in StatScript, StatDataViewer's built-in SAS engine, so no SAS license is needed. It is part of Stat Studio, from version 2.6 (2026.10.11) on.
Lineage in a minute
- Turn it on. Put
options lineage;at the top of your program. The steps after it are recorded;options nolineage;stops recording. - Run the program as usual (Run, or F3).
- Ask for the lineage. Add
proc lineage; run;at the end of the program, or submit it on its own afterwards. The Output window lists each data set the program made, with every variable's origin and derivation. - Follow one variable.
trace work.adsl.agegr1;lists what AGEGR1 is made from, level by level.trace sdtm.dm.age / downstream;lists everything a change to AGE would reach.
Example 1: describe how each variable is derived
A DATA step on SASHELP.CLASS (built into StatDataViewer) computes a BMI and a BMI category. A PROC SQL step then summarizes them. DATA= chooses the data set to describe:
/* Lineage of a small derivation on SASHELP.CLASS */
options lineage;
data work.class_bmi;
set sashelp.class;
where age >= 12;
bmi = round(weight / height**2 * 703, 0.1);
if bmi < 18.5 then bmicat = 'Underweight';
else if bmi < 25 then bmicat = 'Normal';
else bmicat = 'Overweight';
label bmi = 'Body mass index' bmicat = 'BMI category';
run;
proc sql;
create table work.bmi_summary as
select sex, bmicat, count(*) as n, mean(bmi) as mean_bmi format=5.1
from work.class_bmi
group by sex, bmicat;
quit;
proc lineage data=work.class_bmi;
run;
Output
Data Set Name WORK.CLASS_BMI
Made By Step 1, DATA step, line 7
Variables 7
Records Records of SASHELP.CLASS. Reads only the records where AGE ≥ 12.
# Variable Label Origin Derivation
1 Name Predecessor Copied from SASHELP.CLASS.NAME. Records where AGE ≥
12.
2 Sex Predecessor Copied from SASHELP.CLASS.SEX. Records where AGE ≥
12.
3 Age Predecessor Copied from SASHELP.CLASS.AGE. Records where AGE ≥
12.
4 Height Predecessor Copied from SASHELP.CLASS.HEIGHT. Records where AGE ≥
12.
5 Weight Predecessor Copied from SASHELP.CLASS.WEIGHT. Records where AGE ≥
12.
6 bmi Body mass index Derived BMI = ROUND(WEIGHT / HEIGHT ** 2 * 703, 0.1). Records
where AGE ≥ 12.
7 bmicat BMI category Derived Set to 'Underweight' when BMI < 18.5; otherwise
'Normal' when BMI < 25; otherwise 'Overweight'.
Records where AGE ≥ 12.
Code Lists
Variable Values Given By
BMICAT 'Underweight', 'Normal', 'Overweight'
- The header block says which step made the data set (Made By, with its line in the program) and where its records come from (Records: here the input's records, filtered by the
WHERE). - Origin follows define.xml:
Predecessor: copied unchanged from another data set's variable;Derived: computed;Assigned: a constant the program sets, such asSTUDYID = 'ABC01';- blank: never set, or read from raw data.
- Derivation spells out the rule: the formula with the variables it reads, the IF/ELSE or SELECT branches with their conditions, and the records the value is on.
- Code Lists lists the variables the program sets to literals and all their values. These are the raw material of define.xml code lists.
- Without
DATA=, every data set the program wrote is described, in the order it first wrote them.DATA=adam._all_describes all data sets of one library.
Example 2: trace a variable up and down
TRACE follows the lineage graph from one variable. Add the PROC SQL summary and a PROC FREQ to the program above (the full program is class_trace.sas below), then ask two questions: where MEAN_BMI comes from, and what a change to SASHELP.CLASS.WEIGHT would affect.
proc lineage data=work.bmi_summary;
trace work.bmi_summary.mean_bmi; /* where MEAN_BMI comes from */
trace sashelp.class.weight / downstream; /* what a change of WEIGHT reaches */
run;
Output
Upstream Lineage of WORK.BMI_SUMMARY.MEAN_BMI
Level Variable Version Step Line Into Relation
1 WORK.CLASS_BMI.BMI 1 2 12 WORK.BMI_SUMMARY.MEAN_BMI@2 DERIVE
2 WORK.CLASS_BMI.WEIGHT 1 1 6 WORK.CLASS_BMI.BMI@1 DERIVE
2 WORK.CLASS_BMI.HEIGHT 1 1 6 WORK.CLASS_BMI.BMI@1 DERIVE
3 SASHELP.CLASS.WEIGHT 0 1 6 WORK.CLASS_BMI.WEIGHT@1 COPY
3 SASHELP.CLASS.HEIGHT 0 1 6 WORK.CLASS_BMI.HEIGHT@1 COPY
Downstream Impact of SASHELP.CLASS.WEIGHT
Level Variable Version Step Line From Relation
1 WORK.CLASS_BMI.WEIGHT 1 1 6 SASHELP.CLASS.WEIGHT@0 COPY
2 WORK.CLASS_BMI.BMI 1 1 6 WORK.CLASS_BMI.WEIGHT@1 DERIVE
3 WORK.CLASS_BMI.BMICAT 1 1 7 WORK.CLASS_BMI.BMI@1 CONDITION
3 WORK.BMI_SUMMARY.MEAN_BMI 2 2 12 WORK.CLASS_BMI.BMI@1 DERIVE
4 WORK.BMI_SUMMARY.BMICAT 2 2 12 WORK.CLASS_BMI.BMICAT@1 COPY
4 WORK.BMI_SUMMARY 2 2 12 WORK.CLASS_BMI.BMICAT@1 RECORDS (GROUP BY)
4 PROC FREQ 3 3 19 WORK.CLASS_BMI.BMICAT@1 USE (TABLES)
- UPSTREAM (the default) starts from the variable and goes back one level at a time. Level 1 is what it is made from, level 2 is what those are made from, and so on, back to the data sets that came from outside the program (Version 0).
- DOWNSTREAM lists what the variable goes into: the variables derived from it, the data sets whose records it selects or groups (
RECORDS), and the procedures that display or analyse it (USE). That includes listings, tables and figures from PRINT, FREQ, REPORT, SGPLOT, the modelling procedures, and so on. name@nis a variable as step n wrote it, so a data set the program rewrites is followed version by version./ BOTHlists both directions,DEPTH=nstops after n levels,RECORDSalso follows what selects the records, andOUT=writes the rows to a data set.
Example 3: ADaM metadata: value-level derivations and code lists
A small SDTM-to-ADaM flow: ADSL from DM, ADVS from VS, and a derived BMI parameter. The full program, including the DM and VS data, is adam_metadata.sas below.
data adsl;
set dm;
length trt01p $8 agegr1 $5;
if armcd = 'A' then do;
trt01p = 'Drug A';
trt01pn = 1;
end;
else do;
trt01p = 'Placebo';
trt01pn = 0;
end;
if age < 65 then do;
agegr1 = '<65';
agegr1n = 1;
end;
else do;
agegr1 = '>=65';
agegr1n = 2;
end;
label trt01p = 'Planned Treatment' agegr1 = 'Pooled Age Group 1';
run;
proc sort data=vs;
by usubjid;
run;
data advs1;
merge vs(in=invs) adsl(keep=usubjid trt01p trt01pn);
by usubjid;
if invs;
length paramcd $8 param $20;
paramcd = vstestcd;
if vstestcd = 'WEIGHT' then param = 'Weight (kg)';
else if vstestcd = 'HEIGHT' then param = 'Height (cm)';
aval = vsstresn;
avisitn = visitnum;
drop vstestcd vsstresn visitnum;
run;
/* a derived parameter: BMI from each subject's weight and height */
data bmi;
merge advs1(where=(paramcd = 'WEIGHT') rename=(aval=weight))
advs1(where=(paramcd = 'HEIGHT') keep=usubjid paramcd aval rename=(aval=height));
by usubjid;
paramcd = 'BMI';
param = 'BMI (kg/m2)';
aval = round(weight / (height / 100)**2, 0.1);
drop weight height;
run;
data advs;
set advs1 bmi;
by usubjid;
run;
proc lineage data=work.advs out=advs_meta outvalues=advs_vlm outcodes=advs_codes
json="%sysfunc(pathname(work))/advs_lineage.json";
run;
For each variable that is derived differently for different parameters, the report adds one row per value of PARAMCD. This is define.xml's value-level metadata:
Output (part)
Value-Level Derivations
Variable PARAMCD Origin Derivation
AVAL 'BMI' Derived AVAL = ROUND(WEIGHT / (HEIGHT / 100) ** 2, 0.1). Reads
VS.VSSTRESN of the records where VSTESTCD = 'WEIGHT' and
PARAMCD = 'WEIGHT' and VS.VSSTRESN of the records where
VSTESTCD = 'HEIGHT' and PARAMCD = 'HEIGHT'.
AVAL 'HEIGHT' Predecessor Copied from VS.VSSTRESN. Records where VSTESTCD = 'HEIGHT'.
AVAL 'WEIGHT' Predecessor Copied from VS.VSSTRESN. Records where VSTESTCD = 'WEIGHT'.
The code lists come with their decodes. A variable whose values are given by another variable (a code and its decode, set together or through a format) lists the pairs:
Output (part)
Code Lists
Variable Values Given By
TRT01P 'Drug A', 'Placebo' TRT01PN: 1 → 'Drug A', 0 → 'Placebo'
TRT01PN 1, 0 TRT01P: 'Drug A' → 1, 'Placebo' → 0
PARAMCD 'BMI', ...
PARAM 'Weight (kg)', 'Height (cm)', 'BMI (kg/m2)' PARAMCD: 'BMI' → 'BMI (kg/m2)', 'HEIGHT'
→ 'Height (cm)', 'WEIGHT' → 'Weight (kg)'
OUT=has one row per variable: NAME, LABEL, ORIGIN, PREDECESSOR (LIB.DS.VAR), DERIVATION, and the step and line that made it.OUTVALUES=has the value-level rows: NAME, KEY, VALUE (as a SAS literal,'BMI'), ORIGIN, PREDECESSOR, DERIVATION.KEY=names the key variable; the default is PARAMCD.OUTCODES=has one row per literal: NAME, ORDER, VALUE, and CLOSED, which isYwhen those are all the values the variable can have. It also has FORMAT, and PAIRNAME / PAIRVALUE for the decode pairs (TRT01PN1 whereTRT01Pis'Drug A').PARAMCD 'BMI', ...: the trailing...says the list is not closed. PARAMCD is copied from the data for the other records, so its values are not all in the code.
Example 4: impact analysis for a summary table
In a TLF program, the denominators often travel through macro variables. Lineage follows them: the big N of each arm goes from ADSL through PROC SQL INTO into &N0 and &N1. From there it goes into the percentages, and into the title and table that PROC REPORT prints (full program: tlf_impact.sas).
/* the big N of each arm, into &N0 and &N1 */
proc sql noprint;
select count(distinct usubjid) into :n0 trimmed from adsl where saffl = 'Y' and trt01an = 0;
select count(distinct usubjid) into :n1 trimmed from adsl where saffl = 'Y' and trt01an = 1;
quit;
proc sql;
create table counts as
select trt01an, sex, count(*) as n
from adsl
where saffl = 'Y'
group by trt01an, sex;
quit;
data pct;
set counts;
if trt01an = 0 then pct = n / &n0 * 100;
else pct = n / &n1 * 100;
run;
title "Sex by treatment (N=&n0 placebo, N=&n1 drug)";
proc report data=pct;
...
run;
proc lineage data=work.pct;
trace adsl.saffl / downstream;
run;
The percentage's derivation says where the macro variables come from:
Output (part)
4 pct Derived Set to N / &N0 * 100 when TRT01AN = 0; otherwise N / &N1 * 100.
Records where SAFFL = 'Y'. Where &N0 = COUNT(DISTINCT USUBJID) over
the records of ADSL where SAFFL = 'Y' and TRT01AN = 0; &N1 =
COUNT(DISTINCT USUBJID) over the records of ADSL where SAFFL = 'Y' and
TRT01AN = 1.
Tracing the safety flag down shows everything that depends on it: the counts' records, both macro variables, the percentages, and the PROC REPORT step that uses them in its title (USE (MACRO)) and its columns (USE (ANALYSIS)):
Output
Downstream Impact of WORK.ADSL.SAFFL
Level Variable Version Step Line From Relation
1 &N0 2 2 17 WORK.ADSL.SAFFL@1 CONDITION (INTO)
1 &N1 3 3 17 WORK.ADSL.SAFFL@1 CONDITION (INTO)
1 WORK.COUNTS 4 4 22 WORK.ADSL.SAFFL@1 RECORDS (WHERE)
2 WORK.PCT.PCT 5 5 32 &N0@2 DERIVE
2 PROC REPORT 6 6 37 &N0@2 USE (MACRO)
2 WORK.PCT.PCT 5 5 33 &N1@3 DERIVE
2 PROC REPORT 6 6 37 &N1@3 USE (MACRO)
3 PROC REPORT 6 6 37 WORK.PCT.PCT@5 USE (ANALYSIS)
Statements and options
OPTIONS LINEAGE | NOLINEAGE;
PROC LINEAGE <DATA=libref.member | libref._ALL_ | _ALL_>
<OUT=> <OUTDATA=> <OUTVALUES=> <KEY=variable> <OUTCODES=>
<OUTSTEPS=> <OUTRULES=> <OUTEDGES=> <JSON=fileref | 'path'>
<DETAILS> <NOPRINT> <CLEAR>;
VAR variables;
TRACE variables </ UPSTREAM | DOWNSTREAM | BOTH DEPTH=n RECORDS OUT=data-set>;
CLEAR;
RUN;
| Option or statement | What it does |
|---|---|
DATA= | The data sets the report, OUT=, OUTDATA=, OUTVALUES= and OUTCODES= describe, each in its last version. Without it, or with _ALL_: every data set the program wrote. libref._ALL_: one library's. One data set: also what a one-level name in TRACE refers to. |
VAR | Only these variables of the data sets described (names, or prefix:). |
TRACE | Follow variables through the lineage graph. Write libref.member.variable, member.variable (WORK), or just variable when DATA= names one data set. A data set the program only read (sdtm.dm.age) can be traced downstream. Repeat the statement for more variables. |
DETAILS | Adds three pages: Steps (each step's inputs and outputs), Rules (every assignment, filter and variable use), and Lineage Graph (all edges). |
NOPRINT | Prints nothing; the OUT*= data sets and JSON= are still written. |
CLEAR | Forgets everything recorded so far, after the outputs are written. proc lineage clear; run; just starts over. |
JSON= | Writes the whole model (steps, rules, the lineage graph, the value-level derivations and code lists) to a JSON file, for other tools to read. |
Output data sets
| Option | One row per | Main columns |
|---|---|---|
OUT= | variable | LIBNAME MEMNAME VARNUM NAME TYPE LABEL ORIGIN PREDECESSOR DERIVATION STEPNO STEP LINE |
OUTDATA= | data set | MEMNAME STEP ACTION LINE NVAR INPUTS (SET SDTM.VS, MERGE ...) BY KEYS DESCRIPTION (where its records come from) |
OUTVALUES= | variable and key value | NAME KEY VALUE ORIGIN PREDECESSOR DERIVATION |
OUTCODES= | variable and literal | NAME ORDER VALUE CLOSED FORMAT PAIRNAME PAIRVALUE |
OUTSTEPS= | input or output of a step | STEPNO STEP ACTION LINE ROLE (SET, MERGE, FROM, LEFT JOIN, OUTPUT, MACRO ...) MEMNAME VERSION WHERE RENAME KEEP DROP BY |
OUTRULES= | rule, record filter, variable use, macro variable set | CATEGORY TARGET KIND EXPR WORDS SOURCES CONDITIONS CONDITIONWORDS LINE |
OUTEDGES= | edge of the lineage graph | SOURCE_LIB/DS/VAR/VERSION TARGET_LIB/DS/VAR/VERSION STEPNO STEP LINE RELATION DETAIL VIA EXPR |
TRACE ... / OUT= | edge reached | START DIRECTION LEVEL, then the OUTEDGES= columns |
OUTSTEPS=, OUTRULES=, OUTEDGES= and JSON= cover everything recorded, whatever DATA= says. The printed tables are also ODS output objects: ods output Derivations=meta; gives the same data set as OUT=. The others are Datasets, Values, Codes, Steps, Rules, Edges and Trace.
What is recorded
- DATA steps:
- assignments,
IF/ELSE IF/ELSEandSELECT/WHENwith their conditions; - array loops, unrolled to one rule per member;
- sum statements and
RETAIN,CALL MISSING; SET/MERGE/UPDATEwithIN=,WHERE=,KEEP=,DROP=,RENAME=andBY(FIRST./LAST.);- subsetting
IF,DELETE,WHEREandOUTPUT; - user formats used with
PUT; - hash-object lookups (
DECLARE HASHwithFIND).
- assignments,
- PROC SQL:
- each column of
CREATE TABLE ... AS SELECT,CASEbranches, and joins withON,WHERE,GROUP BY,HAVING; - in-line views,
UNION/EXCEPT/INTERSECT, andCREATE VIEW; UPDATE,DELETEandINSERT;SELECT ... INTO :macro-variable.
- each column of
- Procedures:
- output data sets of SORT, MEANS/SUMMARY, TRANSPOSE (each transposed column with the
IDvalue that names it), FREQ, APPEND and DATASETSMODIFY/CHANGE; ODS OUTPUTtables andOUTPUT OUT=data sets of the analysis procedures. A statistic such as an LS-mean is derived from the variables the procedure analyses.
- output data sets of SORT, MEANS/SUMMARY, TRANSPOSE (each transposed column with the
- What procedures display or analyse: the variables PRINT, FREQ, REPORT, TABULATE, SGPLOT, MEANS, GLM, MIXED, LOGISTIC, PHREG, LIFETEST and the others name, each with its role (
TABLES,MODEL_RESPONSE,GROUP...). The JSON file also lists the ODS RTF, Word, HTML or PDF files each step wrote into. - Macro variables:
- those set from data (
INTO,CALL SYMPUT/SYMPUTX), and the steps that resolve them (aTITLEincluded); %LETvalues computed from them (%EVAL(&N1 + &N2)).
- those set from data (
The lineage graph
Behind the descriptions is a graph whose nodes are versions of variables (LIB.DS.VAR as step n wrote it), the records of each data set, macro variables and the procedure steps that use them. Each edge has a relation:
| Relation | Meaning | Examples |
|---|---|---|
COPY | The value as it is. | SET, RENAME=, X = Y, a transposed value |
DERIVE | Computed from it. | BMI = WEIGHT / HEIGHT**2 * 703, MEAN(BMI) |
CONDITION | It decides which rule gives the value. | IF AGE < 65 THEN ..., CASE WHEN, FIRST., IN= flags |
RECORDS | It decides which records a data set has. | WHERE, subsetting IF, join ON, GROUP BY, BY |
USE | A procedure shows or analyses it. | PRINT's VAR, FREQ's TABLES, REPORT's DEFINE, a macro variable in a TITLE |
Working variables that a step drops are passed through: the edge from WEIGHT to a variable computed through a temporary one names that temporary in VIA.
Example programs
Download an example, open it in StatDataViewer, and run it. Each one runs as is, using SASHELP.CLASS or data created in the program. Download all examples (.zip).
| Example | What it shows |
|---|---|
| class_bmi.sas | Example 1: the report of one data set, with derivations, a WHERE, labels and a code list. |
| class_trace.sas | Example 2: TRACE upstream and downstream through a DATA step, a PROC SQL summary and a PROC FREQ. |
| adam_metadata.sas | Example 3: SDTM to ADSL and ADVS, with a derived parameter. Shows OUT=, OUTVALUES=, OUTCODES= and JSON=. |
| tlf_impact.sas | Example 4: big N through INTO macro variables into percentages and a PROC REPORT, traced downstream. |
Tip — lineage builds up over your session
In StatDataViewer the recorded lineage lasts for the whole session: every program you submit while OPTIONS LINEAGE is on adds its steps. You can run a study's programs one after another (SDTM, then ADSL, then ADVS, then the tables) and trace across all of them. Start a fresh record with proc lineage clear; run;. The step numbers then start again at 1.
Note — messages you may see
WARNING: No lineage has been recorded. means no step ran with OPTIONS LINEAGE on: put it before the steps to describe. NOTE: SDTM.DM was not made by a step in the lineage model. means DATA= names a data set the program only read; it can still be traced downstream. ERROR: TRACE variable AGE must be written as libref.member.variable means a one-level name was used without a single DATA= data set.
Note — PROC LINEAGE is a StatDataViewer extension
SAS itself has no PROC LINEAGE or OPTIONS LINEAGE, so run lineage in StatDataViewer with the built-in engine. The recorded steps are the ones StatDataViewer's engine runs. For a program you normally run on your SAS server, run it once in StatDataViewer to get its lineage.