I'm trying to do a bar plot with categories using gchart in SAS. I have in the horizontal axis dates, so I don't want that appear because looks chaotic. I'm using the following code
axis1 label=none value=none;
axis2 label=(angle=90 'Porcentaje');
legend1 label=('Categoría') frame;
proc gchart data=base_fechas;
vbar REPORTE_FCH/ discrete subgroup=TPO_SEX
group=REPORTE_FCH g100 nozero
type=percent
inside=percent width=20
gaxis=axis1 raxis=axis2
legend=legend1;
run;
quit;
but the values of the axis still apear. How can I delete de values of the horizontal axis?
You have vbar <date> / … group=<date> g100 … ;
The group=<date> axis rendering is controlled by the gaxis option. The vbar <date> are mid-points and their rendering are controlled by the maxis option.
You can hide the midpoints by specifying vbar option maxis=axis1
This example hides both the midpoints and the groups:
data have;
do date = today()-100 to today();
do index = 1 to 50 * ranuni(123);
sex = substr('MF',1+(rannor(123) > 0.75),1);
output;
end;
end;
format date yymmdd10.;
run;
axis1 label=none value=none;
axis2 label=(angle=90 '%');
proc gchart data=have;
vbar date
/ discrete
subgroup = sex
GROUP = date
G100
nozero
type=percent
inside=percent width=20
gaxis = axis1
raxis = axis2
maxis = axis1
;
where date > today()-20;
run;
Related
I have the following data
DATA HAVE;
input year dz $8. area;
cards;
2000 stroke 08
2000 stroke 06
2000 stroke 06
;
run;
After using proc freq
proc freq data=have;
table area*dz/ list nocum ;
run;
I get the below output
In this output
I want to delete the 'dz', what can I do to delete this column?
I want a row in the end that gives 'total', what can I do to get a 'total' row?
Thank you!
There must be a better way of doing this, but the following code creates the desired table:
data have;
input year dz $8. area;
cards;
2000 stroke 08
2000 stroke 06
2000 stroke 06
;
run;
ods output List=list;
proc freq data=have;
table area*dz / list;
run;
data stage1;
set list(keep= area frequency percent CumFrequency CumPercent) end=eof;
area_char = put(area,best.-l); /* Convert it to char to add the Total row */
if eof then do;
call symputx("cumFreq", cumfrequency);
call symputx("cumPerc", cumpercent);
end;
drop area;
run;
data want;
retain area frequency percent; /* Put the variables in the desired order */
set stage1(rename=(area_char=area) drop=cumfrequency cumpercent) end=eof;
output;
if eof then do; /* Manually create the Total row */
area = "Total";
Frequency = &cumfreq.;
Percent = &cumperc.;
output;
end;
run;
Output (want table):
You should subset your data with a where clause and use a title statement if a important partitioning variable is to be removed from output. If you didn't subset how would your audience know if a count contained say episodes of stroke and ministroke if ministroke was also in the data.
Compute the frequencies with freq and use a reporting procedure (print, report, tababulate) that summarizes to show a total line.
Example:
data have;
input year dz $ area;
cards;
2000 stroke 08
2000 stroke 06
2000 stroke 06
;
proc freq noprint data=have;
where dz = 'stroke';
table area / out=freqs;
run;
title 'Stroke dz';
title2 'print';
proc print data=freqs noobs label;
var area;
sum count percent;
run;
title2 'report';
proc report data=freqs;
columns area count percent;
define area / display;
define count / analysis;
rbreak after / summarize;
run;
title2 'tabulate';
proc tabulate data=freqs;
class area;
var count percent;
table area all, count percent;
run;
Thank you all for your valuable responses. The following code gives me the desired output in a concise way
proc freq data=HAVE;
tables area / list nocum out=a;
run;
proc sql;
create table b as
select * from a
union
select
'Total' as area,
sum(count) as count,
sum(percent) as percent
FROM a
;
quit;
proc print data=b; run;
I am attempting to create traffic lighting in a report using proc format. But even though the values can be greater than 1 or below 1 the colors are always the lowest color. In this case, they are all red. Why is SAS not seeing the values?
proc format;
value forecast
low - < 0.70 = 'red'
0.70 - <0.90 = 'yellow'
0.90 - high = 'green';
run;
%macro perform_target (cc, year, career_id, cc_name) ;
data Performance_&career_id._&cc._&year. ;
set post_target_comparisons1;
where institution = "&cc." and year = "&year." and career_id = "&career_id.";
run;
ods excel file = "Y:\General - CTE\2019 CTE Accountability\2020\Need Assessment Performance
Tables\Performance_&career_id._&cc._&year..xlsx" style = sasdocprinter;
ods excel options(autofilter="2-39" sheet_name = "Performance &year." embedded_titles = 'yes');
run;
title j= C "Actual to Target Comparisons";
title2 j = C "Academic Year - &year.";
run;
proc report data = Performance_&career_id._&cc._&year.;
column community_college cluster_label measure_label year total_students total_male percent_male
target forecast_male forecast_female forecast_AI forecast_AS forecast_AA forecast_HI forecast_PI
forecast_W forecast_MU forecast_disabled forecast_farms forecast_single forecast_displaced
forecast_ell forecast_nontrad;
define forecast_male/display 'Percent to Forecast Male' style(column) = [cellwidth=1in
tagattr="format:####.##\%" fontweight = bold foreground = forecast.];
run;
ods excel close;
%mend perform_target;
%perform_target (010042, 2016, 01);
This works so I expect your data is the issue.
proc format;
value forecast
low - < 0.70 = 'red'
0.70 - <0.90 = 'yellow'
0.90 - high = 'green';
run;
data have;
do x = 0 to 1 by .05;
output;
end;
run;
ods excel file='test.xlsx';
proc report data=have list;
columns x;
define x / display /*format=percent12.2*/ style(column)=[cellwidth=1in tagattr="format:####.##\%" fontweight = bold foreground = forecast.];
run;
ods excel close;
I want to create a bar chart on yearly death count (based on gender). I want to plot gender and year on x axis and count on Y axis. Can you kindly help how to modify the below code?
TITLE 'DEATH GRAPH BY GENDER';
PROC SGPLOT DATA = DREPORT;
VBAR deathcount / GROUP = gender GROUPDISPLAY = CLUSTER;
RUN;
I am not able to put deathyear in the Y axis. Kindly frame the code.
The VBAR variable is the mid-point values to show on the horizontal axis.
Are you sure that is what you want ?
Do you really want to know how many times a give death count occurred over all the years ?
You probably want deathcount as the response
Consider this example:
data have_raw;
do id = 1 to 1000;
gender = substr('MF',1 + 2 * ranuni(123),1);
year = 2019 - floor (30 * ranuni(123));
output;
end;
run;
proc sql;
create table have as
select year, gender, count(*) as deathcount
from have_raw
group by year, gender
;
proc sgplot data=have;
vbar gender
/ response=deathcount
group=year
groupdisplay=cluster
;
run;
I am trying to produce a graph with multiple groupings. The sample data code is:
proc sort data=sashelp.cars out=cars;
by DriveTrain;
where n(Cylinders);
run;
I used dattrmap to add distinct colors to the different groups as follow:
data MyAttrMap;
length MARKERCOLOR CONTRASTCOLOR color $25;
ID='myreg'; value='All' ; MARKERCOLOR='red'; color='red'; MARKERSYMBOL = 'circle'; output;
ID='myreg'; value='Front'; MARKERCOLOR='blue'; color='blue'; MARKERSYMBOL = 'circle'; output;
ID='myreg1'; value='USA'; CONTRASTCOLOR='yellow'; color='yellow'; output;
ID='myreg1'; value='Europe'; CONTRASTCOLOR='black'; color='black'; output;
ID='myreg1'; value='Asia'; CONTRASTCOLOR='green'; color='green'; > > output;
run;
proc sgplot data=work.cars
dattrmap=MyAttrMap;
hbarparm category=enginesize response=horsepower/group=DriveTrain barwidth=.5 attrid=myreg name='dt';
scatter X=MPG_City Y=enginesize /group=origin name='origin' attrid=myreg1;
keylegend 'dt' / title='Drive Train' location=outside position=bottom;
keylegend 'origin' / title='Origin' location=outside position=bottom;
where DriveTrain in ('All' 'Front');
run;
The Attrmap was created with the intention of having different colors for Origin and DriveTrain however, when the output is created the same colors applied to Origin are applied to DriveTrain.
I also tried using Proc template to change the style as follow:
/*Different colors from the ones used above*/
proc template;
define style MyStyle;
parent = Styles.Listing;
STYLE graphdata1 /
MARKERSYMBOL = 'circle'
LINESTYLE = 1
CONTRASTCOLOR = liypk
COLOR = red
;
STYLE graphdata2 /
MARKERSYMBOL = 'circle'
LINESTYLE = 1
CONTRASTCOLOR = stybr
COLOR = yellow
;
STYLE graphdata3 /
MARKERSYMBOL = 'circle'
LINESTYLE = 1
CONTRASTCOLOR = mog
COLOR = green
;
STYLE graphdata4 /
MARKERSYMBOL = 'circle'
LINESTYLE = 1
CONTRASTCOLOR = brown
COLOR = pink
;
STYLE graphdata5 /
MARKERSYMBOL = 'circle'
LINESTYLE = 1
CONTRASTCOLOR = black
COLOR = grey
;
end;
run;
But still the same results were obtained. Could anyone please tell me what I'm doing wrong or how to get this to work? I'm using SAS 9.3.
Another issue I'm encountering is the sorting. I want to sort the bars so that the same origins appear together and by the horsepower. I sorted using sortkey=national and used grouporder=data as recommended by SAS but this didn't change the ordering in the output. Any help is appreciated.
.
Thanks.
You might find SGPANEL a better option for visually presenting the distributions of different groups.
ods html style=normal;
ods graphics / height=900px;
proc sgpanel data=sashelp.cars;
panelby origin
/ columns=3
;
hbar enginesize
/ group=drivetrain
groupdisplay=cluster
;
where
DriveTrain in ('Front', 'All')
and not missing(cylinders)
;
run;
Check your attribute map data set. Because you haven't specified the lengths for the Value and ID column they're truncated and don't match your data so they don't get assigned correctly.
Simplifying your problem, I assigned all the elements for testing:
I also assumed this was mocked up because of the errors in the log.
proc sort data=sashelp.cars out=cars;
by DriveTrain;
where n(Cylinders);
run;
data MyAttrMap;
length ID $10. linecolor MARKERCOLOR CONTRASTCOLOR fillcolor color value $25;
ID='myreg1';
value='USA';
contrastcolor='cxaf8dc3';
LINECOLOR='cxaf8dc3';
MARKERCOLOR='cxaf8dc3';
fillcolor='cxaf8dc3';
output;
ID='myreg1';
value='Europe';
contrastcolor='cx7fbf7b';
LINECOLOR='cx7fbf7b';
MARKERCOLOR='cx7fbf7b';
fillcolor='cx7fbf7b';
output;
ID='myreg1';
value='Asia';
contrastcolor='cx91bfdb';
LINECOLOR='cxfc8d59';
MARKERCOLOR='cxfc8d59';
fillcolor='cxfc8d59';
output;
run;
ods graphics / attrpriority=none;
proc sgplot data=work.cars dattrmap=MyAttrMap;
scatter X=MPG_City Y=enginesize /group=origin name='origin' attrid=myreg1;
where DriveTrain in ('All' 'Front');
run;
I created the following graph using sgplot
proc sgplot data=Colordistricts;
hbar distrct/response=Percent
group= population;
run;
However, it seems that the individual population groups are arranged in alphabetical order in the graph (Asian followed by Black Color and White).
How do I create this same plot with the population groups in the descending order by percent?
In fact these are districts where the color population is highest. Basically I want to create a graph so that each bar begins with the color population
To force a specific group value to the first position you can map the desired group to a new value that will collate first. Sometimes this is easily done by placing a space character in front of an existing value.
If the group variable is a numeric ID custom formatted to display an associated group label you can create a new version of the custom format to include a 0 id that corresponds to the forced group. The forced group is mapped to the 0 id.
You would then sort the data in the particular way you need and use SGPLOT yaxis type=discrete discreteOrder=data; to force the hbar categories to appear in the particular order.
Here is some sample code to explore. The final SGPLOT uses the mapping technique to force a particular population segment to appear first.
ods html close;
%let path = %sysfunc(pathname(work));
ods html file="&path.\sgplot_hbar.html" gpath="&path.";
proc format;
value popId
0 = 'Color'
1 = 'Asian'
2 = 'Black'
3 = 'Color'
4 = 'White'
;
data have;
do _n_ = rank('A') to rank('P');
district = byte (_n_);
x = 0;
populationID = 2; percent = ceil(40*ranuni(123)); output;
x + percent;
populationID = 3; percent = ceil(40*ranuni(123)); output;
x + percent;
if (ranuni(123) < 0.10) then do;
populationID = 1; percent = ceil(10*ranuni(123)); output;
x + percent;
end;
percent = 100 - x;
populationID = 4;
output;
end;
keep district populationID percent;
label
percent = 'Percent of Total Frequency'
;
format
populationID popId.
;
run;
proc sgplot data=have;
hbar district
/ group = populationID
response = percent
;
title j=L 'default group order by populationID value';
title2 j=L 'districts (yaxis) also implicitly sorted by formatted value';
run;
proc sgplot data=have;
hbar district
/ group = populationID
response = percent
categoryOrder = respAsc
;
title j=L 'categoryOrder: ascending response';
title2 j=L 'districts (yaxis) also implicitly sorted by min(response)';
run;
proc sgplot data=have;
hbar district
/ group = populationID
response = percent
categoryOrder = respDesc
;
title j=L 'categoryOrder: descending response';
title2 j=L 'districts (yaxis) also implicitly sorted by descending max(response)';
run;
proc sql;
create table have2 as
select
case
when populationID = 3 then 0 else populationID
end as hbar_populationID format=popId.
, *
from have
order by
hbar_populationID, percent
;
quit;
proc sgplot data=have2;
yaxis type=discrete discreteOrder=data;
hbar district
/ group = hbar_populationID
response = percent
;
title j=L 'population seqment ordering is partially forced by tweaking populationID values';
title2 j=L 'districts in data order per yaxis statement';
run;
Forced groupOrder
SQL can sort the data in a particular order by using a case in the order by clause. You would then use groupOrder=data in SGPLOT.
proc sql;
create table have3 as
select *
from have
order by
district
, case
when populationID = 3 then 0
when populationID = 2 then 1
when populationID = 4 then 2
when populationID = 1 then 3
else 99
end
;
quit;
proc sgplot data=have3;
hbar district
/ group = populationID
groupOrder = data
response = percent
;
title j=L 'population seqment ordering is partially forced by tweaking populationID values';
title2 j=L 'districts in data order per yaxis statement';
run;
Forcing one segment to be first and then the other segments relying on response values
After mapping populationID 2 to 0 you could force the remaining population segments to be ordered similar to respAsc or respDesc. That process would require additional coding to determine new mappings for the other populationID values. This additional example shows how the global response sum is used to force a descending order on the remaining population segments within a district.
proc sql;
create table way as
select populationID, sum(percent) as allPct
from have
where populationID ne 3
group by populationID
order by allPct descending
;
data waySeq;
set way;
seq + 1;
run;
proc sql;
create table have3 as
select
have.*
, case
when have.populationID = 3 then 1000 else 1000+seq
end as hbar_populationID
from have
left join waySeq on have.populationID = waySeq.populationID
order by
hbar_populationID, percent
;
create table fmtdata as
select distinct
hbar_populationID as start
, put(populationID, popId.) as label
, 'mappedPopId' as fmtname
from have3;
quit;
proc format cntlin = fmtdata;
run;
%let syslast = have3;
proc sgplot data=have3;
yaxis type=discrete discreteOrder=data;
hbar district
/ group = hbar_populationID
response = percent
groupOrder = data
;
format hbar_populationID mappedPopId.;
title j=L 'population seqment ordering is partially forced by tweaking populationID values';
title2 j=L 'districts in data order per yaxis statement';
run;
title;