An earlier post demonstrated how the jupyter SAS kernel could be used to run SAS from within a Quarto document. This post demonstrates the saspy library and how SAS can be incorporated into Quarto, ultimately passing data to an interactive observable visualization.
Setup and Configure
saspy needs to be installed and configured. See the previous post for details on configuring sascfg_personal.py
and _authinfo files
.
Quarto qmd Document
The saspy library can be used to communicate between python and sas. It works within Quarto python
chunks without requiring the SAS kernel. Below is an example document which demonstrates how to call SAS code directly within a python
chunk, how to execute SAS commands from within a python
chunk and how to pass data from SAS to python. Once data have been passed from SAS to python we have the opportunity of using observable
to render interactive visualizations.
---
"Quarto Demo with SAS"
title: format: html
self-contained: true
---
in Quarto. In this document we demonstrate the following:
A simple demo of using SAS
- Running SAS code directly
- Importing a SAS dataset
- Executing SAS commands using saspy
- Converting SAS dataset to a Pandas DataFrame
- Interactive visualization using observable
# Setup
is required to run SAS commands from python/jupyter.
saspy
```{python}import saspy
import pandas as pd
= saspy.SASsession()
sas
```
# Running SAS code directly from the notebook
with two keys, _LOG_ and _LST_. The _LOG_ can simply be printed and the _LST_ rendered as HTML using `sas.HTML()`.
The `sas.submit()` method can be used to submit SAS code directly. The method returns a dictionary
```{python}#| echo: true
#| results: asis
#| warning: false
= sas.submit("""
ll libname work list;
proc sql;
select type, count(*) as 'number of models'n, avg(MPG_city) as 'Avg(MPG_City)'n
from sashelp.cars
group by type
order by 3 desc;
quit;
""")
```
### keys
list of dictionary keys returned by SAS
```{python}
ll.keys()
```
### LST
LST output
```{python}'LST'])
sas.HTML(ll[
```
Alternatively, the _LST_ can be rendered automatically using the `sas.submitLST()` method
```{python}#| echo: true
#| results: asis
#| warning: false
= sas.submitLST("""
ll libname work list;
proc sql;
select type, count(*) as 'number of models'n, avg(MPG_city) as 'Avg(MPG_City)'n
from sashelp.cars
group by type
order by 3 desc;
quit;
""")
```
# Working with SAS and python together
## Importing data from SAS
```{python}= sas.sasdata('cars', 'sashelp')
data_sas
```
## Running SAS PROC MEANS from Quarto
```{python}
data_sas.means()
```
## A simple bar chart (from SAS)
```{python}'EngineSize')
data_sas.bar(
```
## Converting the data to a Pandas DataFrame
```{python}= data_sas.to_df()
data_pd
data_pd.describe()
```
# Interactive visualization with observable
-> python -> observable
SAS is available in python we can use the `ojs_define` function to make it available to observable.
Now that our data
```{python}#| warning: false
# make data available to observable
= data_pd)
ojs_define(ojs_data
```
is included as folded code.
The observabale code to generate the plot below
```{ojs}//| code-fold: true
// create an interactive input, limiting MPG_City
= Inputs.range(
viewof MPG_City 10, 60],
[10, step: 1, label: "MPG City"}
{value:
)
// filter data based on the value based on the MPG_City input
= transpose(ojs_data).filter(function(car) {
filtered_data return MPG_City < car.MPG_City;
})
```
```{ojs}//| code-fold: true
// build a dotplot from the filtered data
= Plot.plot({
plt
marks: ["EngineSize", y: "Horsepower"})
Plot.dot(filtered_data, {x:
]
}) ```