Dear all,
I have a Donut Chart with a legend. The optical purpose it to display the slices in a given order (variable r) and ordered Color list (goptions Colors). The legend should Display the names (variable Status), not the numbers in a given order (variable r).
(Please don't ask the data - I get it like this from somebody else. I wrote it into a proc SQL so that you can test it.)
/* I get this data from somebody else */
/* For your testing I write it as SQL down */
proc sql noprint;
create table work.mydata
(
status char(50),
anz_massnahmen num,
reihenfolge num,
r char(2)
)
;
insert into work.mydata (status,anz_massnahmen,reihenfolge,r)
values("ist umgesetzt", 10, 1, "1")
values("wird umgesetzt", 10, 2, "2")
values("in Aufarbeitung", 20, 3, "3")
values("wird nicht umgesetzt", 20, 4, "4")
values("über anderen Kanal adressiert", 10, 5, "5")
;
quit;
/* Here my code starts */
/* Color list for the legend. The Colors should appear in this order */
goptions cback='cxF2F2F2' colors=('cx113388' 'cx426BB3' 'cx819CCC' 'cxC6CEE2' 'cxAAADC3');
/* Legend for the Donut */
/* The Legend values should appear in this order */
Legend1
ACROSS =1
NOFRAME
LABEL=NONE
POSITION = (MIDDLE RIGHT OUTSIDE)
value=("ist umgesetzt" "wird umgesetzt" "in Aufarbeitung" "wird nicht umgesetzt" "über anderen Kanal adressiert")
;
/* Donut code */
PROC GCHART DATA =mydata;
DONUT r
/
SUMVAR = anz_massnahmen
TYPE = SUM
LEGEND = LEGEND1
SLICE = NONE
PERCENT = NONE
VALUE = OUTSIDE
OTHER = 4
OTHERLABEL = "Sonstige"
COUTLINE = BLACK
NOHEADING
DONUTPCT=70
;
RUN;
quit;
This code runs ok. Everything is as my customer wishes.
My code has to run for whatever data arrives. It has to be able to deal with different data and nevertheless Display the Donut with the right legend, Color list and right data order.
The Problem Comes when I get different data. It may occur that I get data with anz_massnahmen = 0 for some rows. For example:
proc sql noprint;
create table work.mydata
(
status char(50),
anz_massnahmen num,
reihenfolge num,
r char(2)
)
;
insert into work.mydata (status,anz_massnahmen,reihenfolge,r)
values("ist umgesetzt", 10, 1, "1")
values("wird umgesetzt", 0, 2, "2")
values("in Aufarbeitung", 20, 3, "3")
values("wird nicht umgesetzt", 20, 4, "4")
values("über anderen Kanal adressiert", 10, 5, "5")
;
quit;
Please run this data with the aboce goptions, legend and proc gchart code.
What happens is that the slice for Status = "wird umgesetzt" is not displayed (as anz_massnahmen = 0 for this row) and thus the legend is no longer correct (the legend Displays "wird umgesetzt" because I use value= in the legend Statement). And the Color order is the same but now the second Color is used for the third data row. But the customer wants the second Color to always be used with r=2. So in this case the second Color should be left out from the Donut graph.
To solve the Problem with the legend value= I used this code:
proc sql noprint;
create table work.mydata
(
status char(50),
anz_massnahmen num,
reihenfolge num,
r char(2)
)
;
insert into work.mydata (status,anz_massnahmen,reihenfolge,r)
values("ist umgesetzt", 10, 1, "1")
values("wird umgesetzt", 0, 2, "2")
values("in Aufarbeitung", 20, 3, "3")
values("wird nicht umgesetzt", 20, 4, "4")
values("über anderen Kanal adressiert", 10, 5, "5")
;
quit;
proc format;
value $fstatus
1 = "ist umgesetzt"
2 = "wird umgesetzt"
3 = "in Aufarbeitung"
4 = "wird nicht umgesetzt"
5 = "über anderen Kanal adressiert"
6 = "bereits bekannt"
;
run;
goptions cback='cxF2F2F2' colors=('cx113388' 'cx426BB3' 'cx819CCC' 'cxC6CEE2' 'cxAAADC3');
Legend1
ACROSS =1
NOFRAME
LABEL=NONE
POSITION = (MIDDLE RIGHT OUTSIDE)
/* value=("ist umgesetzt" "wird umgesetzt" "in Aufarbeitung" "wird nicht umgesetzt" "über anderen Kanal adressiert")*/
;
PROC GCHART DATA =mydata;
format r $fstatus.;
DONUT r
/
SUMVAR = anz_massnahmen
TYPE = SUM
LEGEND = LEGEND1
SLICE = NONE
PERCENT = NONE
VALUE = OUTSIDE
OTHER = 4
OTHERLABEL = "Sonstige"
COUTLINE = BLACK
NOHEADING
DONUTPCT=70
;
RUN;
quit;
Due to the Format the legend values now correspond to the slices. The graph in itself is correct again.
But my customer now says the second Color is now assigned to the wrong value. (The second Color must be assigned to the data row with r=2 and not to the row with r=3).
I understand what the customer wants. Always the same Color for the same Status. So that the user knows from the Color what it is.
Can you help me with my code? How am I able to do this without knowing what data arrives?
(I tried discrete but it doesn't work.)
Thanx for everybody reading the whole text 🙂
Eva
I don't use pies much, so this is a bit of a gray area for me, but I think this might achieve what you're wanting ...
I think you will want to specify your colors in pattern statements (rather than a goptions color list), and then specify all the possible slices via midpoints=. I think this way, all the slices in the midpoints list will be assigned a color, even if there isn't data for that slice being plotted.
Here's a simplified example demonstrating this technique:
pattern1 v=s c=blue;
pattern2 v=s c=green;
pattern3 v=s c=red;
/* a pie with no slices missing (you don't have to use midpoints) */
data foo;
length cat $20;
cat='blue slice'; value=1; output;
cat='green slice'; value=2; output;
cat='red slice'; value=3; output;
run;
proc gchart data=foo;
donut cat / type=sum sumvar=value legend;
run;
/* a pie with no cat='green slice' ... but using midpoints= you can still get the green pattern statement to be 'consumed' and the red pattern assigned to 'red slice' ... even though there is no 'green slice' in the data nor the pie */
data foo2;
length cat $20;
cat='blue slice'; value=1; output;
cat='red slice'; value=3; output;
run;
proc gchart data=foo2;
donut cat / type=sum sumvar=value legend
midpoints='blue slice' 'green slice' 'red slice';
run;
It has been awhile since I have done any donut charts so I am not sure this will always work but color assignments tend to be in the order data values are encountered so sorting may help. If you have character values you may have issues with default sort order with numerals so us Proc Sort with sortseq=linguistic(numeric_collation=on).
If any of the values are missing for a specific chart you may to insure that the group exists even if the summary variable has missing values.
I don't use pies much, so this is a bit of a gray area for me, but I think this might achieve what you're wanting ...
I think you will want to specify your colors in pattern statements (rather than a goptions color list), and then specify all the possible slices via midpoints=. I think this way, all the slices in the midpoints list will be assigned a color, even if there isn't data for that slice being plotted.
Here's a simplified example demonstrating this technique:
pattern1 v=s c=blue;
pattern2 v=s c=green;
pattern3 v=s c=red;
/* a pie with no slices missing (you don't have to use midpoints) */
data foo;
length cat $20;
cat='blue slice'; value=1; output;
cat='green slice'; value=2; output;
cat='red slice'; value=3; output;
run;
proc gchart data=foo;
donut cat / type=sum sumvar=value legend;
run;
/* a pie with no cat='green slice' ... but using midpoints= you can still get the green pattern statement to be 'consumed' and the red pattern assigned to 'red slice' ... even though there is no 'green slice' in the data nor the pie */
data foo2;
length cat $20;
cat='blue slice'; value=1; output;
cat='red slice'; value=3; output;
run;
proc gchart data=foo2;
donut cat / type=sum sumvar=value legend
midpoints='blue slice' 'green slice' 'red slice';
run;
Dear Robert,
thanx a lot. The midpoints Option did it. I didn't even have to use pattern instead of goptions Color. But additionally, I found out, the missing Option has to be set as well.
So this is what works: (all the code from the question, but the proc gchart as I write it here in this answer.)
PROC GCHART DATA =mydata;
DONUT r
/
SUMVAR = anz_massnahmen
TYPE = SUM
missing
midpoints="ist umgesetzt" "wird umgesetzt" "in Aufarbeitung" "wird nicht umgesetzt" "über anderen Kanal adressiert"
LEGEND = LEGEND1
SLICE = NONE
PERCENT = NONE
VALUE = OUTSIDE
OTHER = 4
OTHERLABEL = "Sonstige"
COUTLINE = BLACK
NOHEADING
DONUTPCT=70
;
RUN;
quit;
Best wishes
Eva
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.