Note the x-axis is month and day (no year) while the y-axis is year. The graph would be simple to replicate using Proc Sgscatter, but how do I get month and day without the year? I could extract the month and day from each date, then construct a "dummy date" where they retain the original month and day but all with the same year and only display the month and day. Is there a better way?
Here's an alternate way, if you want to get the *exact* same plot. I use a custom Gplot, with a bit of date manipulation and a bit of annotate. Below is the SAS/Graph output, and the code I used:
%let name=roe_menhaden_plot;
filename odsout '.';
/*
A scatter plot of dates when roe menhaden were landed at
Beaufort, North Carolina, 1988-1999. Using estimated data
from Figure 2 in the following paper:
http://spo.nwr.noaa.gov/mfr621/mfr6211.pdf
You can't really get this graph by default, and you have to
use a few little "tricks" ... look for 'Trick' in the comments...
*/
data fish_data;
informat catch_date date9.;
format catch_date date9.;
input catch_date;
datalines;
25oct1988
04nov1988
09nov1988
12nov1988
15nov1988
22nov1988
25nov1988
27nov1988
03dec1988
08dec1988
10dec1988
14dec1988
27dec1988
30dec1988
03jan1989
09jan1989
11jan1989
12oct1989
14oct1989
17oct1989
09nov1989
13nov1989
14nov1989
22nov1989
30nov1989
03jan1990
03nov1990
07nov1990
14nov1990
21nov1990
23nov1990
26nov1990
27nov1990
28nov1990
03dec1990
07dec1990
10dec1990
14dec1990
20dec1990
27dec1990
03jan1991
04jan1991
08jan1991
11jan1991
19jan1991
05nov1991
06nov1991
07nov1991
08nov1991
18nov1991
19nov1991
31dec1991
22jan1992
30oct1992
08nov1992
10nov1992
13nov1992
17nov1992
19nov1992
24nov1992
28nov1992
03dec1992
04dec1992
08dec1992
09dec1992
03nov1993
12nov1993
15nov1993
16nov1993
17nov1993
22nov1993
29nov1993
30nov1993
01dec1993
02dec1993
03dec1993
04dec1993
06dec1993
08dec1993
14dec1993
08nov1994
14nov1994
15nov1994
24nov1994
25nov1994
26nov1994
27nov1994
06dec1994
16nov1995
17nov1995
18nov1995
20nov1995
22nov1995
24nov1995
27nov1995
04dec1995
06dec1995
13dec1995
16dec1995
10nov1996
11nov1996
12nov1996
18nov1996
21nov1996
25nov1996
29nov1996
30nov1996
13dec1996
16dec1996
17dec1996
20jan1997
16nov1997
17nov1997
20nov1997
26nov1997
27nov1997
28nov1997
29nov1997
07dec1997
10dec1997
11dec1997
18dec1997
19dec1997
02nov1998
09nov1998
13nov1998
15nov1998
16nov1998
22nov1998
27nov1998
28nov1998
30nov1998
01dec1998
02dec1998
06dec1998
30nov1999
05dec1999
06dec1999
07dec1999
19dec1999
28dec1999
29dec1999
30dec1999
31dec1999
;
run;
data fish_data; set fish_data;
day=.; day=trim(left(put(catch_date,day.)));
month_name=trim(left(put(catch_date,monname20.)));
year=.; year=trim(left(put(catch_date,year4.)));
if month_name='January' then fishing_year=year-1;
else fishing_year=year;
/*
Trick #1 ... I'm converting the catch_date to a 1988 date,
so they can all be plotted along the same x-axis.
*/
plot_date=catch_date-((fishing_year-1988)*365.25);
run;
/*
Trick #2 - I annotate the tickmarks, and dates & months,
along the x-axis, so I can get them exactly the way I want.
*/
data anno_days;
informat catch_date date9.;
format catch_date date9.;
input catch_date;
datalines;
05oct1988
10oct1988
15oct1988
20oct1988
25oct1988
05nov1988
10nov1988
15nov1988
20nov1988
25nov1988
05dec1988
10dec1988
15dec1988
20dec1988
25dec1988
05jan1989
10jan1989
15jan1989
20jan1989
25jan1989
;
run;
data anno_ticks; set anno_days;
length function $8 text $20;
xsys='2'; ysys='1'; when='a';
x=catch_date; y=0;
function='move'; output;
y=1.5; function='draw'; output;
run;
data anno_days; set anno_days;
length function $8 text $20;
xsys='2'; ysys='1'; when='a';
x=catch_date; y=0;
function='label'; position='e'; text=put(catch_date,day.);
run;
data anno_months;
informat catch_date date9.;
format catch_date date9.;
input catch_date;
datalines;
15oct1988
15nov1988
15dec1988
15jan1989
;
run;
data anno_months; set anno_months;
length function $8 text $20;
xsys='2'; ysys='1'; when='a';
x=catch_date; y=-7;
function='label'; position='5'; text=trim(left(put(catch_date,monname20.)));
run;
/*
Wanted the refline to be slightly to the left of the 1st of month,
therefore annotating it instead of using aurohref.
*/
data anno_ref;
informat catch_date date9.;
format catch_date date9.;
input catch_date;
datalines;
01nov1988
01dec1988
01jan1989
;
run;
data anno_ref; set anno_ref;
length function $8 text $20;
xsys='2'; ysys='1'; when='a';
x=catch_date-1; /* shift it left a bit */
y=0;
function='move'; output;
y=100; function='draw'; output;
run;
data anno_all; set anno_ticks anno_ref anno_days anno_months;
run;
goptions device=png;
goptions noborder;
ODS LISTING CLOSE;
ODS HTML path=odsout body="&name..htm"
(title="Roe Menhaden @ Beaufort, NC")
style=htmlblue;
goptions gunit=pct htitle=4.0 ftitle="albany amt/bold" htext=2.8 ftext="albany amt/bold";
symbol1 font='albany amt/unicode' value='25cf'x height=3.5 interpol=none color=black;
axis1 label=(h=3.5 angle=90 'Fishing Year') order=(1988 to 1999 by 1) minor=none
major=(height=-.75) offset=(5,5);
/*
Trick #3 - I force the x-axis to cross a year boundary
*/
axis2 label=none order=('01oct1988'd to '01feb1989'd by month) minor=none
major=none value=none offset=(0,0);
title1 h=1 " ";
title2 h=2 a=90 " ";
title3 h=2 a=-90 " ";
footnote1 h=5 ' ';
footnote2 j=l move=(+13,+0) font="thorndale amt/bold" h=3.0
'Figure 2. -- A scatter plot of dates when roe menhaden were landed at Beaufort,';
footnote3 j=l move=(+13,+0) font="thorndale amt/bold" h=3.0
'North Carolina, 1988-1999 ("Fishing Year" includes January of the following';
footnote4 j=l move=(+13,+0) font="thorndale amt/bold" h=3.0
'calendar year).';
footnote5 h=2 ' ';
proc gplot data=fish_data anno=anno_all;
format plot_date date9.;
plot fishing_year*plot_date=1 /
vaxis=axis1
haxis=axis2
des='' name="&name";
run;
quit;
ODS HTML CLOSE;
ODS LISTING;
If it is important to retain the scale for the days along the X axis, then I suggest use SGPLOT procedure, with DAYn. format for X variable. You can draw reflines at each month end for the separators. With SAS 9.3, you can add the month names using SGAnnotate.
If scale for the dates on x axis is not critical, you could use the SGPANEL procedure. Extract monthname as a separate column and use it as the PANELBY variable with LAYOUT=COLUMNLATTICE, and ColumnHeaderPosition=bottom. Use a SCATTER plot with X=date with DAYn. format.
With SGPANEL solution, you may get data range in each column only to the extend you have data, and each cell will be of equal width. To force the dates in each column to span 1-30 (or 28 or 31), you could use try using another column that has data for those dates, and use that as a scatter ovarlay with markersize=0. I think that may force the correct dates on each axis.
If you are having problems, attach your data, and I can try it out.
Thanks, Sanjay. I have your book!
Here's an alternate way, if you want to get the *exact* same plot. I use a custom Gplot, with a bit of date manipulation and a bit of annotate. Below is the SAS/Graph output, and the code I used:
%let name=roe_menhaden_plot;
filename odsout '.';
/*
A scatter plot of dates when roe menhaden were landed at
Beaufort, North Carolina, 1988-1999. Using estimated data
from Figure 2 in the following paper:
http://spo.nwr.noaa.gov/mfr621/mfr6211.pdf
You can't really get this graph by default, and you have to
use a few little "tricks" ... look for 'Trick' in the comments...
*/
data fish_data;
informat catch_date date9.;
format catch_date date9.;
input catch_date;
datalines;
25oct1988
04nov1988
09nov1988
12nov1988
15nov1988
22nov1988
25nov1988
27nov1988
03dec1988
08dec1988
10dec1988
14dec1988
27dec1988
30dec1988
03jan1989
09jan1989
11jan1989
12oct1989
14oct1989
17oct1989
09nov1989
13nov1989
14nov1989
22nov1989
30nov1989
03jan1990
03nov1990
07nov1990
14nov1990
21nov1990
23nov1990
26nov1990
27nov1990
28nov1990
03dec1990
07dec1990
10dec1990
14dec1990
20dec1990
27dec1990
03jan1991
04jan1991
08jan1991
11jan1991
19jan1991
05nov1991
06nov1991
07nov1991
08nov1991
18nov1991
19nov1991
31dec1991
22jan1992
30oct1992
08nov1992
10nov1992
13nov1992
17nov1992
19nov1992
24nov1992
28nov1992
03dec1992
04dec1992
08dec1992
09dec1992
03nov1993
12nov1993
15nov1993
16nov1993
17nov1993
22nov1993
29nov1993
30nov1993
01dec1993
02dec1993
03dec1993
04dec1993
06dec1993
08dec1993
14dec1993
08nov1994
14nov1994
15nov1994
24nov1994
25nov1994
26nov1994
27nov1994
06dec1994
16nov1995
17nov1995
18nov1995
20nov1995
22nov1995
24nov1995
27nov1995
04dec1995
06dec1995
13dec1995
16dec1995
10nov1996
11nov1996
12nov1996
18nov1996
21nov1996
25nov1996
29nov1996
30nov1996
13dec1996
16dec1996
17dec1996
20jan1997
16nov1997
17nov1997
20nov1997
26nov1997
27nov1997
28nov1997
29nov1997
07dec1997
10dec1997
11dec1997
18dec1997
19dec1997
02nov1998
09nov1998
13nov1998
15nov1998
16nov1998
22nov1998
27nov1998
28nov1998
30nov1998
01dec1998
02dec1998
06dec1998
30nov1999
05dec1999
06dec1999
07dec1999
19dec1999
28dec1999
29dec1999
30dec1999
31dec1999
;
run;
data fish_data; set fish_data;
day=.; day=trim(left(put(catch_date,day.)));
month_name=trim(left(put(catch_date,monname20.)));
year=.; year=trim(left(put(catch_date,year4.)));
if month_name='January' then fishing_year=year-1;
else fishing_year=year;
/*
Trick #1 ... I'm converting the catch_date to a 1988 date,
so they can all be plotted along the same x-axis.
*/
plot_date=catch_date-((fishing_year-1988)*365.25);
run;
/*
Trick #2 - I annotate the tickmarks, and dates & months,
along the x-axis, so I can get them exactly the way I want.
*/
data anno_days;
informat catch_date date9.;
format catch_date date9.;
input catch_date;
datalines;
05oct1988
10oct1988
15oct1988
20oct1988
25oct1988
05nov1988
10nov1988
15nov1988
20nov1988
25nov1988
05dec1988
10dec1988
15dec1988
20dec1988
25dec1988
05jan1989
10jan1989
15jan1989
20jan1989
25jan1989
;
run;
data anno_ticks; set anno_days;
length function $8 text $20;
xsys='2'; ysys='1'; when='a';
x=catch_date; y=0;
function='move'; output;
y=1.5; function='draw'; output;
run;
data anno_days; set anno_days;
length function $8 text $20;
xsys='2'; ysys='1'; when='a';
x=catch_date; y=0;
function='label'; position='e'; text=put(catch_date,day.);
run;
data anno_months;
informat catch_date date9.;
format catch_date date9.;
input catch_date;
datalines;
15oct1988
15nov1988
15dec1988
15jan1989
;
run;
data anno_months; set anno_months;
length function $8 text $20;
xsys='2'; ysys='1'; when='a';
x=catch_date; y=-7;
function='label'; position='5'; text=trim(left(put(catch_date,monname20.)));
run;
/*
Wanted the refline to be slightly to the left of the 1st of month,
therefore annotating it instead of using aurohref.
*/
data anno_ref;
informat catch_date date9.;
format catch_date date9.;
input catch_date;
datalines;
01nov1988
01dec1988
01jan1989
;
run;
data anno_ref; set anno_ref;
length function $8 text $20;
xsys='2'; ysys='1'; when='a';
x=catch_date-1; /* shift it left a bit */
y=0;
function='move'; output;
y=100; function='draw'; output;
run;
data anno_all; set anno_ticks anno_ref anno_days anno_months;
run;
goptions device=png;
goptions noborder;
ODS LISTING CLOSE;
ODS HTML path=odsout body="&name..htm"
(title="Roe Menhaden @ Beaufort, NC")
style=htmlblue;
goptions gunit=pct htitle=4.0 ftitle="albany amt/bold" htext=2.8 ftext="albany amt/bold";
symbol1 font='albany amt/unicode' value='25cf'x height=3.5 interpol=none color=black;
axis1 label=(h=3.5 angle=90 'Fishing Year') order=(1988 to 1999 by 1) minor=none
major=(height=-.75) offset=(5,5);
/*
Trick #3 - I force the x-axis to cross a year boundary
*/
axis2 label=none order=('01oct1988'd to '01feb1989'd by month) minor=none
major=none value=none offset=(0,0);
title1 h=1 " ";
title2 h=2 a=90 " ";
title3 h=2 a=-90 " ";
footnote1 h=5 ' ';
footnote2 j=l move=(+13,+0) font="thorndale amt/bold" h=3.0
'Figure 2. -- A scatter plot of dates when roe menhaden were landed at Beaufort,';
footnote3 j=l move=(+13,+0) font="thorndale amt/bold" h=3.0
'North Carolina, 1988-1999 ("Fishing Year" includes January of the following';
footnote4 j=l move=(+13,+0) font="thorndale amt/bold" h=3.0
'calendar year).';
footnote5 h=2 ' ';
proc gplot data=fish_data anno=anno_all;
format plot_date date9.;
plot fishing_year*plot_date=1 /
vaxis=axis1
haxis=axis2
des='' name="&name";
run;
quit;
ODS HTML CLOSE;
ODS LISTING;
Wow! Thanks!
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.