filename resp clear; filename resp 'rdu_weather_2019.json'; /* proc http url = 'https://data.townofcary.org/api/records/1.0/search/?dataset=rdu-weather-history&q=date+%3E+31-12-2018+and+date+%3C+1-1-2020&rows=-1&sort=date' method = "GET" out = resp; run; */ /* Assign a JSON library to the HTTP response */ libname rdu clear; libname rdu JSON fileref=resp noalldata; /* Derive the group variable 'month' */ data temp; set rdu.records_fields; date_num = input(date, YYMMDD12.); month = month(date_num); run; proc print data=temp (obs=5); var date month temperatureMin temperatureMax; run; proc sql noprint; select count(distinct month) into: nGroups TRIMMED from work.temp; create table work._temp1 as select distinct month from work.temp; create table work._temp2 as select *, monotonic() as group from work._temp1; quit; /* Method 1: compute kernel density estimates using proc kde in SAS 9.4 */ /* proc sort data=temp out=sorted; by month; run; proc kde data=sorted; univar temperatureMax / out=outkde (rename=(value=temperatureMax)) method=snr bwm=0.5 noprint plots=none; by month; run; */ /* Method 2: compute kernel density estimates using the kde Action in SAS Viya 3.5 */ /* connect to a CAS server prior to loading your data */ /*cas casauto;*/ /* load data in CAS */ libname mycas cas; data mycas.temp; set work.temp; run; /* CASL code to compute densities using kde action */ proc cas; session CASAUTO; dataPreprocess.kde result=s / table = {name="temp" , groupBy = {{name = "month"}} }, inputs = {"temperatureMax"}, casoutKDEDetails = { name = "_castemp", replace = TRUE }, requestPackages={ { bandwidthOpts={method ="SNR" multiplier = 0.5} } } ; quit; /* Copy CAS table */ data work._castemp; set mycas._castemp; run; /* drop table from CAS */ proc cas; session CASAUTO; table.dropTable status=t / name="_castemp" ; if (t.severity == 0) then print "table dropped successfully"; quit; proc sort data=_temp2; by month; run; proc sort data=work._castemp; by month; run; /* merge computed kde and recoded group variable */ data work.density; merge work._castemp work._temp2; by month; run; /* store the maximum density in a macro var */ proc sql noprint; select max(_density_) into: maxDensity from work.density; quit; %macro rescale; /* for each group, re-scale the computed values */ data work.rescale; set work.density; %do grp=1 %to &nGroups; if group = &grp then do; increment = %sysevalf(&maxDensity * %eval(&grp - 1)); increment = increment * 0.85 ; density = _density_ + increment; end; %end; run; %mend; %rescale; /* add variables for reference lines */ proc sql noprint; create table work._temp3 as select distinct increment as refVal from work.rescale; create table work._temp4 as select distinct month as refLabel from work.rescale; quit; /* create data for plotting purpose */ data work.plotData; merge work.rescale work._temp3 work._temp4; run; proc format; value mth 1 = 'January' 2 = 'February' 3 = 'March' 4 = 'April' 5 = 'May' 6 = 'June' 7 = 'July' 8 = 'August' 9 = 'September' 10 = 'October' 11 = 'November' 12 = 'December' ; run; quit; proc sql noprint; select avg(temperatureMax) into :avg from work.plotData; quit; ods listing gpath='.' image_dpi=150 ; ods graphics / width=500px height=600px imagename='figure2'; title "Distribution of Maximum Temperatures for Cary, North Carolina in 2019"; footnote j=l "Figure 2: Created using PROC SGPLOT"; proc sgplot data=work.plotData noautolegend nowall noborder; band x = temperatureMax lower = increment upper = Density / group = month fillattrs=(color=lightseagreen transparency=0.5); series x = temperatureMax y = Density / group = month lineattrs=(color=lightseagreen pattern=solid); refline refVal / label=refLabel labelloc=outside labelpos=min ; refline &avg / label="OverAll Average = &avg" axis=x labelloc=outside labelpos=max labelattrs=(color=blue) lineattrs=(color=blue); yaxis display=none offsetmax=0; xaxis label = 'Temperature (in Fahrenheit)' ; format refLabel mth.; run; title; footnote; /* ============================ MACRO PROGRAM TO PREPARE DATA FOR RIDGELINE PLOT ===============================*/ %macro prepareRidgeData( dslib=sashelp, dsnm=iris, analysisVar=sepalLength, groupVar=species, dsnout=outkde ); /* store total number of groups in a macro variable */ /* create a table with a re-coded group var */ proc sql noprint; select count(distinct &groupVar) into: nGroups TRIMMED from &dslib..&dsnm; create table work._temp1 as select distinct &groupVar from &dslib..&dsnm; create table work._temp2 as select *, monotonic() as group from work._temp1; quit; /* Load data into CAS */ libname mycas cas ; data mycas.&dsnm; set &dslib..&dsnm; run; /* Compute kernel density estimates using CAS action */ proc cas; session CASAUTO; table.columnInfo result=colInfo / table = {name="&dsnm"}; dataPreprocess.kde result=kdeResult status=s / table = {name="&dsnm" , groupBy = {{name = "&groupVar"}} }, inputs = {"&analysisVar"}, casoutKDEDetails = { name = "_castemp", replace = TRUE }, requestPackages={ { bandwidthOpts={method ="SNR" multiplier = 0.5} } } ; print s ; quit; /* merge computed kde and recoded group variable */ data work._castemp; set mycas._castemp; run; /* drop table from CAS */ proc cas; session CASAUTO; table.dropTable status=t / name="_castemp" ; if (t.severity == 0) then print "table dropped successfully"; quit; proc sort data=_temp2; by &groupVar; run; proc sort data=work._castemp; by &groupVar; run; data work.density; merge work._castemp work._temp2; by &groupVar; run; /* store the maximum density in a macro var */ proc sql noprint; select max(_density_) into: maxDensity from work.density; quit; /* for each group, re-scale the computed values */ data work.rescale; set work.density; %do grp=1 %to &nGroups; if group = &grp then do; increment = %sysevalf(&maxDensity * %eval(&grp - 1)); increment = increment * 0.85 ; density = _density_ + increment; end; %end; run; /* add variables for reference lines */ proc sql noprint; create table work._temp3 as select distinct increment as refVal from work.rescale; create table work._temp4 as select distinct &groupVar as refLabel from work.rescale; quit; data work.&dsnout; merge work.rescale work._temp3 work._temp4; run; %mend; /* invoke macro program to create output datasets for measures /* temperatureMax and temperatureMin */ %prepareRidgeData(dslib=work, dsnm=temp, analysisVar=temperatureMax, groupVar=month, dsnout=out1); %prepareRidgeData(dslib=work, dsnm=temp, analysisVar=temperatureMin, groupVar=month, dsnout=out2); /* merge both output datasets for plotting */ data plotData; merge out1 (rename=(_density_=_density_temp_max density=density_temp_max increment=inc_temp_max refLabel=refLabel_temp_max refVal=refVal_temp_max)) out2 (rename=(_density_=_density_temp_min density=density_temp_min increment=inc_temp_min refLabel=refLabel_temp_min refVal=refVal_temp_min) drop=_Dim_ month_f _NPerDimGridPoints_ _NPerDimGridPoints_ ); by group; run; proc sql noprint; select avg(temperatureMax) into :avgmax from work.out1; select avg(temperatureMin) into :avgmin from work.out2; quit; ods listing gpath='.' image_dpi=150 ; ods graphics / width=500px height=600px imagename='figure3'; title "Distribution of Max/Min Temperatures for Cary, North Carolina in 2019"; footnote j=l "Figure 3: Created using PROC SGPLOT"; proc sgplot data=work.plotData noautolegend noborder ; band x = temperatureMax lower = inc_temp_max upper = density_temp_max / group = month fillattrs=(color=lightseagreen transparency=0.5); band x = temperatureMin lower = inc_temp_min upper = density_temp_min / group = month fillattrs=(color=LIYG transparency=0.5) y2axis; scatter x = temperatureMax y = density_temp_max / markerattrs=(color=lightseagreen size=2px symbol=squarefilled) transparency=0.5 name='max' legendlabel="maxTemperature"; scatter x = temperatureMin y = density_temp_min / markerattrs=(color=LIYG size=2px symbol=squarefilled) transparency=0.5 y2axis name='min' legendlabel="minTemperature"; refline refVal_temp_min / label=refLabel_temp_min labelloc=outside labelpos=min axis=y2 lineattrs=(thickness=2px); yaxis display=none; y2axis display=none; xaxis label = 'Temperature (in Fahrenheit)' ; format refLabel_temp_min mth.; keylegend "min" "max" / AUTOITEMSIZE location=outside position=topright noborder; run; title; footnote; cas _all_ terminate;