Annotate Syntax PROC SGRENDER SAS - graph

I have a dataset I am working with that is very similar to the one created below. I want to graph the yearly trend in score by state, on the same graph. Additionally, I want to shade a portion of the graph where something happened (in this case a drop in score). Let's say I expected this event to be between 2011 and 2013. I want to shade a light gray rectangle over those years. I think my code is close, but cannot quite get the syntax correct.
Any help accomplishing this would be greatly appreciated. Also, any recommendations on cleaning up the proc template statements (are both needed? or can I combine into one?). Thanks.
Edit: the main issue, I think, is the syntax of the annorec data step.
data statescores;
input state $ year score;
cards;
NC 2010 75
NC 2011 77
NC 2012 72
NC 2013 85
NC 2014 87
SC 2010 72
SC 2011 73
SC 2012 60
SC 2013 79
SC 2014 76
VA 2010 80
VA 2011 80
VA 2012 79
VA 2013 81
VA 2014 83
;
run;
data drop;
input startdate enddate;
datalines;
2011 2013
;
data annorec;
/* length function style color $8; */
retain xsys '2' ysys '1' when 'b';
set drop;
function='rectangle';
height=.4;
width=2;
x=startdate;
y=60;
display="all";
FILLCOLOR='LTGRAY';
output;
/* function='bar'; */
/* x=enddate; */
/* y=90; */
/* color='ltgray'; */
/* style='solid'; */
/* output; */
run;
proc template;
define style styles.stocks;
parent=styles.listing;
style GraphData1 from GraphData1 /
ContrastColor=blue
Color=red
MarkerSymbol="CircleFilled"
Linestyle=1;
style GraphData2 from GraphData2 /
ContrastColor=brown
Color=blue
MarkerSymbol="none"
Linestyle=2;
style GraphData3 from GraphData3 /
ContrastColor=orange
Color=orange
MarkerSymbol="none"
Linestyle=2;
end;
run;
proc template;
define statgraph trend;
begingraph;
entrytitle "Scores for NC, SC, and VA";
discreteattrmap name="stockname" / ignorecase=true;
value 'NC' /
markerattrs=GraphData1(color=red symbol=circlefilled)
lineattrs=GraphData1(color=red pattern=solid);
value 'SC' /
markerattrs=GraphData2(color=orange)
lineattrs=GraphData2(color=green pattern=dot);
value 'VA' /
markerattrs=GraphData3(color=blue)
lineattrs=GraphData3(color=blue pattern=dot);
enddiscreteattrmap;
discreteattrvar attrvar=stockmarkers var=stock
attrmap="stockname";
layout overlay;
seriesplot x=year y=score /
group=state
display=(markers)
name="scores";
discretelegend "scores" / title="State Scores";
endlayout;
endgraph;
end;
run;
/* Plot the score trends */
ods pdf file="/sasdata/username/testgraph.pdf";
ods pdf style=styles.stocks;
proc sgrender data=statescores template=trend sganno=annorec;
run;
quit;
ods pdf close;

I would try to avoid using a discrete attribute map in GTL if you can avoid it. If you have only a few states, you really don't need it; even in your code above it does little other than to override some things you set in the earlier template step. Attribute maps are nice for SGPLOT, but are a pain in GTL in my experience.
In this case, you should try to use the BAND plot to make your gray band. Play with it some, but this should basically give you what you want:
proc sgplot data=statescores;
series x=year y=score/ group=state;
band y=score upper=2013 lower=2011 /transparency=0.8 ;
run;
That makes a pretty nice looking plot with four lines of code, plus if you want to add the colors you can fairly easily (either in an attribute map dataset, or in template code). In general, annotate datasets are often unnecessary in the SGPlot/GTL world, as you can layer plots easily and a lot of annotation can be done via layered plots instead.
If you want more detailed code review, I suggest posting in communities.sas.com, where some of the graph developers who work at SAS will often give suggestions on improvements to code.

Related

Impossible to print a graph in scilab if I try it through a callback of a function because syslin doesn't consider both arguments to be equal

how are you, I'm making a GUI in scilab based on a tutorial of Openeering people, in the GUI that I'm making I need to plot the response of a system on the right side of the figure window. It prints an initial graph of the system and I've a button to print the new graph with the parameters set in some text boxes that the GUI has, so:
the code where I initially store the data written in the text boxes is
//Lista ordenada de valores por defecto
values1=[0.00074,0.3,8.7,0.48,3.9,0.0035];
//Posicionamiento
l1=30;l2=100;l3=110;
for k=1:size(labels1,2)
uicontrol("parent",sistem_graf,"style","text","string",labels1(k),"position",[l1,guih1-
k*20+guih1o,l2,20],"horizontalalignment","left","fontsize",14,"background",[1 1 1]);
guientry(k)=uicontrol("parent",sistem_graf,"style","edit","string",string(values1(k)),
"position",
[l3,guih1k*20+guih1o,180,20],"horizontalalignment","left","fontsize",14,"background",
[.9 .9 .9],"tag",labels1(k));
end
guientry(k) is the control that names the text boxes.
The button is generated with the following code
//Adicionando un botón
huibutton=uicontrol(sistem_graf,"style","pushbutton",...
"position",[110 100 100 20],"String","Graficar",...
"BackgroundColor",[.9 .9 .9], "fontsize",14,...
"Callback","Calcula_Sistema");
and the function that is the callback of the button which is called "Calcula_Sistema" is
function Calcula_Sistema()
//Lee los parámetros del sistema
parametros=[];
la=findobj("tag,""La [H]"); parametros.la=la;
ra=findobj("tag","Ra [Ohm]"); parametros.ra=ra;
in=findobj("tag","In [A]"); parametros.in=in;
par=findobj("tag","Par [N*m]"); parametros.par=par;
ke=findobj("tag","Ke [V/krpm]"); parametros.ke=ke;
j=findobj("tag","j [N/m^2]"); parametros.j=j;
//Lee los tiempos del sistema
/* Tsim=[];
Tini=findobj("tag","Tinicio [s]"); Tsim.Tini=evstr(Tini);
Tfin=findobj("tag","Tfin [s]"); Tsim.Tini=evstr(Tfin);
Tpaso=findobj("tag", "Tpaso [s]"); Tsim.Tpaso=evstr(Tpaso);
*/
Sis_Motor(parametros.la,parametros.ra,parametros.in,
parametros.par,parametros.ke,parametros.j);
endfunction
when I press the button to generate the new graph the it gives me the error
at line 8 of function Sis_Motor ( F:\Users\valery\Documents\MEGAsync\UCV\Postgrado en Controles Industriales\Trabajo de Grado\Proyecto\Cálculos\Aplicación Scilab\Ventana.sce line 96 )
at line 18 of function Calcula_Sistema ( F:\Users\valery\Documents\MEGAsync\UCV\Postgrado en Controles Industriales\Trabajo de Grado\Proyecto\Cálculos\Aplicación Scilab\Ventana.sce line 142 )
syslin: Input arguments #2 y #3 incompatibles: Are expected of the same size.
The line 8 of the Sis_Motor function is the line 8 of the following code which is the Sis_Motor code
function [Wn,Zita,ftr,fta]=Sis_Motor(in,par,la,ra,ke,j)
kt=par/in;
n=kt/(j*la);
b=j/10;
d=[((b*ra+ke*kt)/(j*la)) ((b*la+j*ra)/(j*la)) 1];
dpoly=poly(d,'s','c');
t=[0:0.001:0.2];
fta=syslin('c',n,dpoly);
ftr=fta/(1+fta);
[Wn,Zita]=damp(ftr);
graf=csim('step',t,ftr);
delete(gca());
plot2d(t,graf);
legend('Respuesta al escalón');
//Línea vertical.
set(gca(),"auto_clear","off");
graf_eje=gca();
graf_eje.axes_bounds=[1/3,0,2/3,1];
endfunction
I also tried changing the second line of Sis_Motor where is the following code
n=kt/(j*la);
for the line
n=[kt/(j*la) 0 0];
but that didn't worked and the same errors keeps appearing.
I suppose that the error comes from the processing of the inputs of the text boxes but I don't know how to solve it
Can anyone help me with that?
Update 1:
findobj wasn't find the tags exactly as #Stephane Mottelet said, now is solved.
findobj yields a handle to the uicontrol. To recover the numeric value of edit boxes you have to write (here e.g. for ra)
ra=findobj("tag","Ra [Ohm]"); parametros.ra=evstr(ra.string);
If it still fails maybe the object is not found and findobj yields an empty matrix. Just insert disp(ra) after the findobj call to be sure that the tag is (or is not) found.

Scilab plot with many lines: automatic cycling trough 'LineSpec' styles

I am plotting around 10 Lines in the same plot and use the built-in option of plot to cycle through colors. Sadly, this option only has 7 colors and then starts with the first color again. Is there an option like in Matlab to get a different line type, when the colors cycled through once?
I know I can change the color and line style manually for every line, but I would prefer an automatic solution.
I do not know a built-in way to do this, but reading the Linespec man page, you could create a function to cycle trough all specifiers.
The simplest of them being :
function Linespec=CycleSpec(n)
// n : from 0 to N
Linestyle =['-';'--';':';'-.']
Linecolor = ['r';'g';'b';'c';'m';'y';'k';'w']
Linemarker =['';'+';'o';'*';'.';'x';'s';'d';'^';'v';'>';'<';'p']
i = modulo(n,size(Linecolor,'*'))+1
j = modulo(floor(n/size(Linecolor,'*')),size(Linestyle,'*'))+1
k = modulo(floor(n/size(Linecolor,'*')/size(Linestyle,'*')),size(Linemarker,'*'))+1
Linespec = Linestyle(j)+Linecolor(i)+Linemarker(k)
endfunction
Which could be use as
figure(1)
for n=0:40
plot(x,x+n,CycleSpec(n))
end
And if you really want something simple, we can add a global variable storing the counter so you only need to call the function, no need for parameter
function Linespec=CycleSpec()
// n : from 0 to N
global CycleSpecCounter
if CycleSpecCounter==[] then
CycleSpecCounter = 0
end
n=CycleSpecCounter
[...] same code as before [...]
CycleSpecCounter=CycleSpecCounter+1
endfunction
and you'd only need to type
plot(x,x+n,CycleSpec())

sunburst.R total frequency count is incorrect

I am plotting a sunburst donut and I cannot figure out why the total is incorrect.
library(sunburstR)
reports <- data.frame(
sequence = c("SVP-VP-Dir-end","SVP-VP-Dir-end","SVP-VP-Dir-end","SVP-VP-Dir-end","SVP-No VP-Dir-end","SVP-No VP-Dir-end","SVP-No VP-Dir-end"),
freq = as.numeric(c("167","60","51","32","5","1","1")))
sunburst(reports, count = TRUE)
It is supposed to be 100% 317 of 317 . Anyone know how to fix this? There is not much documentation on this great package.
Also, I would like it to have a default value in the center of donut.
If there is another way to create an interactive donut using R, please let me know.
Thanks you in advance.
It looks like the default function generating the message in the center of the donut rounds the total value to the nearest ten.
But you can customize this function using the explanation argument of sunburst. Oddly, the customized function (in javascript) must be provided as a string.
Try the following function:
custom.message = "function (d) {
root = d;
while (root.parent) {
root = root.parent
}
p = (100*d.value/root.value).toPrecision(3);
msg = p+' %<br/>'+d.value+' of '+root.value;
return msg;
}"
Now:
sunburst(reports, explanation = custom.message )
will generate the donut displaying exact total values. The count argument is no longer needed, as it is used by the default explanation function.
The value returned by custom.message is html code. As you can see, I've just inserted a line break (<br/>). You can modify the msg return value to further customize the look and feel.

Extracting value from XMLType Column

I was learning XMLType applications when I came accross the below problem. It's returning NULL insteade of the CD Title. I am not sure why it's behaving in this way.
DROP TABLE Xml_tab;
/
CREATE TABLE Xml_tab ( xmlval xmltype);
/
INSERT INTO Xml_tab
VALUES(XMLTYPE.CREATEXML(
'<CATALOG><CD><TITLE>Empire Burlesque</TITLE><ARTIST>Bob Dylan</ARTIST><COUNTRY>USA</COUNTRY><COMPANY>Columbia</COMPANY><PRICE>10.90</PRICE><YEAR>1985</YEAR></CD><CD><TITLE>Hide your heart</TITLE><ARTIST>Bonnie Tyler</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>CBS Records</COMPANY><PRICE>9.90</PRICE><YEAR>1988</YEAR></CD><CD><TITLE>Greatest Hits</TITLE><ARTIST>Dolly Parton</ARTIST><COUNTRY>USA</COUNTRY><COMPANY>RCA</COMPANY><PRICE>9.90</PRICE><YEAR>1982</YEAR></CD><CD><TITLE>Still got the blues</TITLE><ARTIST>Gary Moore</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>Virgin records</COMPANY><PRICE>10.20</PRICE><YEAR>1990</YEAR></CD><CD><TITLE>Eros</TITLE><ARTIST>Eros Ramazzotti</ARTIST><COUNTRY>EU</COUNTRY><COMPANY>BMG</COMPANY><PRICE>9.90</PRICE><YEAR>1997</YEAR></CD><CD><TITLE>One night only</TITLE><ARTIST>Bee Gees</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>Polydor</COMPANY><PRICE>10.90</PRICE><YEAR>1998</YEAR></CD><CD><TITLE>Sylvias Mother</TITLE><ARTIST>Dr.Hook</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>CBS</COMPANY><PRICE>8.10</PRICE><YEAR>1973</YEAR></CD><CD><TITLE>Maggie May</TITLE><ARTIST>Rod Stewart</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>Pickwick</COMPANY><PRICE>8.50</PRICE><YEAR>1990</YEAR></CD><CD><TITLE>Romanza</TITLE><ARTIST>Andrea Bocelli</ARTIST><COUNTRY>EU</COUNTRY><COMPANY>Polydor</COMPANY><PRICE>10.80</PRICE><YEAR>1996</YEAR></CD><CD><TITLE>When a man loves a woman</TITLE><ARTIST>Percy Sledge</ARTIST><COUNTRY>USA</COUNTRY><COMPANY>Atlantic</COMPANY><PRICE>8.70</PRICE><YEAR>1987</YEAR></CD><CD><TITLE>Black angel</TITLE><ARTIST>Savage Rose</ARTIST><COUNTRY>EU</COUNTRY><COMPANY>Mega</COMPANY><PRICE>10.90</PRICE><YEAR>1995</YEAR></CD><CD><TITLE>1999 Grammy Nominees</TITLE><ARTIST>Many</ARTIST><COUNTRY>USA</COUNTRY><COMPANY>Grammy</COMPANY><PRICE>10.20</PRICE><YEAR>1999</YEAR></CD><CD><TITLE>For the good times</TITLE><ARTIST>Kenny Rogers</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>Mucik Master</COMPANY><PRICE>8.70</PRICE><YEAR>1995</YEAR></CD><CD><TITLE>Big Willie style</TITLE><ARTIST>Will Smith</ARTIST><COUNTRY>USA</COUNTRY><COMPANY>Columbia</COMPANY><PRICE>9.90</PRICE><YEAR>1997</YEAR></CD><CD><TITLE>Tupelo Honey</TITLE><ARTIST>Van Morrison</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>Polydor</COMPANY><PRICE>8.20</PRICE><YEAR>1971</YEAR></CD><CD><TITLE>Soulsville</TITLE><ARTIST>Jorn Hoel</ARTIST><COUNTRY>Norway</COUNTRY><COMPANY>WEA</COMPANY><PRICE>7.90</PRICE><YEAR>1996</YEAR></CD><CD><TITLE>The very best of</TITLE><ARTIST>Cat Stevens</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>Island</COMPANY><PRICE>8.90</PRICE><YEAR>1990</YEAR></CD><CD><TITLE>Stop</TITLE><ARTIST>Sam Brown</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>A and M</COMPANY><PRICE>8.90</PRICE><YEAR>1988</YEAR></CD><CD><TITLE>Bridge of Spies</TITLE><ARTIST>T''Pau</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>Siren</COMPANY><PRICE>7.90</PRICE><YEAR>1987</YEAR></CD><CD><TITLE>Private Dancer</TITLE><ARTIST>Tina Turner</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>Capitol</COMPANY><PRICE>8.90</PRICE><YEAR>1983</YEAR></CD><CD><TITLE>Midt om natten</TITLE><ARTIST>Kim Larsen</ARTIST><COUNTRY>EU</COUNTRY><COMPANY>Medley</COMPANY><PRICE>7.80</PRICE><YEAR>1983</YEAR></CD><CD><TITLE>Pavarotti Gala Concert</TITLE><ARTIST>Luciano Pavarotti</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>DECCA</COMPANY><PRICE>9.90</PRICE><YEAR>1991</YEAR></CD><CD><TITLE>The dock of the bay</TITLE><ARTIST>Otis Redding</ARTIST><COUNTRY>USA</COUNTRY><COMPANY>Atlantic</COMPANY><PRICE>7.90</PRICE><YEAR>1987</YEAR></CD><CD><TITLE>Picture book</TITLE><ARTIST>Simply Red</ARTIST><COUNTRY>EU</COUNTRY><COMPANY>Elektra</COMPANY><PRICE>7.20</PRICE><YEAR>1985</YEAR></CD><CD><TITLE>Red</TITLE><ARTIST>The Communards</ARTIST><COUNTRY>UK</COUNTRY><COMPANY>London</COMPANY><PRICE>7.80</PRICE><YEAR>1987</YEAR></CD><CD><TITLE>Unchain my heart</TITLE><ARTIST>Joe Cocker</ARTIST><COUNTRY>USA</COUNTRY><COMPANY>EMI</COMPANY><PRICE>8.20</PRICE><YEAR>1987</YEAR></CD></CATALOG>'));
/
COMMIT;
SELECT P.xmlval.extract('//CATALOG/CD/TITLE/text()').GETSTRINGVAL AS CD
FROM Xml_tab P;
Any explanation is very welcome.
It's a little bit confusing but you can get cd titles like this:
SELECT extract(value(b),'//TITLE/text()').getstringval() AS CD
FROM xml_tab x,
TABLE(XMLSEQUENCE(extract(xmlval,'//CATALOG/CD'))) b
You sort of convert the xml into a table first and then get the values with the EXTRACT function.

How to format timevalue to HH:MM:SS in datalabel

So i have a bar graph in crystal reports. On this graph i have a data label attached to each of the graphs that displays the value of the graph in seconds, which appears like so:
What i would like to do is format this data-label into a time formatting. So for each bar in the graph it would have the data-label appear in the following format:
HH:MM:SS.
i am able to get the time formatting to appear using the following formula:
local NumberVar Sec;
local NumberVar ss;
local NumberVar mm;
local NumberVar hh;
local StringVar SSS;
local StringVar MMM;
Sec := Sum ({GetAlarmSummaryDataSet2Response/GetAlarmSummaryDataSet2Result/Items/AlarmSummaryItem2.StopTime}, {GetAlarmSummaryDataSet2Response/GetAlarmSummaryDataSet2Result/Items/AlarmSummaryItem2.Section}) ;
hh := Int (Sec/3600);
mm :=Int ((Sec/60)- (60* Int(Sec/3600 )));
If mm<10 then MMM := "0" & ToText (mm,0);
If mm>9 Then MMM := ToText(mm,0) ;
ss :=Sec-(3600 * hh ) - (60 * mm ) ;
If ss<10 then SSS := "0" & ToText (ss,0);
If ss>9 Then SSS := ToText(ss,0) ;
ToText ( hh,0) & ":" & MMM & ":" & SSS
But what i am unsure of is how to implement this formula onto a data label.
Any help or suggestions are greatly appreciated.
Thank you
You can choose to display the group name, and you can display and format the summarized value calculated by the chart, but you can't provide a custom formula. It just isn't possible using the chart library in CR XI.
My eventual workaround for this problem:
Modify the value formula to eliminate the aggregate function. (This is necessary because Crystal won't allow an aggregate function in a group name field -- see #2.)
For the group name, specify a formula with the text you want to display in the riser. Include both the label and the formatted value, separated by Chr(13) & Chr(10) to place them on separate lines.
Configure the riser to display the label, not the value.
To apply this to your problem you'd need to make these changes:
Eliminate the aggregate function. Of course I don't know if this will be possible using your setup. Perhaps if you're using a DBMS you could use a SQL command or a stored procedure to calculate the sum before the data reaches Crystal.
Print the label and value together, either on the riser or the X-axis.
If that's not good enough for your application, you might consider CRChart, a commercial replacement which tries to address the sometimes-crippling limitations of Crystal's chart library. (I thought it was too pricey.) I think the #APPEND_DATATEXT macro would let you place a custom value on a riser, but you'd still need to move the summary to the server.

Resources