BookmarkSubscribeRSS Feed
tc
Lapis Lazuli | Level 10 tc
Lapis Lazuli | Level 10

2024MensOlympicsBasketballFinal.png

 

An ODS Graphics scoring chart of the USA's victory over France Saturday in the 2024 Paris Olympics Men's Basketball Final that illustrates how the amazing Steph Curry's end-of-game 3-pointers helped Team USA clinch the Gold. Enjoy the Closing Ceremony, all!

 

 

* Fun With SAS ODS Graphics: Paris Olympics 2024 Men's Basketball Final - USA vs France
  Play-by-Play Data from usab.com/boxscore/2016;

proc import file="~/FranceUSA.xlsx" out=scoring dbms=xlsx replace;  * Get scoring data;

data scoring2;                                                      * Tweak data for charting;
length country $ 6; format country $6.;
set scoring end=eof; 
time=hms(0,hour(time),minute(time));                                * Fix Excel times (hh:mm -> mm:ss);       
time='0:10:00't-time+(quarter-1)*'0:10:00't;                        * Convert quarter times to game times;
format time mmss5.;
if country='FRA' then do; country='FRANCE'; countrysort=2; end;     * Get country names and force sort order;
if country='USA' then do; country='USA'; countrysort=1; end;
if points=3 then points3=points;                                    * Categorize points by shot type;
if points=2 then points2=points;
if points=1 then points1=points;
pointsort=points;
output;
player=country; countrysort=0; output;                              * Generate team-level scoring rows; 
if eof;                                                             * Generate team separators; 
pointsort=999; time='0:00:00't; points=.; points3=.; points2=.; points1=.; 
country='USA'; player='TEAM USA'; countrysort=1; output;
country='FRANCE'; player='TEAM FRANCE'; countrysort=2; pointsort=999; output;

proc sql;                                                           * Append total scores for sorting; 
create table scoring3 as 
select s.*, p.totpoints, p.totpoints3, p.totpoints2, p.totpoints1 
from scoring2 s
left join 
(select player, country, sum(points) as totpoints, sum(points3) as totpoints3,
        sum(points2) as totpoints2, sum(points1) as totpoints1 
 from scoring2 group by 1, 2) p 
on s.player=p.player and s.country=p.country 
order by countrysort, pointsort desc, totpoints desc, country, player;

data attrmapPoints;                                                * Distinguish shot types by color and size;
input id $ value $ fillcolor $ markersize;
datalines;
point 1 red 12 
point 2 blue 18 
point 3 green 24 
;
options missing=' ';
ods graphics / width=14in height=8.5in noborder;

proc sgplot data=scoring3 dattrmap=attrmapPoints;                  * Scatter plot of team/player scoring, highest scorers first;
title height=16pt "2024 PARIS OLYMPICS MEN'S BASKETBALL FINAL - USA VS FRANCE";
scatter x=time y=player / attrid=point group=points jitter FILLEDOUTLINEDMARKERS markeroutlineattrs=(color=black) markerattrs=(symbol=circlefilled) transparency=.6; * Jitter scores for shots occuring at same clock time (e.g., free throws);
xaxis display=(nolabel noline noticks) values=('00:00:00't to'00:40:00't by '00:02:00't); 
yaxis display=(nolabel noline noticks)  valueattrs=(size=10pt) grid discreteorder=data reverse;
yaxistable totpoints / stat=mean label='PTS' labelattrs=(size=8pt weight=bold)  valueattrs=(size=10pt) location=outside; * Show total points by categories;
yaxistable totpoints3 / stat=mean label='3' labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
yaxistable totpoints2 / stat=mean label='2' labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
yaxistable totpoints1 / stat=mean label='1' labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
keylegend / exclude=(".") SORTORDER=ASCENDING noborder location=outside title="POINTS" position=top; 
refline '0:00:00't '0:10:00't '0:20:00't '0:30:00't '0:40:00't / axis=x; * Draw reference lines to show start/end of quarters;
refline 'TEAM USA' 'TEAM FRANCE' / axis=y lineattrs=(thickness=6pt); * Draw separator lines between teams;
run;

 

SAMPLE DATA

Quarter Time Play FRA USA COUNTRY PLAYER EVENT POINTS
1 9:22 USA: LeBron James: 2 Pointer 0 2 USA  LeBron James  2 Pointer 2
1 9:12 FRA: Victor Wembanyama: 3 Pointer 3 2 FRA  Victor Wembanyama  3 Pointer 3
1 9:01 USA: Devin Booker: 3 Pointer 3 5 USA  Devin Booker  3 Pointer 3
1 8:50 FRA: Nicolas Batum: 2 Pointer 5 5 FRA  Nicolas Batum  2 Pointer 2
1 8:28 FRA: Victor Wembanyama: 2 Pointer 7 5 FRA  Victor Wembanyama  2 Pointer 2
1 7:21 USA: Kevin Durant: 3 Pointer 7 8 USA  Kevin Durant  3 Pointer 3
1 6:52 USA: Devin Booker: 2 Pointer 7 10 USA  Devin Booker  2 Pointer 2
12 REPLIES 12
PaigeMiller
Diamond | Level 26

This is a very nice graph. However, I would like to make a suggestion for improvement. The scores of both teams need to be plotted on the same x-axis.

--
Paige Miller
tc
Lapis Lazuli | Level 10 tc
Lapis Lazuli | Level 10

@PaigeMiller: Good suggestion! I was struggling with the question of how to show who was leading and by how much throughout the game. I was considering adding a step chart of the scores, a waterfall, or some kind of a +/- lead chart but wasn't sure how well I could align the axes of the two charts. In retrospect, just displaying the scores on the x-axis at 2-minute intervals on the existing chart would do the trick! 

ChrisNZ
Tourmaline | Level 20
Why not 2 simple lines? No need to round to 2 minutes, plot as scores come.
tc
Lapis Lazuli | Level 10 tc
Lapis Lazuli | Level 10

@ChrisNZ: Good idea, too! While I think that would work fine for plots of scores, the problem with displaying the scores themselves is that new ones can come in near each other or even at the same time, e.g., free-throws and a 2- or 3-pointer can occur at the same time with the clock stopped. ODS Graphics' jitter option takes care of that nicely here with the scatter plot markers in the chart (without me even having to lift a finger! 😀). While ODS Graphics also offers neat collision-avoidance for data labels in scatter plots, I'm not sure how well that would work for this particular data and layout (everything is plotted on horizontal lines, increasing the likelihood of collisions). Suppose I could try it and find out! Not sure if there's an option to only display labels that would not cause overlapping (hard to keep track of which dataviz software offers which features!), but I suppose one could always DIY something to ty to prevent collisions (even if I'm too lazy to do so and would likely settle for a "good-enough" every-two-minutes display! 😀).

 

UPDATE: Now that I think about it, if I created an HTML version of this chart, I could do exactly what you're suggesting by providing hover-over tooltips that would display the scores for every marker!

WarrenKuhfeld
Ammonite | Level 13

Nice! I have always been a big fan of and proponent of the axis table. I love the combination of graphical displays along with the axis table.

ChrisNZ
Tourmaline | Level 20

Lines added.

 

ChrisNZ_0-1723558330060.png

 


/* data found here: https://www.espn.com/mens-olympics-basketball/playbyplay/_/gameId/401694866 */

proc import file="~/France USA 2024.xlsx" out=Q1 dbms=xlsx replace; sheet='1st';
proc import file="~/France USA 2024.xlsx" out=Q2 dbms=xlsx replace; sheet='2nd';
proc import file="~/France USA 2024.xlsx" out=Q3 dbms=xlsx replace; sheet='3rd';
proc import file="~/France USA 2024.xlsx" out=Q4 dbms=xlsx replace; sheet='4th';
run;

data FIX_DATA;  
  format time mmss5. PLAY $100.; 
  set Q1-Q4 indsname=_INDS ;
  where TIME;
  POINTS= dif(FRA) + dif(USA);
  if POINTS;
  COUNTRY    =ifc(dif(USA) ne 0, 'USA', 'FRANCE');
  COUNTRYSORT=ifn(COUNTRY='USA', 1, 2);
  QUARTER    = input(compress(_INDS,,'dk'),1.);
  TIME       = hms(0,hour(TIME),minute(TIME));                     %* Fix Excel times (hh:mm -> mm:ss)   ;
  TIME       = '0:10:00't-TIME+(QUARTER-1)*'0:10:00't;             %* Convert quarter times to game times;
  POINTS3    = POINTS*(POINTS=3 );                                 %* Prepare YAXISTABLE; 
  POINTS2    = POINTS*(POINTS=2) ;
  POINTS1    = POINTS*(POINTS=1);
  POINTSORT  = POINTS;
  PLAYER     = substr(PLAY, 1, index(PLAY, 'made')-1);
run;

data SET_Y_GROUPS;  
  set FIX_DATA end=LASTOBS;
  output;                                                        %* Used for per-player plot;
  PLAYER=COUNTRY; COUNTRYSORT=0;                                 
  output;                                                        %* Used for per-country plot ; 
  COUNTRYSORT=4; PLAYER='Score Plot'; 
  output;                                                        %* Used to reserve space for sparkline plot at the bottom ;
  if LASTOBS;                                                    %* Used to draw team separators; 
  POINTSORT=999; TIME='0:00:00't; call missing(of POINTS1-POINTS3, POINTS);
  COUNTRY='USA'   ; PLAYER='TEAM USA'   ; COUNTRYSORT=1; output;
  COUNTRY='FRANCE'; PLAYER='TEAM FRANCE'; COUNTRYSORT=2; output;
run;

proc sql;                                                           * Append total scores for sorting; 
  create table PLOT as 
  select s.*, p.TOTPOINTS, p.TOTPOINTS3, p.TOTPOINTS2, p.TOTPOINTS1 
  from SET_Y_GROUPS s
  left join 
  (select PLAYER, COUNTRY, sum(POINTS) as TOTPOINTS  , sum(POINTS1) as TOTPOINTS1
                         , sum(POINTS2) as TOTPOINTS2, sum(POINTS3) as TOTPOINTS3
   from SET_Y_GROUPS group by 1, 2) p 
  on s.player=p.player and s.country=p.country 
  order by COUNTRYSORT, POINTSORT desc, TOTPOINTS desc, COUNTRY, PLAYER;

data ANNO;  
  retain X1SPACE X2SPACE 'datavalue' Y1SPACE Y2SPACE 'datapercent' FUNCTION 'line' LINECOLOR 'blue'; 
  do until (LASTOBS);
    set FIX_DATA(where=(COUNTRY='USA')) end=LASTOBS;
    P+POINTS;
    N+1;
    if N=1 then do; X1=TIME; Y1=-5; end;
    else do; X2=TIME; Y2=P*.1-5; output; X1=X2; Y1=Y2; end; 
  end;
  
  call missing(N,P);
  LINECOLOR='red';
  do until (LASTOBS1);
    set FIX_DATA(where=(COUNTRY='FRANCE')) end=LASTOBS1;
    P+POINTS;
    N+1;
    if N=1 then do; X1=TIME; Y1=-5; end;
    else do; X2=TIME; Y2=P*.1-5; output; X1=X2; Y1=Y2; end;
  end;
run;  

data ATTRMAPPOINTS;                                                * Distinguish shot types by color and size;
  input ID $ VALUE $ FILLCOLOR $ MARKERSIZE;
datalines;
point 1 red 12 
point 2 blue 18 
point 3 green 24 
;
options missing=' ';
ods graphics / width=14in height=8.5in noborder;

proc sgplot data=PLOT dattrmap=ATTRMAPPOINTS sganno=ANNO;                  * Scatter plot of team/player scoring, highest scorers first;
  title height=16pt "2024 PARIS OLYMPICS MEN'S BASKETBALL FINAL - USA VS FRANCE";
  scatter x=TIME y=PLAYER / group=POINTS attrid=point jitter filledoutlinedmarkers markeroutlineattrs=(color=black) markerattrs=(symbol=circlefilled) transparency=.6; * Jitter scores for shots occuring at same clock time (e.g., free throws);
  xaxis display=(nolabel noline noticks) values=('00:00:00't to'00:40:00't by '00:02:00't); 
  yaxis display=(nolabel noline noticks)  valueattrs=(size=10pt) grid discreteorder=data reverse;
  yaxistable TOTPOINTS  / stat=mean label='PTS' labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside; * Show total points by categories;
  yaxistable TOTPOINTS3 / stat=mean label='3'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS2 / stat=mean label='2'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS1 / stat=mean label='1'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  keylegend / exclude=(".") sortorder=ascending noborder location=outside title="POINTS" position=top; 
  refline 'TEAM USA' 'TEAM FRANCE' / axis=y lineattrs=(thickness=6pt); * Draw separator lines between teams;
  refline 'Score Plot' / axis=y lineattrs=(thickness=22pt color=white); *Canvas for plot;
  refline '0:00:00't '0:10:00't '0:20:00't '0:30:00't '0:40:00't / axis=x; * Draw reference lines to show start/end of quarters;
 
run;
ChrisNZ
Tourmaline | Level 20

I almost forgot to label the sparklines.

 

ChrisNZ_0-1723558759022.png

 

 

 


/* data found here: https://www.espn.com/mens-olympics-basketball/playbyplay/_/gameId/401694866 */

proc import file="~/France USA 2024.xlsx" out=Q1 dbms=xlsx replace; sheet='1st';
proc import file="~/France USA 2024.xlsx" out=Q2 dbms=xlsx replace; sheet='2nd';
proc import file="~/France USA 2024.xlsx" out=Q3 dbms=xlsx replace; sheet='3rd';
proc import file="~/France USA 2024.xlsx" out=Q4 dbms=xlsx replace; sheet='4th';
run;

data FIX_DATA;  
  format time mmss5. PLAY $100.; 
  set Q1-Q4 indsname=_INDS ;
  where TIME;
  POINTS= dif(FRA) + dif(USA);
  if POINTS;
  COUNTRY    =ifc(dif(USA) ne 0, 'USA', 'FRANCE');
  COUNTRYSORT=ifn(COUNTRY='USA', 1, 2);
  QUARTER    = input(compress(_INDS,,'dk'),1.);
  TIME       = hms(0,hour(TIME),minute(TIME));                     %* Fix Excel times (hh:mm -> mm:ss)   ;
  TIME       = '0:10:00't-TIME+(QUARTER-1)*'0:10:00't;             %* Convert quarter times to game times;
  POINTS3    = POINTS*(POINTS=3 );                                 %* Prepare YAXISTABLE; 
  POINTS2    = POINTS*(POINTS=2) ;
  POINTS1    = POINTS*(POINTS=1);
  POINTSORT  = POINTS;
  PLAYER     = substr(PLAY, 1, index(PLAY, 'made')-1);
run;

data SET_Y_GROUPS;  
  set FIX_DATA end=LASTOBS;
  output;                                                        %* Used for per-player plot;
  PLAYER=COUNTRY; COUNTRYSORT=0;                                 
  output;                                                        %* Used for per-country plot ; 
  COUNTRYSORT=4; PLAYER='Score Plot'; 
  output;                                                        %* Used to reserve space for sparkline plot at the bottom ;
  if LASTOBS;                                                    %* Used to draw team separators; 
  POINTSORT=999; TIME='0:00:00't; call missing(of POINTS1-POINTS3, POINTS);
  COUNTRY='USA'   ; PLAYER='TEAM USA'   ; COUNTRYSORT=1; output;
  COUNTRY='FRANCE'; PLAYER='TEAM FRANCE'; COUNTRYSORT=2; output;
run;

proc sql;                                                           * Append total scores for sorting; 
  create table PLOT as 
  select s.*, p.TOTPOINTS, p.TOTPOINTS3, p.TOTPOINTS2, p.TOTPOINTS1 
  from SET_Y_GROUPS s
  left join 
  (select PLAYER, COUNTRY, sum(POINTS) as TOTPOINTS  , sum(POINTS1) as TOTPOINTS1
                         , sum(POINTS2) as TOTPOINTS2, sum(POINTS3) as TOTPOINTS3
   from SET_Y_GROUPS group by 1, 2) p 
  on s.player=p.player and s.country=p.country 
  order by COUNTRYSORT, POINTSORT desc, TOTPOINTS desc, COUNTRY, PLAYER;

data ANNO;  
  retain X1SPACE X2SPACE 'datavalue' Y1SPACE Y2SPACE 'datapercent' FUNCTION 'line' LINECOLOR 'blue'; 
  do until (LASTOBS);
    set FIX_DATA(where=(COUNTRY='USA')) end=LASTOBS;
    P+POINTS;
    N+1;
    if N=1 then do; X1=TIME; Y1=-5; end;
    else do; X2=TIME; Y2=P*.1-5; output; X1=X2; Y1=Y2; end; 
  end;
  
  call missing(N,P);
  LINECOLOR='red';
  do until (LASTOBS1);
    set FIX_DATA(where=(COUNTRY='FRANCE')) end=LASTOBS1;
    P+POINTS;
    N+1;
    if N=1 then do; X1=TIME; Y1=-5; end;
    else do; X2=TIME; Y2=P*.1-5; output; X1=X2; Y1=Y2; end;
  end;
  FUNCTION='text'; X1='0:16:00't; Y1= 1; TEXTCOLOR='blue'; LABEL='USA   '; output;  
  FUNCTION='text'; X1='0:18:00't; Y1=-4; TEXTCOLOR='red '; LABEL='France'; output;
run;  


data ATTRMAPPOINTS;                                                * Distinguish shot types by color and size;
  input ID $ VALUE $ FILLCOLOR $ MARKERSIZE;
datalines;
point 1 red 12 
point 2 blue 18 
point 3 green 24 
;
options missing=' ';
ods graphics / width=14in height=8.5in noborder;

proc sgplot data=PLOT dattrmap=ATTRMAPPOINTS sganno=ANNO;                  * Scatter plot of team/player scoring, highest scorers first;
  title height=16pt "2024 PARIS OLYMPICS MEN'S BASKETBALL FINAL - USA VS FRANCE";
  scatter x=TIME y=PLAYER / group=POINTS attrid=point jitter filledoutlinedmarkers markeroutlineattrs=(color=black) markerattrs=(symbol=circlefilled) transparency=.6; * Jitter scores for shots occuring at same clock time (e.g., free throws);
  xaxis display=(nolabel noline noticks) values=('00:00:00't to'00:40:00't by '00:02:00't); 
  yaxis display=(nolabel noline noticks)  valueattrs=(size=10pt) grid discreteorder=data reverse;
  yaxistable TOTPOINTS  / stat=mean label='PTS' labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside; * Show total points by categories;
  yaxistable TOTPOINTS3 / stat=mean label='3'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS2 / stat=mean label='2'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS1 / stat=mean label='1'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  keylegend / exclude=(".") sortorder=ascending noborder location=outside title="POINTS" position=top; 
  refline 'TEAM USA' 'TEAM FRANCE' / axis=y lineattrs=(thickness=6pt); * Draw separator lines between teams;
  refline 'Score Plot' / axis=y lineattrs=(thickness=22pt color=white); *Canvas for plot;
  refline '0:00:00't '0:10:00't '0:20:00't '0:30:00't '0:40:00't / axis=x; * Draw reference lines to show start/end of quarters;
 
run;
ChrisNZ
Tourmaline | Level 20

Alright, final version.

Fixed a bug with player order, simplified the code, highlighted the line plot.

ChrisNZ_0-1723617329639.png

 

/* Source: https://www.espn.com/mens-olympics-basketball/playbyplay/_/gameId/401694866 */

proc import file="~/France USA 2024.xlsx" out=Q1 dbms=xlsx replace; sheet='1st';
proc import file="~/France USA 2024.xlsx" out=Q2 dbms=xlsx replace; sheet='2nd';
proc import file="~/France USA 2024.xlsx" out=Q3 dbms=xlsx replace; sheet='3rd';
proc import file="~/France USA 2024.xlsx" out=Q4 dbms=xlsx replace; sheet='4th';
run;

data CLEANUP;  
  format time mmss5. PLAY $100.; 
  set Q1-Q4 indsname=_INDS ;
  where TIME;                                                   %* No empty excel lines;
  POINTS= dif(FRA) + dif(USA);                                  %* Get score change;
  if POINTS;                                                    %* Only lines where the score changes;
  COUNTRY    = ifc(dif(USA) ne 0, 'USA', 'FRANCE');             %* Identify which country scored;
  COUNTRYSORT= ifn(COUNTRY='USA', 1, 2);                        %* Set sort order for the graph;
  QUARTER    = input(compress(_INDS, , 'dk'),1.);               %* Set game quarter; 
  PLAYER     = substr(PLAY, 1, index(PLAY, 'made')-1);          %* Set player name;
  TIME       = hms(0,hour(TIME),minute(TIME));                  %* Excel time to SAS time (hh:mm -> mm:ss)   ;
  TIME       = '0:10:00't-TIME+(QUARTER-1)*'0:10:00't;          %* Convert quarter times to game times;
  POINTS3    = POINTS*(POINTS=3);                               %* Prepare YAXISTABLE; 
  POINTS2    = POINTS*(POINTS=2);                               %* Prepare YAXISTABLE;
  POINTS1    = POINTS*(POINTS=1);                               %* Prepare YAXISTABLE;
run;

data YGROUPS;                                                   %* 4 Groups: Country scores, player scores, dividers, line plot;

  set CLEANUP end=LASTOBS; 
  output;                                                       %* Group for per-player plot;
  
  PLAYER=COUNTRY; COUNTRYSORT=0; output;                        %* Group for per-country plot, top of Y axis (COUNTRYSORT=0);                                                
  
  if LASTOBS;                                                   %* At the end, write out the data needed to display the 2 other groups;
  call missing(of POINTS1-POINTS3, POINTS);                     %* No YAXISTABLE data;
  
  TIME='0:00:00't; POINTSORT=999;                               %* Group used to draw team dividers;
  PLAYER='TEAM USA'   ; COUNTRYSORT=1; output;                  %* COUNTRYSORT as needed and POINTSORT=999 to be at the top of the country players; 
  PLAYER='TEAM FRANCE'; COUNTRYSORT=2; output;

  PLAYER='09'x; COUNTRYSORT=4; output;                          %* Group to reserve space for sparkline plot, bottom of Y axis (COUNTRYSORT=4);
                      
run;

proc sql;                                                       %* Derive total scores used for sorting; 
  create table PLOT as 
  select *, sum(POINTS)  as TOTPOINTS , sum(POINTS1) as TOTPOINTS1
          , sum(POINTS2) as TOTPOINTS2, sum(POINTS3) as TOTPOINTS3
  from YGROUPS 
  group by PLAYER, COUNTRY
  order by COUNTRYSORT, POINTSORT desc, TOTPOINTS desc, COUNTRY, PLAYER;
quit;

data ANNO;                                                      %* Create line plots, line plot labels, line plot background;
  length FUNCTION $12;
  retain X1SPACE X2SPACE 'datavalue' Y1SPACE Y2SPACE DRAWSPACE 'datapercent' FUNCTION 'line' LINECOLOR 'blue' WIDTH 105; 
  
  X1=0; Y1=-6; 
  do until (LASTOBS);
    set CLEANUP(where=(COUNTRY='USA')) end=LASTOBS ;
    P+POINTS;
    X2=ifn(LASTOBS, '0:40:00't, TIME); 
    Y2=P*.1-6; 
    output; 
    X1=X2; Y1=Y2; 
  end;  
  
  X1=0; Y1=-6; P=0;
  LINECOLOR='red';
  do until (LASTOBS1);
    set CLEANUP(where=(COUNTRY='FRANCE')) end=LASTOBS1 ;
    P+POINTS;
    X2=ifn(LASTOBS1, '0:40:00't, TIME); 
    Y2=P*.1-6; 
    output; 
    X1=X2; Y1=Y2; 
  end;
  
  FUNCTION='text     '; X1= '0:18:00't; Y1= 0; TEXTCOLOR='blue '; LABEL='USA       '; output; %* line plot label;
  FUNCTION='text     '; X1= '0:19:00't; Y1=-4; TEXTCOLOR='red  '; LABEL='France    '; output; %* line plot label;
  FUNCTION='text     '; X1=-'0:03:30't; Y1=-1; TEXTCOLOR='black'; LABEL='GAME SCORE'; output; %* Y axis value   ;
  FUNCTION='rectangle'; X1= '0:20:00't; Y1=-1; FILLCOLOR='lightyellow'; HEIGHT=10; DISPLAY='fill'; LAYER='back' ;output;
run;  

data ATTRMAPPOINTS;                                             %* Differentiate shot types by using color and size;
  input ID $ VALUE $ FILLCOLOR $ MARKERSIZE;
datalines;
point 1 red 12 
point 2 blue 18 
point 3 green 24 
;
options missing=' ';
ods graphics / width=14in height=8.5in noborder;

proc sgplot data=PLOT dattrmap=ATTRMAPPOINTS sganno=ANNO nowall;  %* Scatter plot of team/player scoring, highest scorers first;
  title height=16pt "2024 PARIS OLYMPICS MEN'S BASKETBALL FINAL - USA VS FRANCE";
  scatter x=TIME y=PLAYER / group=POINTS attrid=point jitter filledoutlinedmarkers markeroutlineattrs=(color=black) markerattrs=(symbol=circlefilled) transparency=.6; %* Jitter scores for shots occuring at same clock time (e.g., free throws);
  xaxis display=(nolabel noline noticks) values=('00:00:00't to'00:40:00't by '00:02:00't) ; 
  yaxis display=(nolabel noline noticks)  valueattrs=(size=10pt) grid discreteorder=data reverse;
  yaxistable TOTPOINTS  / stat=mean label='PTS' labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside; %* Show total points by categories;
  yaxistable TOTPOINTS3 / stat=mean label='3'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS2 / stat=mean label='2'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS1 / stat=mean label='1'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  keylegend / exclude=(' ') sortorder=ascending noborder location=outside title="POINTS" position=top; 
  refline 'TEAM USA' 'TEAM FRANCE' / axis=y lineattrs=(thickness=6pt);       %* Draw separator lines between teams;
  refline '09'x / axis=y lineattrs=(thickness=8pt color=lightyellow);        %* Hide H ref line for game score ;
  refline ('0:00:00't to '0:40:00't by '0:10:00't) / axis=x;                 %* Draw V ref lines for start/end of quarters;
run;

 

 

 

ChrisNZ
Tourmaline | Level 20

How much information is too much?

 

I used a new data source https://www.fiba.basketball/en/events/mens-olympic-basketball-tournament-paris-2024/games/122608-FRA...

and added:

  • The missed shots (very light colour)
  • The leader tracker (at the bottom)
  • The on-court presence (2 visuals: a thin red line or a thick grey line).

I probably don't understand how the player being in/out works on that web page, so a few players' presence displays wrongly on the chart.

 

Here you go. Sorry, no comprehensive legend yet. What do you think? Information overload? Which presence marker do you prefer?

 

ChrisNZ_0-1723710924215.png

 

 

 

 

 

ChrisNZ
Tourmaline | Level 20

Perfection (almost)! 🙂

ChrisNZ_1-1723978791400.png

 

 

Spoiler

/* source https://www.fiba.basketball/en/events/mens-olympic-basketball-tournament-paris-2024/games/122608-FRA-USA#playByPlay */
data PLAYERS;
 input COUNTRY &$6. PLAYER &: $24.;   
 retain FMTNAME '$country';
cards;
USA  Kevin Durant
USA  LeBron James
USA  Bam Adebayo
USA  Devin Booker
USA  Stephen Curry
USA  Anthony Davis
USA  Anthony Edwards
USA  Joel Embiid
USA  Tyrese Haliburton
USA  Jrue Holiday
USA  Kawhi Leonard
USA  Jayson Tatum
FRANCE  Andrew Albicy
FRANCE  Bilal Coulibaly
FRANCE  Evan Fournier
FRANCE  Frank Ntilikina
FRANCE  Guerschon Yabusele
FRANCE  Isaia Cordinier
FRANCE  Mathias Lessort
FRANCE  Matthew Strazel
FRANCE  Nando De Colo
FRANCE  Nicolas Batum
FRANCE  Rudy Gobert
FRANCE  Victor Wembanyama
run;
proc format cntlin=PLAYERS(rename=(PLAYER=START COUNTRY=LABEL));
run;
data CLEANUP;
  input @1 X :& $80. ;
  if X=:'End of' then QUARTER+1;
  format TIMEIN TIME time. TEXT1 TEXT2 $80.;
  if      index(X, ':')  then TIMEIN=hms(0, input(scan(X,1,':'),2.), input(scan(X,2,':'),2.));
  else if index(X, '+')  then POINTS=input(X,2.);
  else if index(X, '-')  then ;
  else if missing(TEXT1) then TEXT1 =X;
  else                        TEXT2 =X; 
  if index(X, '-') then do;
    SCORE = X;
    TIME  = QUARTER * '0:10:00't - TIMEIN;
    if prxmatch('/\dpt.*missed/',TEXT1) then POINTS=input(compress(TEXT1,,'dk'),1.)/10;
    if TEXT1 not in: (' ', 'team offensive', 'Start of', 'End of', 'Timeout') then PLAYER=catx(' ',scan(TEXT1,1), scan(TEXT1,2));
    if PLAYER=:'Nando' then PLAYER='Nando De Colo';   
    COUNTRY=put(PLAYER,$country.);
    COUNTRYSORT= ifn(COUNTRY='USA', 1, 2);                        %* Set sort order for the graph;
    POINTS3    = POINTS*(POINTS=3);                               %* Prepare YAXISTABLE; 
    POINTS2    = POINTS*(POINTS=2);                               %* Prepare YAXISTABLE;
    POINTS1    = POINTS*(POINTS=1);                               %* Prepare YAXISTABLE;
    output;
    call missing(TIME, POINTS, TEXT1, TEXT2);
  end;  
  retain TIMEIN POINTS TEXT1 TEXT2;
cards4;
00:00
End of period
15 - 20
00:02
Isaia Cordinier 2pt step back jump shot missed
15 - 20
00:28
Anthony Edwards
+3
3pt step back jump shot made
15 - 20
00:42
Anthony Edwards defensive rebound
15 - 17
00:42
Evan Fournier 3pt jump shot missed
15 - 17
00:48
Rudy Gobert foul drawn
15 - 17
00:48
Jayson Tatum personal foul
15 - 17
00:54
Evan Fournier offensive rebound
15 - 17
00:54
Victor Wembanyama 3pt jump shot missed
15 - 17
01:00
Evan Fournier defensive rebound
15 - 17
01:00
Anthony Davis 2pt driving layup missed
15 - 17
01:15
Rudy Gobert made the assist
15 - 17
01:15
Bilal Coulibaly
+2
2pt floating jump shot made
15 - 17
01:37
Bilal Coulibaly defensive rebound
13 - 17
01:37
Anthony Edwards 3pt jump shot missed
13 - 17
01:45
Jayson Tatum steal
13 - 17
01:45
Victor Wembanyama turnover; ball handling
13 - 17
01:59
Jrue Holiday
OUT
13 - 17
01:59
LeBron James
IN
13 - 17
01:59
Kevin Durant
OUT
13 - 17
01:59
Stephen Curry
IN
13 - 17
01:59
Victor Wembanyama
OUT
13 - 17
01:59
Mathias Lessort
IN
13 - 17
01:59
Isaia Cordinier
OUT
13 - 17
01:59
Nicolas Batum
IN
13 - 17
01:59
Timeout
13 - 17
02:04
Anthony Davis made the assist
13 - 17
02:04
Anthony Edwards
+3
3pt pullup jump shot made
13 - 17
02:09
Anthony Edwards steal
13 - 14
02:09
Evan Fournier turnover; ball handling
13 - 14
02:17
Rudy Gobert defensive rebound
13 - 14
02:17
Anthony Edwards 2pt floating jump shot missed
13 - 14
02:35
Nicolas Batum made the assist
13 - 14
02:35
Rudy Gobert
+2
dunk made
13 - 14
02:45
Mathias Lessort defensive rebound
11 - 14
02:45
Jayson Tatum 3pt jump shot missed
11 - 14
02:56
Jayson Tatum defensive rebound
11 - 14
02:56
Evan Fournier 3pt pullup jump shot missed
11 - 14
03:25
Stephen Curry made the assist
11 - 14
03:25
Jayson Tatum
+2
dunk made
11 - 14
03:28
LeBron James steal
11 - 12
03:28
Evan Fournier turnover; bad pass
11 - 12
03:43
Nicolas Batum defensive rebound
11 - 12
03:43
Stephen Curry 3pt step back jump shot missed
11 - 12
04:01
Anthony Davis foul drawn
11 - 12
04:01
Mathias Lessort personal foul
11 - 12
04:04
Anthony Davis offensive rebound
11 - 12
04:04
LeBron James 2pt fadeaway jump shot missed
11 - 12
04:12
Jayson Tatum
OUT
11 - 12
04:12
Kevin Durant
IN
11 - 12
04:12
Anthony Edwards
OUT
11 - 12
04:12
Devin Booker
IN
11 - 12
04:12
Mathias Lessort
OUT
11 - 12
04:12
Guerschon Yabusele
IN
11 - 12
04:17
Kevin Durant foul drawn
11 - 12
04:17
Rudy Gobert personal foul
11 - 12
04:30
LeBron James defensive rebound
11 - 12
04:30
Nicolas Batum 3pt jump shot missed
11 - 12
04:44
Rudy Gobert defensive rebound
11 - 12
04:44
Stephen Curry 3pt jump shot missed
11 - 12
04:52
Bilal Coulibaly
OUT
11 - 12
04:52
Frank Ntilikina
IN
11 - 12
04:52
Anthony Davis
OUT
11 - 12
04:52
Joel Embiid
IN
11 - 12
04:52
Rudy Gobert
OUT
11 - 12
04:52
Victor Wembanyama
IN
11 - 12
04:52
Evan Fournier
OUT
11 - 12
04:52
Isaia Cordinier
IN
11 - 12
04:52
Stephen Curry foul drawn
11 - 12
04:52
Isaia Cordinier personal foul
11 - 12
04:54
Stephen Curry steal
11 - 12
04:54
Nicolas Batum turnover; bad pass
11 - 12
05:03
Nicolas Batum offensive rebound
11 - 12
05:03
Frank Ntilikina 3pt jump shot missed
11 - 12
05:21
LeBron James made the assist
11 - 12
05:21
Devin Booker
+2
layup made
11 - 12
05:32
Joel Embiid defensive rebound
11 - 10
05:32
Victor Wembanyama alley oop missed
11 - 10
05:52
Victor Wembanyama defensive rebound
11 - 10
05:52
Kevin Durant 3pt jump shot missed
11 - 10
06:14
Victor Wembanyama
+2
dunk made
11 - 10
06:22
Victor Wembanyama defensive rebound
9 - 10
06:22
Stephen Curry 3pt pullup jump shot missed
9 - 10
06:34
Victor Wembanyama made the assist
9 - 10
06:34
Guerschon Yabusele
+2
dunk made
9 - 10
06:52
Stephen Curry made the assist
7 - 10
06:52
Devin Booker
+2
layup made
7 - 10
07:00
Kevin Durant defensive rebound
7 - 8
07:00
Guerschon Yabusele 3pt jump shot missed
7 - 8
07:21
Devin Booker made the assist
7 - 8
07:21
Kevin Durant
+3
3pt jump shot made
7 - 8
07:30
Stephen Curry defensive rebound
7 - 5
07:30
LeBron James blocked the shot
7 - 5
07:30
Guerschon Yabusele 2pt driving layup missed
7 - 5
07:36
Guerschon Yabusele steal
7 - 5
07:36
Kevin Durant turnover; bad pass
7 - 5
07:43
LeBron James defensive rebound
7 - 5
07:43
Frank Ntilikina 3pt pullup jump shot missed
7 - 5
07:52
Frank Ntilikina defensive rebound
7 - 5
07:52
Joel Embiid 2pt turnaround jump shot missed
7 - 5
07:55
Kevin Durant foul drawn
7 - 5
07:55
Frank Ntilikina personal foul
7 - 5
08:00
Devin Booker defensive rebound
7 - 5
08:00
Victor Wembanyama 3pt jump shot from center missed
7 - 5
08:05
Isaia Cordinier steal
7 - 5
08:05
Stephen Curry turnover; bad pass
7 - 5
08:28
Victor Wembanyama
+2
2pt driving layup made
7 - 5
08:43
Stephen Curry turnover; bad pass
5 - 5
08:50
Nicolas Batum
+2
2pt putback dunk made
5 - 5
08:51
Nicolas Batum offensive rebound
3 - 5
08:51
Frank Ntilikina 2pt driving layup missed
3 - 5
09:01
LeBron James made the assist
3 - 5
09:01
Devin Booker
+3
3pt jump shot made
3 - 5
09:12
Frank Ntilikina made the assist
3 - 2
09:12
Victor Wembanyama
+3
3pt jump shot made
3 - 2
09:22
Kevin Durant made the assist
0 - 2
09:22
LeBron James
+2
dunk made
0 - 2
09:28
Kevin Durant defensive rebound
0 - 0
09:28
Isaia Cordinier 2pt driving layup missed
0 - 0
09:46
Nicolas Batum defensive rebound
0 - 0
09:46
Kevin Durant 3pt jump shot missed
0 - 0
10:00
Victor Wembanyama jump ball lost
0 - 0
10:00
Joel Embiid jump ball won
0 - 0
10:00
Start of game
0 - 0


00:00
End of period
41 - 49
00:00
Victor Wembanyama made the assist
41 - 49
00:00
Guerschon Yabusele
+2
layup made
41 - 49
00:24
Stephen Curry made the assist
39 - 49
00:24
Jrue Holiday
+3
3pt jump shot made
39 - 49
00:34
Anthony Davis defensive rebound
39 - 46
00:34
Evan Fournier 3pt jump shot missed
39 - 46
00:49
Isaia Cordinier foul drawn
39 - 46
00:49
Jrue Holiday turnover
39 - 46
00:49
Jrue Holiday offensive foul
39 - 46
01:02
Victor Wembanyama
+2
tip in made
39 - 46
01:05
Victor Wembanyama offensive rebound
37 - 46
01:05
Guerschon Yabusele 2nd of 2 free throws missed
37 - 46
01:05
Guerschon Yabusele
+1
1st of 2 free throws made
37 - 46
01:05
Anthony Davis
OUT
36 - 46
01:05
Bam Adebayo
IN
36 - 46
01:05
Guerschon Yabusele foul drawn
36 - 46
01:05
Bam Adebayo personal foul; 2 free throws awarded
36 - 46
01:10
Nicolas Batum offensive rebound
36 - 46
01:10
Guerschon Yabusele 3pt jump shot missed
36 - 46
01:20
Jrue Holiday
OUT
36 - 46
01:20
Devin Booker
IN
36 - 46
01:20
Isaia Cordinier foul drawn
36 - 46
01:20
Devin Booker personal foul
36 - 46
01:32
Devin Booker
+1
1st free throw made
36 - 46
01:32
Isaia Cordinier
OUT
36 - 45
01:32
Frank Ntilikina
IN
36 - 45
01:32
Devin Booker foul drawn
36 - 45
01:32
Evan Fournier personal foul; 1 free throw awarded
36 - 45
01:32
Kevin Durant made the assist
36 - 45
01:32
Devin Booker
+2
layup made
36 - 45
01:35
LeBron James steal
36 - 43
01:35
Frank Ntilikina turnover; bad pass
36 - 43
01:58
Kevin Durant made the assist
36 - 43
01:58
Stephen Curry
+3
3pt jump shot made
36 - 43
02:13
Victor Wembanyama
OUT
36 - 40
02:13
Mathias Lessort
IN
36 - 40
02:13
Guerschon Yabusele
+1
1st free throw made
36 - 40
02:13
Evan Fournier
OUT
35 - 40
02:13
Nando De Colo
IN
35 - 40
02:13
Guerschon Yabusele foul drawn
35 - 40
02:13
LeBron James personal foul; 1 free throw awarded
35 - 40
02:13
Guerschon Yabusele
+2
dunk made
35 - 40
02:33
Stephen Curry made the assist
33 - 40
02:33
Kevin Durant
+3
3pt jump shot made
33 - 40
02:43
Devin Booker defensive rebound
33 - 37
02:43
Nando De Colo 3pt jump shot missed
33 - 37
02:53
Guerschon Yabusele defensive rebound
33 - 37
02:53
Devin Booker 3pt jump shot missed
33 - 37
03:03
LeBron James defensive rebound
33 - 37
03:03
Guerschon Yabusele 3rd of 3 free throws missed
33 - 37
03:03
Guerschon Yabusele
+1
2nd of 3 free throws made
33 - 37
03:03
Nicolas Batum made the assist
32 - 37
03:03
Guerschon Yabusele
+1
1st of 3 free throws made
32 - 37
03:03
Guerschon Yabusele foul drawn
31 - 37
03:03
Bam Adebayo personal foul; 3 free throws awarded
31 - 37
03:26
LeBron James
+1
1st free throw made
31 - 37
03:26
Frank Ntilikina
OUT
31 - 36
03:26
Matthew Strazel
IN
31 - 36
03:26
Timeout
31 - 36
03:26
LeBron James foul drawn
31 - 36
03:26
Mathias Lessort personal foul; 1 free throw awarded
31 - 36
03:26
LeBron James
+2
2pt driving layup made
31 - 36
03:34
Nando De Colo
+2
2pt pullup jump shot made
31 - 34
03:53
Nando De Colo foul drawn
29 - 34
03:53
Devin Booker personal foul
29 - 34
03:59
Stephen Curry made the assist
29 - 34
03:59
Bam Adebayo
+2
dunk made
29 - 34
04:11
Mathias Lessort made the assist
29 - 32
04:11
Guerschon Yabusele
+2
layup made
29 - 32
04:31
Devin Booker made the assist
27 - 32
04:31
Stephen Curry
+3
3pt jump shot made
27 - 32
04:41
Bam Adebayo offensive rebound
27 - 29
04:41
Devin Booker 2pt pullup jump shot missed
27 - 29
04:50
Kevin Durant
OUT
27 - 29
04:50
Jrue Holiday
IN
27 - 29
04:50
Mathias Lessort
OUT
27 - 29
04:50
Bilal Coulibaly
IN
27 - 29
04:50
Nicolas Batum
OUT
27 - 29
04:50
Victor Wembanyama
IN
27 - 29
04:50
Stephen Curry foul drawn
27 - 29
04:50
Nando De Colo personal foul
27 - 29
04:50
 team defensive rebound
27 - 29
04:53
Matthew Strazel 3pt pullup jump shot missed
27 - 29
05:09
Jrue Holiday made the assist
27 - 29
05:09
Devin Booker
+3
3pt jump shot made
27 - 29
05:25
Matthew Strazel made the assist
27 - 26
05:25
Victor Wembanyama
+2
layup made
27 - 26
05:43
LeBron James
+2
2pt driving layup made
25 - 26
05:52
LeBron James defensive rebound
25 - 24
05:52
Guerschon Yabusele 2pt fadeaway jump shot missed
25 - 24
06:18
Victor Wembanyama defensive rebound
25 - 24
06:18
LeBron James 3pt pullup jump shot missed
25 - 24
06:26
LeBron James defensive rebound
25 - 24
06:26
Victor Wembanyama 2pt fadeaway jump shot missed
25 - 24
06:45
 team turnover; 24 seconds violation
25 - 24
07:10
Devin Booker
OUT
25 - 24
07:10
Anthony Davis
IN
25 - 24
07:10
Bam Adebayo
OUT
25 - 24
07:10
Jayson Tatum
IN
25 - 24
07:10
LeBron James
OUT
25 - 24
07:10
Kevin Durant
IN
25 - 24
07:10
Stephen Curry
OUT
25 - 24
07:10
Anthony Edwards
IN
25 - 24
07:10
Timeout
25 - 24
07:10
Matthew Strazel made the assist
25 - 24
07:10
Bilal Coulibaly
+2
dunk made
25 - 24
07:17
Nando De Colo defensive rebound
23 - 24
07:17
Kevin Durant 3pt jump shot missed
23 - 24
07:21
Jayson Tatum offensive rebound
23 - 24
07:21
Jayson Tatum 2pt floating jump shot missed
23 - 24
07:47
Bilal Coulibaly made the assist
23 - 24
07:47
Matthew Strazel
+3
3pt pullup jump shot made
23 - 24
08:00
Nando De Colo
OUT
20 - 24
08:00
Isaia Cordinier
IN
20 - 24
08:00
 team defensive rebound
20 - 24
08:02
Kevin Durant 3pt jump shot missed
20 - 24
08:20
Matthew Strazel made the assist
20 - 24
08:20
Guerschon Yabusele
+3
3pt jump shot made
20 - 24
08:42
Anthony Davis
+2
2pt putback dunk made
17 - 24
08:44
Anthony Davis offensive rebound
17 - 22
08:44
Jrue Holiday 2pt driving layup missed
17 - 22
08:52
Anthony Davis offensive rebound
17 - 22
08:52
Anthony Edwards 2pt turnaround jump shot missed
17 - 22
09:10
Victor Wembanyama
+2
tip in made
17 - 22
09:12
Victor Wembanyama offensive rebound
15 - 22
09:12
Guerschon Yabusele layup missed
15 - 22
09:32
Jrue Holiday made the assist
15 - 22
09:32
Anthony Davis
+2
layup made
15 - 22
09:39
Jrue Holiday defensive rebound
15 - 20
09:39
Anthony Davis blocked the shot
15 - 20
09:39
Isaia Cordinier 3pt jump shot missed
15 - 20
10:00
 jump ball situation; throw-in
15 - 20
10:00
Start of period
15 - 20


00:00
End of period
66 - 72
00:00
Nando De Colo
+2
2pt driving layup made
66 - 72
00:03
Nando De Colo steal
64 - 72
00:03
Anthony Edwards turnover; bad pass
64 - 72
00:23
Nando De Colo made the assist
64 - 72
00:23
Evan Fournier
+3
3pt step back jump shot made
64 - 72
00:38
Kevin Durant made the assist
61 - 72
00:38
Anthony Edwards
+2
dunk made
61 - 72
00:43
Anthony Davis steal
61 - 70
00:43
Evan Fournier turnover; bad pass
61 - 70
01:00
Victor Wembanyama steal
61 - 70
01:00
Anthony Davis turnover; ball handling
61 - 70
01:04
Anthony Davis offensive rebound
61 - 70
01:04
Kevin Durant 3pt jump shot from center missed
61 - 70
01:15
 team defensive rebound
61 - 70
01:17
Isaia Cordinier 2nd of 2 free throws missed
61 - 70
01:17
Isaia Cordinier 1st of 2 free throws missed
61 - 70
01:17
Victor Wembanyama
OUT
61 - 70
01:17
Guerschon Yabusele
IN
61 - 70
01:17
Isaia Cordinier foul drawn
61 - 70
01:17
Anthony Davis personal foul; 2 free throws awarded
61 - 70
01:19
Nando De Colo steal
61 - 70
01:19
Kevin Durant turnover; ball handling
61 - 70
01:34
Anthony Davis defensive rebound
61 - 70
01:34
Anthony Davis blocked the shot
61 - 70
01:34
Guerschon Yabusele layup missed
61 - 70
01:49
Anthony Davis
+2
layup made
61 - 70
01:51
Anthony Davis offensive rebound
61 - 68
01:51
Anthony Edwards 2pt step back jump shot missed
61 - 68
02:05
Jayson Tatum defensive rebound
61 - 68
02:05
Isaia Cordinier 2pt pullup jump shot missed
61 - 68
02:11
Kevin Durant
OUT
61 - 68
02:11
LeBron James
IN
61 - 68
02:11
Anthony Davis turnover; bad pass
61 - 68
02:30
Nando De Colo made the assist
61 - 68
02:30
Evan Fournier
+2
layup made
61 - 68
02:31
Anthony Edwards
OUT
59 - 68
02:31
Stephen Curry
IN
59 - 68
02:31
Isaia Cordinier
OUT
59 - 68
02:31
Bilal Coulibaly
IN
59 - 68
02:31
Rudy Gobert foul drawn
59 - 68
02:31
Jayson Tatum personal foul
59 - 68
02:46
LeBron James
+3
3pt pullup jump shot made
59 - 68
03:05
Evan Fournier
+3
3pt pullup jump shot made
59 - 65
03:23
Rudy Gobert defensive rebound
56 - 65
03:23
Jrue Holiday 3pt jump shot missed
56 - 65
03:31
Anthony Davis steal
56 - 65
03:31
Nando De Colo turnover; bad pass
56 - 65
03:51
Stephen Curry turnover; out of bounds
56 - 65
04:01
Anthony Davis
OUT
56 - 65
04:01
Devin Booker
IN
56 - 65
04:01
Jrue Holiday
OUT
56 - 65
04:01
Joel Embiid
IN
56 - 65
04:01
Jayson Tatum
OUT
56 - 65
04:01
Kevin Durant
IN
56 - 65
04:01
Evan Fournier
OUT
56 - 65
04:01
Victor Wembanyama
IN
56 - 65
04:01
Timeout
56 - 65
04:05
Nando De Colo made the assist
56 - 65
04:05
Victor Wembanyama
+3
3pt jump shot made
56 - 65
04:26
Joel Embiid made the assist
53 - 65
04:26
LeBron James
+2
dunk made
53 - 65
04:30
Joel Embiid defensive rebound
53 - 63
04:30
Bilal Coulibaly layup missed
53 - 63
04:34
Rudy Gobert steal
53 - 63
04:34
Stephen Curry turnover; ball handling
53 - 63
04:45
Victor Wembanyama
+2
tip in made
53 - 63
04:46
Victor Wembanyama offensive rebound
51 - 63
04:46
Nando De Colo 2pt driving layup missed
51 - 63
05:01
Nando De Colo defensive rebound
51 - 63
05:01
LeBron James 2pt driving layup missed
51 - 63
05:15
Guerschon Yabusele turnover; bad pass
51 - 63
05:38
LeBron James made the assist
51 - 63
05:38
Kevin Durant
+2
2pt fadeaway jump shot made
51 - 63
06:05
Nando De Colo
+3
3pt pullup jump shot made
51 - 61
06:12
Guerschon Yabusele offensive rebound
48 - 61
06:12
Bilal Coulibaly 2pt floating jump shot missed
48 - 61
06:18
Rudy Gobert steal
48 - 61
06:18
LeBron James turnover; bad pass
48 - 61
06:37
Nando De Colo
+1
1st free throw made
48 - 61
06:37
 Bench: technical foul
47 - 61
06:37
Joel Embiid foul drawn
47 - 61
06:37
Rudy Gobert personal foul
47 - 61
06:37
Rudy Gobert foul drawn
47 - 61
06:37
Joel Embiid personal foul
47 - 61
06:37
Joel Embiid steal
47 - 61
06:37
Victor Wembanyama turnover; bad pass
47 - 61
06:57
Nando De Colo
OUT
47 - 61
06:57
Andrew Albicy
IN
47 - 61
06:57
Timeout
47 - 61
06:58
LeBron James made the assist
47 - 61
06:58
Stephen Curry
+3
3pt jump shot made
47 - 61
07:12
Guerschon Yabusele
+1
2nd of 2 free throws made
47 - 58
07:12
Guerschon Yabusele
+1
1st of 2 free throws made
46 - 58
07:12
Bilal Coulibaly
OUT
45 - 58
07:12
Nicolas Batum
IN
45 - 58
07:12
Guerschon Yabusele foul drawn
45 - 58
07:12
LeBron James personal foul; 2 free throws awarded
45 - 58
07:36
Rudy Gobert
OUT
45 - 58
07:36
Isaia Cordinier
IN
45 - 58
07:36
Joel Embiid
+1
2nd of 2 free throws made
45 - 58
07:36
LeBron James made the assist
45 - 57
07:36
Joel Embiid
+1
1st of 2 free throws made
45 - 57
07:36
Joel Embiid foul drawn
45 - 56
07:36
Isaia Cordinier personal foul; 2 free throws awarded
45 - 56
07:54
Andrew Albicy made the assist
45 - 56
07:54
Guerschon Yabusele
+2
layup made
45 - 56
08:19
LeBron James made the assist
43 - 56
08:19
Stephen Curry
+3
3pt step back jump shot made
43 - 56
08:25
Kevin Durant steal
43 - 53
08:25
Isaia Cordinier turnover; ball handling
43 - 53
08:37
Joel Embiid
+1
2nd of 2 free throws made
43 - 53
08:37
LeBron James made the assist
43 - 52
08:37
Joel Embiid
+1
1st of 2 free throws made
43 - 52
08:37
Joel Embiid foul drawn
43 - 51
08:37
Guerschon Yabusele personal foul; 2 free throws awarded
43 - 51
08:45
Devin Booker foul drawn
43 - 51
08:45
Isaia Cordinier personal foul
43 - 51
08:53
Isaia Cordinier made the assist
43 - 51
08:53
Victor Wembanyama
+2
layup made
43 - 51
09:05
Andrew Albicy foul drawn
41 - 51
09:05
Devin Booker personal foul
41 - 51
09:05
 team defensive rebound
41 - 51
09:08
Stephen Curry 3pt jump shot missed
41 - 51
09:17
LeBron James defensive rebound
41 - 51
09:17
Isaia Cordinier 3pt pullup jump shot missed
41 - 51
09:44
Joel Embiid made the assist
41 - 51
09:44
Kevin Durant
+2
2pt pullup jump shot made
41 - 51
09:50
Joel Embiid offensive rebound
41 - 49
09:50
Devin Booker 3pt jump shot missed
41 - 49
10:00
 jump ball situation; throw-in
41 - 49
10:00
Start of period
41 - 49



00:00
End of game
87 - 98
00:03
 jump ball situation; throw-in
87 - 98
00:11
Stephen Curry steal
87 - 98
00:11
Isaia Cordinier turnover; ball handling
87 - 98
00:16
Isaia Cordinier
OUT
87 - 98
00:16
Nicolas Batum
IN
87 - 98
00:16
Victor Wembanyama foul drawn
87 - 98
00:16
Devin Booker personal foul
87 - 98
00:21
LeBron James made the assist
87 - 98
00:21
Devin Booker
+2
dunk made
87 - 98
00:28
Anthony Davis defensive rebound
87 - 96
00:28
Guerschon Yabusele 3pt jump shot from center missed
87 - 96
00:35
Stephen Curry
+3
3pt fadeaway jump shot made
87 - 96
00:54
Stephen Curry
OUT
87 - 93
00:54
Jrue Holiday
IN
87 - 93
00:55
Nicolas Batum made the assist
87 - 93
00:55
Victor Wembanyama
+3
3pt jump shot made
87 - 93
00:56
 team offensive rebound
84 - 93
01:00
Evan Fournier 3pt step back jump shot missed
84 - 93
01:04
Evan Fournier offensive rebound
84 - 93
01:04
Anthony Davis blocked the shot
84 - 93
01:04
Evan Fournier 3pt pullup jump shot missed
84 - 93
01:18
Jrue Holiday
OUT
84 - 93
01:18
Stephen Curry
IN
84 - 93
01:19
Devin Booker made the assist
84 - 93
01:19
Stephen Curry
+3
3pt step back jump shot made
84 - 93
01:43
Evan Fournier made the assist
84 - 90
01:43
Nicolas Batum
+3
3pt jump shot made
84 - 90
01:52
Stephen Curry
+3
3pt step back jump shot made
81 - 90
02:10
Nando De Colo
+2
2pt fadeaway jump shot made
81 - 87
02:22
Evan Fournier
OUT
79 - 87
02:22
Bilal Coulibaly
IN
79 - 87
02:22
Timeout
79 - 87
02:22
Kevin Durant
+1
2nd of 2 free throws made
79 - 87
02:22
Kevin Durant
+1
1st of 2 free throws made
79 - 86
02:22
Kevin Durant foul drawn
79 - 85
02:22
Guerschon Yabusele personal foul; 2 free throws awarded
79 - 85
02:25
Kevin Durant defensive rebound
79 - 85
02:25
Victor Wembanyama 3pt step back jump shot missed
79 - 85
02:47
LeBron James made the assist
79 - 85
02:47
Stephen Curry
+3
3pt pullup jump shot made
79 - 85
03:04
Victor Wembanyama
+2
2pt putback dunk made
79 - 82
03:05
Victor Wembanyama offensive rebound
77 - 82
03:05
Victor Wembanyama layup missed
77 - 82
03:08
Nicolas Batum offensive rebound
77 - 82
03:08
Kevin Durant blocked the shot
77 - 82
03:08
Guerschon Yabusele dunk missed
77 - 82
03:16
Nicolas Batum defensive rebound
77 - 82
03:16
Stephen Curry 2pt floating jump shot missed
77 - 82
03:32
Guerschon Yabusele
+1
2nd of 2 free throws made
77 - 82
03:32
Guerschon Yabusele 1st of 2 free throws missed
76 - 82
03:32
Anthony Davis
OUT
76 - 82
03:32
Bam Adebayo
IN
76 - 82
03:32
Guerschon Yabusele foul drawn
76 - 82
03:32
LeBron James personal foul; 2 free throws awarded
76 - 82
03:35
Guerschon Yabusele steal
76 - 82
03:35
Stephen Curry turnover; bad pass
76 - 82
03:53
Nando De Colo
+2
2pt driving layup made
76 - 82
04:06
LeBron James turnover; bad pass
74 - 82
04:06
Stephen Curry foul drawn
74 - 82
04:06
Nicolas Batum personal foul
74 - 82
04:15
Victor Wembanyama
OUT
74 - 82
04:15
Mathias Lessort
IN
74 - 82
04:15
LeBron James
OUT
74 - 82
04:15
Jrue Holiday
IN
74 - 82
04:15
Nando De Colo turnover; bad pass
74 - 82
04:17
Nicolas Batum defensive rebound
74 - 82
04:17
Kevin Durant 2pt jump shot missed
74 - 82
04:25
Kevin Durant offensive rebound
74 - 82
04:25
Bilal Coulibaly blocked the shot
74 - 82
04:25
Devin Booker 3pt jump shot missed
74 - 82
04:31
Mathias Lessort turnover; bad pass
74 - 82
04:46
Kevin Durant
OUT
74 - 82
04:46
LeBron James
IN
74 - 82
04:46
Nando De Colo
OUT
74 - 82
04:46
Evan Fournier
IN
74 - 82
04:46
LeBron James turnover; ball handling
74 - 82
05:01
Mathias Lessort made the assist
74 - 82
05:01
Bilal Coulibaly
+2
2pt step back jump shot made
74 - 82
05:24
Jrue Holiday made the assist
72 - 82
05:24
LeBron James
+2
dunk made
72 - 82
05:38
Evan Fournier made the assist
72 - 80
05:38
Mathias Lessort
+2
2pt driving layup made
72 - 80
06:04
Mathias Lessort defensive rebound
70 - 80
06:04
Jrue Holiday 3pt jump shot missed
70 - 80
06:29
Bam Adebayo
OUT
70 - 80
06:29
Anthony Davis
IN
70 - 80
06:29
Guerschon Yabusele
OUT
70 - 80
06:29
Victor Wembanyama
IN
70 - 80
06:29
Nicolas Batum made the assist
70 - 80
06:29
Victor Wembanyama
+1
2nd of 2 free throws made
70 - 80
06:29
Victor Wembanyama 1st of 2 free throws missed
69 - 80
06:29
Victor Wembanyama foul drawn
69 - 80
06:29
Anthony Davis personal foul; 2 free throws awarded
69 - 80
06:38
Nicolas Batum steal
69 - 80
06:38
LeBron James turnover; bad pass
69 - 80
06:50
Devin Booker defensive rebound
69 - 80
06:50
Victor Wembanyama 3pt jump shot from center missed
69 - 80
07:02
LeBron James made the assist
69 - 80
07:02
Jrue Holiday
+3
3pt jump shot made
69 - 80
07:09
Devin Booker offensive rebound
69 - 77
07:09
LeBron James 2pt fadeaway jump shot missed
69 - 77
07:21
Stephen Curry
OUT
69 - 77
07:21
Kevin Durant
IN
69 - 77
07:21
Kevin Durant foul drawn
69 - 77
07:21
Mathias Lessort personal foul
69 - 77
07:39
Mathias Lessort
+1
2nd of 2 free throws made
69 - 77
07:39
Mathias Lessort 1st of 2 free throws missed
68 - 77
07:39
Mathias Lessort foul drawn
68 - 77
07:39
Kevin Durant personal foul; 2 free throws awarded
68 - 77
07:48
Evan Fournier steal
68 - 77
07:48
LeBron James turnover; ball handling
68 - 77
08:11
Devin Booker foul drawn
68 - 77
08:11
Bilal Coulibaly personal foul
68 - 77
08:13
Devin Booker defensive rebound
68 - 77
08:13
Anthony Davis blocked the shot
68 - 77
08:13
Evan Fournier 2pt driving layup missed
68 - 77
08:24
Jrue Holiday made the assist
68 - 77
08:24
Kevin Durant
+3
3pt jump shot from center made
68 - 77
08:53
Mathias Lessort
+2
dunk made
68 - 74
08:57
Mathias Lessort offensive rebound
66 - 74
08:57
Evan Fournier 3pt step back jump shot missed
66 - 74
09:02
Bilal Coulibaly
OUT
66 - 74
09:02
Nando De Colo
IN
66 - 74
09:23
Anthony Davis
+2
dunk made
66 - 74
09:27
Anthony Davis offensive rebound
66 - 72
09:27
Kevin Durant 3pt jump shot missed
66 - 72
09:38
Nicolas Batum
OUT
66 - 72
09:38
Isaia Cordinier
IN
66 - 72
09:38
Kevin Durant foul drawn
66 - 72
09:38
Nando De Colo personal foul
66 - 72
09:44
Devin Booker defensive rebound
66 - 72
09:44
Victor Wembanyama 3pt jump shot from center missed
66 - 72
10:00
 jump ball situation; throw-in
66 - 72
10:00
Start of period
66 - 72
;;;;
run;

proc sort data=CLEANUP out=SORTED; 
  by TIME ;
  where POINTS | TEXT2 in('IN','OUT') ;
run;


data YGROUPS;                                                   %* 4 Groups: Country scores, player scores, dividers, line plot;

  set SORTED end=LASTOBS; 
  where TEXT2 not in('IN','OUT') ;
  output;                                                       %* Group for per-player plot;
  
  PLAYER=COUNTRY; COUNTRYSORT=0; 
  if POINTS >= 1 then output;                             %* Group for per-country plot, top of Y axis (COUNTRYSORT=0);                                                
  
  if LASTOBS;                                                   %* At the end, write out the data needed to display the 2 other groups;
  call missing(of POINTS1-POINTS3, POINTS);                     %* No YAXISTABLE data;
  
  TIME='0:00:00't; POINTSORT=999;                               %* Group used to draw team dividers;
  PLAYER='TEAM USA'   ; COUNTRYSORT=1; output;                  %* COUNTRYSORT as needed and POINTSORT=999 to be at the top of the country players; 
  PLAYER='TEAM FRANCE'; COUNTRYSORT=2; output;

/*   PLAYER='09'x; COUNTRYSORT=4; output;                          %* Group to reserve space for sparkline plot, bottom of Y axis (COUNTRYSORT=4); */
                      
run;

proc sql;                                                       %* Derive total scores used for sorting; 
  create table POINTS_PLOT as 
  select *, sum(POINTS*(POINTS >= 1))  as TOTPOINTS , sum(POINTS1) as TOTPOINTS1
          , sum(POINTS2) as TOTPOINTS2, sum(POINTS3) as TOTPOINTS3
  from YGROUPS 
  group by PLAYER, COUNTRY
  order by COUNTRYSORT, POINTSORT desc, TOTPOINTS desc, COUNTRY, PLAYER;
quit;

proc sql;
  create table LEADTIME as select SCORE, min(TIME) as TIME 
  from SORTED 
  group by SCORE 
  order by calculated TIME ;
data LEAD_PLOT;
  set LEADTIME(keep=TIME SCORE) end=LASTOBS;
  if ^LASTOBS then set LEADTIME(keep=TIME rename=(TIME=NEXTTIME) firstobs=2);
  else NEXTTIME='0:40:00't;
  if _N_=1 then TIME=0;
  DIF=input(resolve('%eval('||SCORE||')'),8.);
run;  
  
proc sql;
  %* Get list of players for each quarter;
  create table QP as
  select unique QUARTER, PLAYER, COUNTRY  
  from CLEANUP 
  where PLAYER ne ' ' and PLAYER not like 'team%'
  order by 1, 2;  
     
 %* Get list of player swap times;
  create table INOUT as
  select QUARTER, PLAYER, TIME, COUNTRY, ifc(TEXT2='IN', 'stop', 'start')as ENTRY length=5
  from CLEANUP
  where TEXT2 in ('IN','OUT') 
  order by 1, 2, 3;
  
data QPTIME; %* Assign max play time to each player;
  set QP;
  TIME=QUARTER*'0:10:00't-'0:10:00't; ENTRY='start'; output;
  TIME=QUARTER*'0:10:00't           ; ENTRY='stop '; output;
run;
 
data QPINOUT; %* Mix max times and actual times ;
   set QPTIME
       INOUT(where=(ENTRY='start')) 
       INOUT(where=(ENTRY='stop ')) ; 
   by QUARTER PLAYER TIME;
run;

data INOUT_PLOT; 
   if 0 then set QPINOUT nobs=NOBS;
   do CURRENT=1 to NOBS; 
     NEXT=CURRENT+1;
     set QPINOUT point=CURRENT;
     if CURRENT ne NOBS then set QPINOUT(keep= QUARTER PLAYER ENTRY rename=(QUARTER=_QUARTER PLAYER=_PLAYER ENTRY=_ENTRY)) point=NEXT;
     if ENTRY='start' then do; %* lastest START possible, skip to next record if available;  
       if QUARTER=_QUARTER & PLAYER=_PLAYER & _ENTRY='start' then continue; 
       else START=TIME; 
     end;  
     if ENTRY='stop' then do; %* earliest STOP, skip next record if also STOP;
       END=TIME;
       output;
       if QUARTER=_QUARTER & PLAYER=_PLAYER & _ENTRY='stop' then CURRENT+1;
     end; 
   end;
   stop;
run;

data ANNO;                                                      %* Create line plots, line plot labels, line plot background;

  length FUNCTION LABEL FILLCOLOR LINECOLOR COMMENT X1SPACE X2SPACE Y1SPACE Y2SPACE $48;
  retain X1SPACE X2SPACE 'datavalue' Y1SPACE Y2SPACE 'datapercent' FUNCTION 'line' WIDTH 105 Y0LINESCORE -11; 
  
  X1=0; Y1=Y0LINESCORE; LINECOLOR='blue';
  do until (LASTOBS1);
    set SORTED(where=(COUNTRY='USA' and POINTS >= 1)) end=LASTOBS1 ;
    P+POINTS;
    X2=ifn(LASTOBS1, '0:40:00't, TIME); 
    Y2=P*.1+Y0LINESCORE; 
    COMMENT='Line Score USA';
    output; 
    X1=X2; Y1=Y2; 
  end;  
  
  X1=0; Y1=Y0LINESCORE; P=0; LINECOLOR='red'; 
  do until (LASTOBS2);
    set SORTED(where=(COUNTRY='FRANCE' and POINTS >= 1)) end=LASTOBS2;
    P+POINTS;
    X2=ifn(LASTOBS2, '0:40:00't, TIME); 
    Y2=P*.1+Y0LINESCORE;
    COMMENT='Line Score France';
    output; 
    X1=X2; Y1=Y2; 
  end;
      
  Y0TRACKER=-18; TRACKERSCALE=0.4;
    
  X1=0; Y1=Y0TRACKER ; LINECOLOR='gray'; X2='0:40:10't; Y2=Y1; LINETHICKNESS=.1; COMMENT='Line 0 Lead Tracker '; output;
        Y1=Y0TRACKER+10*TRACKERSCALE;                   Y2=Y1;                   COMMENT='Line 10 Lead Tracker'; output;
  FUNCTION='text'; TEXTSIZE=8; X1='0:40:30't; Y1=Y0TRACKER                ; LABEL=' 0'; COMMENT='Value 0 Lead Tracker '; output; 
                                              Y1=Y0TRACKER+10*TRACKERSCALE; LABEL='10'; COMMENT='Value 10 Lead Tracker'; output;
  
  Y1=Y0TRACKER;
  FUNCTION='rectangle'; DISPLAY='fill'; WIDTHUNIT='data';
  do until (LASTOBS3);
    set LEAD_PLOT end=LASTOBS3 ;
    X1=TIME; WIDTH=(NEXTTIME-TIME)+0.01; 
    if DIF<0 then do; HEIGHT=-DIF*TRACKERSCALE; ANCHOR='bottomleft'; FILLCOLOR='blue'; end;
    else do;          HEIGHT=+DIF*TRACKERSCALE; ANCHOR='topleft   '; FILLCOLOR='red '; end;
    COMMENT='Bars Lead Tracker';
    if DIF then output; 
  end;
   
  WIDTH='0:42:10't; ANCHOR='Center'; LAYER='back '; DISPLAY='fill'; 
  FUNCTION='rectangle'; X1= '0:20:00't; Y1= -6;         FILLCOLOR='lightyellow'; HEIGHT=11; COMMENT='yellow rectangle'; output;
  FUNCTION='rectangle'; X1= '0:20:00't; Y1=Y0TRACKER+1; FILLCOLOR='cxeeeeff   '; HEIGHT=11; COMMENT='blue rectangle  '; output;
  FILLCOLOR=' ';  
  FUNCTION='text     '; X1= '0:18:00't; Y1= -5; TEXTCOLOR='blue '; LABEL='USA       '; COMMENT='Line plot label'; output;
  FUNCTION='text     '; X1= '0:19:00't; Y1= -9; TEXTCOLOR='red  '; LABEL='France    '; COMMENT='Line plot label'; output;
  FUNCTION='text     '; X1=-'0:03:00't; Y1= -7; TEXTCOLOR='black'; LABEL='SCOREBOARD'; COMMENT='Y axis value   '; output; 
  FUNCTION='text     '; X1=-'0:03:00't; Y1=Y0TRACKER; TEXTCOLOR='black'; LABEL='LEAD TRACKER'; COMMENT='Y axis value '; output;
  
  COMMENT='legend'; FILLCOLOR=' '; LAYER='front'; X1SPACE ='datapercent'; X2SPACE ='datapercent'; Y1SPACE ='datapercent'; Y2SPACE ='datapercent'; 
  FUNCTION='text     '; X1=53  ; Y1=110; TEXTCOLOR='black'; LABEL='S  c  o  r  e  d'; output;
  FUNCTION='text     '; X1=75  ; Y1=110; TEXTCOLOR='black'; LABEL='M  i  s  s  e  d'; output;
  
  FUNCTION='oval     '; X1=67.5; Y1=114; HEIGHT=2; WIDTH=HEIGHT * 13 ; FILLCOLOR='cxfff5f5'; output;
  FUNCTION='text     '; X1=70  ; Y1=114; TEXTCOLOR='black'; LABEL='1'; FILLCOLOR=' '; output;

  FUNCTION='oval     '; X1=74  ; Y1=114; HEIGHT=3.5; WIDTH=HEIGHT *13; FILLCOLOR='cxf2f2ff'; output;
  FUNCTION='text     '; X1=76.5; Y1=114; TEXTCOLOR='black'; LABEL='2'; FILLCOLOR=' '; output;
  
  FUNCTION='oval     '; X1=81  ; Y1=114; HEIGHT=5; WIDTH=HEIGHT * 13 ; FILLCOLOR='cxf3f9f3'; output;
  FUNCTION='text     '; X1=85  ; Y1=114; TEXTCOLOR='black'; LABEL='3'; FILLCOLOR=' '; output;
 
  FUNCTION='line     '; X1=13  ; Y1=114; X2=19; Y2=Y1; LINECOLOR='cxe3e3e3'; LINETHICKNESS=5; LAYER='back'; output;
  FUNCTION='text     '; X1=26  ; Y1=114; LABEL='P l a y e r   o n   c o u r t'; WIDTH=999; output;
   
  COMMENT='IN OUT'; X1SPACE ='datavalue'; X2SPACE ='datavalue'; Y1SPACE ='datavalue'; Y2SPACE ='datavalue';
  Y1=.; Y2=.; ANCHOR='left'; FUNCTION='line';   
  do until (LASTOBS4);
   set INOUT_PLOT end=LASTOBS4;
   X1=START; X2=END; YC1=PLAYER; YC2=PLAYER; 
   if PLAYER ne 'Andrew Albicy' then output; %* not on graph as never attempted a shot;
  end;
run;

data ATTRMAPPOINTS;                                             %* Differentiate shot types using color and size;
  input ID $ VALUE $ FILLCOLOR :$16. MARKERSIZE MARKERTRANSPARENCY LINECOLOR $ LINEPATTERN LINETHICKNESS;
datalines;
point 1 red 12 .6 red 2 1
point 2 blue 18 .6 red 2 1
point 3 green 24 .6 red 2 1
point 0.1 red 12 .9 red 1 0
point 0.2 blue 18 .9 red 1 0
point 0.3 green 24 .9 red 1 0
;
options missing=' ';
ods graphics / reset width=14in height=8.5in noborder ;
    
proc sgplot data=POINTS_PLOT dattrmap=ATTRMAPPOINTS sganno=ANNO nowall; 
  title height=16pt "2024 Paris Olympics Men's Basketball Final - USA vs. France";
  scatter x=TIME y=PLAYER / group=POINTS attrid=point jitter filledoutlinedmarkers markeroutlineattrs=(color=darkgray) markerattrs=(symbol=circlefilled) ; %* Jitter scores for shots occuring at same clock time (e.g., free throws);
  xaxis display=(nolabel noline noticks) values=('00:00:00't to'00:40:00't by '00:02:00't) ; 
  yaxis display=(nolabel noline noticks)  valueattrs=(size=10pt) grid discreteorder=data reverse offsetmax=0.16;
  yaxistable TOTPOINTS  / stat=mean label='PTS' labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside; %* Show total points by categories;
  yaxistable TOTPOINTS3 / stat=mean label='3'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS2 / stat=mean label='2'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS1 / stat=mean label='1'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  keylegend / exclude=(' ' '0.1' '0.2' '0.3') sortorder=ascending noborder location=outside title="POINTS" position=top; 
  refline 'TEAM USA' 'TEAM FRANCE' / axis=y lineattrs=(thickness=6pt);   %* Draw H separator lines between teams;
  refline ('0:00:00't to '0:40:00't by '0:10:00't) / axis=x;             %* Draw V ref lines for start/end of quarters;
run;  
.

 

 

ChrisNZ
Tourmaline | Level 20

Here's the women's game. Very different style from the men's.

France had more 3-pointers, but team USA (barely) won with an avalanche of 1-pointers.

ChrisNZ_0-1724067654427.png

Spoiler
/* Source  https://www.fiba.basketball/en/events/womens-olympic-basketball-tournament-paris-2024/games/122593-FRA-USA#playByPlay */

data PLAYERS;
  infile cards ;
  input COUNTRY $6. / _PLAYERS $200.; 
  do _I=1 to countw(_PLAYERS,',');
    PLAYER=scan(_PLAYERS, _I, ',');
    output;
  end;
  retain FMTNAME '$country';
  drop _:;
cards;
FRANCE
Valeriane Ayayi,Marieme Badiane,Alexia Chery,Marine Fauthoux,Marine Johannes,Leila Lacan,Dominique Malonga,Sarah Michel Boury,Iliana Rupert,Janelle Salaun,Gabby Williams,Romane Bernies 
USA
Napheesa Collier,Kahleah Copper,Chelsea Gray,Brittney Griner,Sabrina Ionescu,Jewell Loyd,Kelsey Plum,Breanna Stewart,Diana Taurasi,Alyssa Thomas,A'ja Wilson,Jackie Young 
run;
proc format cntlin=PLAYERS(rename=(PLAYER=START COUNTRY=LABEL));
run;
data CLEANUP;
  input @1 X :& $80. ;
  if X=:'End of' then QUARTER+1;
  format TIMEIN TIME time. TEXT1 TEXT2 $80.;
  if      index(X, ':')  then TIMEIN=hms(0, input(scan(X,1,':'),2.), input(scan(X,2,':'),2.));
  else if index(X, '+')  then POINTS=input(X,2.);
  else if index(X, '-')  then ;
  else if missing(TEXT1) then TEXT1 =X;
  else                        TEXT2 =X; 
  if index(X, '-') then do;
    SCORE = X;
    TIME  = QUARTER * '0:10:00't - TIMEIN;
    if prxmatch('/\dpt.*missed/',TEXT1) then POINTS=input(compress(TEXT1,,'dk'),1.)/10;
    if TEXT1 not in: (' ', 'team offensive', 'Start of', 'End of', 'Timeout') then PLAYER=catx(' ',scan(TEXT1,1), scan(TEXT1,2));
    if PLAYER='Sarah Michel' then PLAYER='Sarah Michel Boury';   
    COUNTRY=put(PLAYER,$country.);
    COUNTRYSORT= ifn(COUNTRY='USA', 1, 2);                        %* Set sort order for the graph;
    POINTS3    = POINTS*(POINTS=3);                               %* Prepare YAXISTABLE; 
    POINTS2    = POINTS*(POINTS=2);                               %* Prepare YAXISTABLE;
    POINTS1    = POINTS*(POINTS=1);                               %* Prepare YAXISTABLE;
    output;
    call missing(TIME, POINTS, TEXT1, TEXT2);
  end;  
  retain TIMEIN POINTS TEXT1 TEXT2;
cards4;
00:00
End of period
9 - 15
00:02
Napheesa Collier defensive rebound
9 - 15
00:02
Alexia Chery 2pt floating jump shot missed
9 - 15
00:26
Alyssa Thomas made the assist
9 - 15
00:26
Brittney Griner
+2
2pt turnaround jump shot made
9 - 15
00:38
Brittney Griner defensive rebound
9 - 13
00:38
Marine Johannes 3pt pullup jump shot missed
9 - 13
00:52
Kelsey Plum made the assist
9 - 13
00:52
Brittney Griner
+2
2pt turnaround jump shot made
9 - 13
01:13
Marine Johannes
+2
2pt driving layup made
9 - 11
01:30
Alyssa Thomas turnover; bad pass
7 - 11
01:38
Napheesa Collier offensive rebound
7 - 11
01:38
Alyssa Thomas 2nd of 2 free throws missed
7 - 11
01:38
Alyssa Thomas
+1
1st of 2 free throws made
7 - 11
01:38
Brittney Griner
OUT
7 - 10
01:38
A'ja Wilson
IN
7 - 10
01:38
Alyssa Thomas foul drawn
7 - 10
01:38
Iliana Rupert personal foul; 2 free throws awarded
7 - 10
01:44
Alyssa Thomas steal
7 - 10
01:44
Iliana Rupert turnover; ball handling
7 - 10
01:53
Sarah Michel Boury steal
7 - 10
01:53
Napheesa Collier turnover; ball handling
7 - 10
01:55
Napheesa Collier offensive rebound
7 - 10
01:55
Sarah Michel Boury blocked the shot
7 - 10
01:55
Napheesa Collier layup missed
7 - 10
02:00
Napheesa Collier offensive rebound
7 - 10
02:00
Kahleah Copper 3pt jump shot missed
7 - 10
02:08
Marine Johannes
+2
2pt fadeaway jump shot made
7 - 10
02:22
Kahleah Copper
OUT
5 - 10
02:22
Jackie Young
IN
5 - 10
02:22
Kelsey Plum
+1
2nd of 2 free throws made
5 - 10
02:22
Kelsey Plum
+1
1st of 2 free throws made
5 - 9
02:22
Leila Lacan
OUT
5 - 8
02:22
Romane Bernies
IN
5 - 8
02:22
Alexia Chery
OUT
5 - 8
02:22
Marieme Badiane
IN
5 - 8
02:22
Kelsey Plum foul drawn
5 - 8
02:22
Romane Bernies personal foul; 2 free throws awarded
5 - 8
02:30
Alyssa Thomas offensive rebound
5 - 8
02:30
Jackie Young 2pt pullup jump shot missed
5 - 8
02:45
A'ja Wilson defensive rebound
5 - 8
02:45
Marine Johannes 3pt jump shot missed
5 - 8
02:56
Kelsey Plum made the assist
5 - 8
02:56
Napheesa Collier
+1
2nd of 2 free throws made
5 - 8
02:56
Napheesa Collier 1st of 2 free throws missed
5 - 7
02:56
Alyssa Thomas
OUT
5 - 7
02:56
Breanna Stewart
IN
5 - 7
02:56
Sarah Michel Boury
OUT
5 - 7
02:56
Gabby Williams
IN
5 - 7
02:56
Napheesa Collier foul drawn
5 - 7
02:56
Romane Bernies personal foul; 2 free throws awarded
5 - 7
03:03
Breanna Stewart defensive rebound
5 - 7
03:03
Gabby Williams 2pt floating jump shot missed
5 - 7
03:10
Gabby Williams steal
5 - 7
03:10
Breanna Stewart turnover; bad pass
5 - 7
03:23
Jackie Young defensive rebound
5 - 7
03:23
Marine Johannes 2pt floating jump shot missed
5 - 7
03:43
Jackie Young made the assist
5 - 7
03:43
A'ja Wilson
+1
2nd of 2 free throws made
5 - 7
03:43
A'ja Wilson 1st of 2 free throws missed
5 - 6
03:43
A'ja Wilson foul drawn
5 - 6
03:43
Marieme Badiane personal foul; 2 free throws awarded
5 - 6
03:51
Jackie Young defensive rebound
5 - 6
03:51
Gabby Williams 2pt hook shot missed
5 - 6
03:55
Gabby Williams offensive rebound
5 - 6
03:55
Iliana Rupert 3pt pullup jump shot missed
5 - 6
04:10
Gabby Williams offensive rebound
5 - 6
04:10
Breanna Stewart blocked the shot
5 - 6
04:10
Marieme Badiane layup missed
5 - 6
04:15
Marieme Badiane offensive rebound
5 - 6
04:15
Marine Johannes 3pt step back jump shot missed
5 - 6
04:28
Romane Bernies defensive rebound
5 - 6
04:28
A'ja Wilson 2pt jump shot inside the paint missed
5 - 6
04:32
A'ja Wilson offensive rebound
5 - 6
04:32
A'ja Wilson 2pt pullup jump shot missed
5 - 6
04:37
Kelsey Plum
OUT
5 - 6
04:37
Chelsea Gray
IN
5 - 6
04:37
 team offensive rebound
5 - 6
04:39
Marieme Badiane blocked the shot
5 - 6
04:39
Breanna Stewart layup missed
5 - 6
04:43
Napheesa Collier steal
5 - 6
04:43
Iliana Rupert turnover; ball handling
5 - 6
04:49
Iliana Rupert offensive rebound
5 - 6
04:49
Marine Johannes 3pt pullup jump shot missed
5 - 6
04:56
 jump ball situation; throw-in
5 - 6
05:04
Iliana Rupert offensive rebound
5 - 6
05:04
Gabby Williams 3pt pullup jump shot missed
5 - 6
05:19
Breanna Stewart
+1
2nd of 2 free throws made
5 - 6
05:19
Breanna Stewart
+1
1st of 2 free throws made
5 - 5
05:19
Breanna Stewart foul drawn
5 - 4
05:19
Romane Bernies personal foul; 2 free throws awarded
5 - 4
05:36
Iliana Rupert
OUT
5 - 4
05:36
Valeriane Ayayi
IN
5 - 4
05:36
Napheesa Collier foul drawn
5 - 4
05:36
Valeriane Ayayi personal foul
5 - 4
05:41
Napheesa Collier defensive rebound
5 - 4
05:41
Valeriane Ayayi 2pt step back jump shot missed
5 - 4
05:55
Valeriane Ayayi foul drawn
5 - 4
05:55
Chelsea Gray personal foul
5 - 4
06:11
Marieme Badiane steal
5 - 4
06:11
A'ja Wilson turnover; ball handling
5 - 4
06:28
Gabby Williams
+2
2pt driving layup made
5 - 4
06:40
Romane Bernies
OUT
3 - 4
06:40
Janelle Salaun
IN
3 - 4
06:40
Marine Johannes
OUT
3 - 4
06:40
Marine Fauthoux
IN
3 - 4
06:40
Chelsea Gray turnover; bad pass
3 - 4
06:41
A'ja Wilson foul drawn
3 - 4
06:41
Valeriane Ayayi personal foul
3 - 4
06:52
Napheesa Collier defensive rebound
3 - 4
06:52
Marine Fauthoux 2pt floating jump shot missed
3 - 4
06:58
Gabby Williams steal
3 - 4
06:58
Jackie Young turnover; ball handling
3 - 4
07:16
Gabby Williams
+3
3pt pullup jump shot made
3 - 4
07:27
Breanna Stewart turnover; travelling
0 - 4
07:46
A'ja Wilson defensive rebound
0 - 4
07:46
Valeriane Ayayi 3pt pullup jump shot missed
0 - 4
08:08
Chelsea Gray made the assist
0 - 4
08:08
A'ja Wilson
+2
layup made
0 - 4
08:13
Jackie Young steal
0 - 2
08:13
Marine Fauthoux turnover; bad pass
0 - 2
08:30
Marine Fauthoux defensive rebound
0 - 2
08:30
Breanna Stewart layup missed
0 - 2
08:38
Jackie Young defensive rebound
0 - 2
08:38
Gabby Williams 2pt pullup jump shot missed
0 - 2
08:51
Marieme Badiane offensive rebound
0 - 2
08:51
Marieme Badiane 2pt hook shot missed
0 - 2
09:14
Chelsea Gray made the assist
0 - 2
09:14
Breanna Stewart
+2
2pt turnaround jump shot made
0 - 2
09:31
Napheesa Collier defensive rebound
0 - 0
09:31
Marine Fauthoux 3pt pullup jump shot missed
0 - 0
09:46
Gabby Williams defensive rebound
0 - 0
09:46
Breanna Stewart 2pt jump shot missed
0 - 0
10:00
Marieme Badiane jump ball lost
0 - 0
10:00
A'ja Wilson jump ball won
0 - 0
10:00
Start of game
0 - 0


00:00
End of period
25 - 25
00:00
Napheesa Collier
+2
tip in made
25 - 25
00:02
Napheesa Collier offensive rebound
25 - 23
00:02
A'ja Wilson 2pt driving layup missed
25 - 23
00:08
Iliana Rupert
OUT
25 - 23
00:08
Marieme Badiane
IN
25 - 23
00:08
Alexia Chery
OUT
25 - 23
00:08
Valeriane Ayayi
IN
25 - 23
00:08
 team offensive rebound
25 - 23
00:09
A'ja Wilson layup missed
25 - 23
00:12
A'ja Wilson offensive rebound
25 - 23
00:12
A'ja Wilson 2pt driving layup missed
25 - 23
00:32
A'ja Wilson defensive rebound
25 - 23
00:32
A'ja Wilson blocked the shot
25 - 23
00:32
Janelle Salaun 2pt driving layup missed
25 - 23
00:48
Marieme Badiane defensive rebound
25 - 23
00:48
Jackie Young 2pt floating jump shot missed
25 - 23
01:02
Janelle Salaun
+2
2pt pullup jump shot made
25 - 23
01:21
Janelle Salaun foul drawn
23 - 23
01:21
Napheesa Collier personal foul
23 - 23
01:23
Janelle Salaun defensive rebound
23 - 23
01:23
A'ja Wilson 2pt driving layup missed
23 - 23
01:31
A'ja Wilson defensive rebound
23 - 23
01:31
Janelle Salaun 3pt pullup jump shot missed
23 - 23
01:54
Kelsey Plum
OUT
23 - 23
01:54
Chelsea Gray
IN
23 - 23
01:54
 team defensive rebound
23 - 23
01:57
Chelsea Gray 2pt step back jump shot missed
23 - 23
02:24
Jackie Young steal
23 - 23
02:24
Gabby Williams turnover; bad pass
23 - 23
02:36
Chelsea Gray turnover; bad pass
23 - 23
02:45
Timeout
23 - 23
02:47
Marieme Badiane made the assist
23 - 23
02:47
Marine Fauthoux
+3
3pt jump shot made
23 - 23
03:14
A'ja Wilson
+2
2pt fadeaway jump shot made
20 - 23
03:23
A'ja Wilson defensive rebound
20 - 21
03:23
Marine Fauthoux 2pt floating jump shot missed
20 - 21
03:37
Chelsea Gray made the assist
20 - 21
03:37
Breanna Stewart
+1
2nd of 2 free throws made
20 - 21
03:37
Breanna Stewart 1st of 2 free throws missed
20 - 20
03:37
Marine Fauthoux
OUT
20 - 20
03:37
Leila Lacan
IN
20 - 20
03:37
Breanna Stewart foul drawn
20 - 20
03:37
Leila Lacan personal foul; 2 free throws awarded
20 - 20
03:44
Breanna Stewart steal
20 - 20
03:44
Leila Lacan turnover; bad pass
20 - 20
03:57
Janelle Salaun defensive rebound
20 - 20
03:57
Napheesa Collier 2pt turnaround jump shot missed
20 - 20
04:17
Marieme Badiane made the assist
20 - 20
04:17
Valeriane Ayayi
+2
2pt fadeaway jump shot made
20 - 20
04:35
Janelle Salaun defensive rebound
18 - 20
04:35
Breanna Stewart 3pt pullup jump shot missed
18 - 20
04:44
Valeriane Ayayi
OUT
18 - 20
04:44
Alexia Chery
IN
18 - 20
04:44
Timeout
18 - 20
04:44
A'ja Wilson foul drawn
18 - 20
04:44
Marieme Badiane personal foul
18 - 20
04:54
Napheesa Collier defensive rebound
18 - 20
04:54
Gabby Williams 2pt pullup jump shot missed
18 - 20
04:57
Gabby Williams steal
18 - 20
04:57
A'ja Wilson turnover; bad pass
18 - 20
05:02
A'ja Wilson defensive rebound
18 - 20
05:02
Alexia Chery 3pt step back jump shot missed
18 - 20
05:16
Janelle Salaun offensive rebound
18 - 20
05:16
Alexia Chery 3pt jump shot from center missed
18 - 20
05:38
A'ja Wilson
+1
2nd of 2 free throws made
18 - 20
05:38
A'ja Wilson 1st of 2 free throws missed
18 - 19
05:38
Napheesa Collier
OUT
18 - 19
05:38
Alyssa Thomas
IN
18 - 19
05:38
Marieme Badiane
OUT
18 - 19
05:38
Dominique Malonga
IN
18 - 19
05:38
Janelle Salaun
OUT
18 - 19
05:38
Sarah Michel Boury
IN
18 - 19
05:38
A'ja Wilson foul drawn
18 - 19
05:38
Dominique Malonga personal foul; 2 free throws awarded
18 - 19
05:41
A'ja Wilson offensive rebound
18 - 19
05:41
A'ja Wilson 2pt hook shot missed
18 - 19
05:58
Alexia Chery
+2
layup made
18 - 19
06:13
Sarah Michel Boury steal
16 - 19
06:13
Chelsea Gray turnover; bad pass
16 - 19
06:26
Chelsea Gray defensive rebound
16 - 19
06:26
Dominique Malonga layup missed
16 - 19
06:55
Chelsea Gray made the assist
16 - 19
06:55
Jackie Young
+2
2pt jump shot made
16 - 19
06:56
A'ja Wilson
OUT
16 - 17
06:56
Brittney Griner
IN
16 - 17
06:56
Brittney Griner foul drawn
16 - 17
06:56
Alexia Chery personal foul
16 - 17
06:57
Brittney Griner offensive rebound
16 - 17
06:57
Breanna Stewart 2pt driving layup missed
16 - 17
07:08
Dominique Malonga made the assist
16 - 17
07:08
Gabby Williams
+3
3pt pullup jump shot made
16 - 17
07:14
Dominique Malonga offensive rebound
13 - 17
07:14
Leila Lacan 3pt jump shot missed
13 - 17
07:28
Alyssa Thomas turnover; bad pass
13 - 17
07:34
Alyssa Thomas defensive rebound
13 - 17
07:34
Dominique Malonga layup missed
13 - 17
07:40
Sarah Michel Boury steal
13 - 17
07:40
Jackie Young turnover; bad pass
13 - 17
07:45
Breanna Stewart steal
13 - 17
07:45
Gabby Williams turnover; ball handling
13 - 17
08:04
Jackie Young
OUT
13 - 17
08:04
Kahleah Copper
IN
13 - 17
08:04
Chelsea Gray
OUT
13 - 17
08:04
Kelsey Plum
IN
13 - 17
08:04
Gabby Williams
OUT
13 - 17
08:04
Marine Johannes
IN
13 - 17
08:04
Dominique Malonga
OUT
13 - 17
08:04
Iliana Rupert
IN
13 - 17
08:04
Alyssa Thomas turnover; bad pass
13 - 17
08:17
Alexia Chery made the assist
13 - 17
08:17
Leila Lacan
+2
2pt driving layup made
13 - 17
08:24
Marine Johannes defensive rebound
11 - 17
08:24
Kelsey Plum 3pt pullup jump shot missed
11 - 17
08:41
Sarah Michel Boury made the assist
11 - 17
08:41
Alexia Chery
+2
layup made
11 - 17
08:47
Alexia Chery offensive rebound
9 - 17
08:47
Iliana Rupert 3pt jump shot missed
9 - 17
09:03
Sarah Michel Boury offensive rebound
9 - 17
09:03
Marine Johannes 3pt jump shot missed
9 - 17
09:24
Kahleah Copper
+2
2pt driving layup made
9 - 17
09:34
Kahleah Copper defensive rebound
9 - 15
09:34
Alexia Chery 3pt jump shot missed
9 - 15
09:49
Iliana Rupert defensive rebound
9 - 15
09:49
Brittney Griner 2pt hook shot missed
9 - 15
10:00
 jump ball situation; throw-in
9 - 15
10:00
Start of period
9 - 15


00:00
End of period
43 - 45
00:00
Marine Johannes 3pt pullup jump shot missed
43 - 45
00:05
Alyssa Thomas
OUT
43 - 45
00:05
Sabrina Ionescu
IN
43 - 45
00:05
A'ja Wilson
+1
2nd of 2 free throws made
43 - 45
00:05
A'ja Wilson
+1
1st of 2 free throws made
43 - 44
00:05
Jackie Young
OUT
43 - 43
00:05
Kelsey Plum
IN
43 - 43
00:05
A'ja Wilson foul drawn
43 - 43
00:05
Iliana Rupert personal foul; 2 free throws awarded
43 - 43
00:08
A'ja Wilson offensive rebound
43 - 43
00:08
Sabrina Ionescu 2pt driving layup missed
43 - 43
00:25
Marine Johannes
+3
3pt pullup jump shot made
43 - 43
00:34
Marieme Badiane defensive rebound
40 - 43
00:34
Kelsey Plum 2pt turnaround jump shot missed
40 - 43
00:44
Marieme Badiane turnover; ball handling
40 - 43
00:59
Iliana Rupert defensive rebound
40 - 43
00:59
Napheesa Collier 3pt jump shot missed
40 - 43
01:16
Kahleah Copper steal
40 - 43
01:16
Marine Johannes turnover; bad pass
40 - 43
01:36
Sabrina Ionescu made the assist
40 - 43
01:36
Napheesa Collier
+2
layup made
40 - 43
01:43
Kahleah Copper foul drawn
40 - 41
01:43
Iliana Rupert personal foul
40 - 41
01:50
Kahleah Copper defensive rebound
40 - 41
01:50
Marine Johannes 2pt step back jump shot missed
40 - 41
02:05
Kelsey Plum
OUT
40 - 41
02:05
Jackie Young
IN
40 - 41
02:05
Sarah Michel Boury
OUT
40 - 41
02:05
Gabby Williams
IN
40 - 41
02:05
Leila Lacan foul drawn
40 - 41
02:05
Jackie Young personal foul
40 - 41
02:05
Leila Lacan steal
40 - 41
02:05
Jackie Young turnover; ball handling
40 - 41
02:15
Sabrina Ionescu defensive rebound
40 - 41
02:15
A'ja Wilson blocked the shot
40 - 41
02:15
Gabby Williams 2pt pullup jump shot missed
40 - 41
02:31
Sabrina Ionescu made the assist
40 - 41
02:31
Napheesa Collier
+2
layup made
40 - 41
02:45
A'ja Wilson defensive rebound
40 - 39
02:45
Iliana Rupert 3pt jump shot from center missed
40 - 39
02:58
Jackie Young made the assist
40 - 39
02:58
A'ja Wilson
+2
layup made
40 - 39
03:16
Iliana Rupert
OUT
40 - 37
03:16
Valeriane Ayayi
IN
40 - 37
03:16
Jackie Young foul drawn
40 - 37
03:16
Marine Johannes personal foul
40 - 37
03:18
Jackie Young defensive rebound
40 - 37
03:18
A'ja Wilson blocked the shot
40 - 37
03:18
Leila Lacan 2pt driving layup missed
40 - 37
03:36
A'ja Wilson
+1
2nd of 2 free throws made
40 - 37
03:36
A'ja Wilson
+1
1st of 2 free throws made
40 - 36
03:36
A'ja Wilson foul drawn
40 - 35
03:36
Gabby Williams personal foul; 2 free throws awarded
40 - 35
03:37
A'ja Wilson offensive rebound
40 - 35
03:37
Jackie Young 2pt pullup jump shot missed
40 - 35
03:46
Napheesa Collier
OUT
40 - 35
03:46
Breanna Stewart
IN
40 - 35
03:49
Sabrina Ionescu defensive rebound
40 - 35
03:49
A'ja Wilson blocked the shot
40 - 35
03:49
Marieme Badiane 2pt jump shot from center missed
40 - 35
04:06
Marine Johannes defensive rebound
40 - 35
04:06
Breanna Stewart 3pt jump shot missed
40 - 35
04:13
Kahleah Copper defensive rebound
40 - 35
04:13
Leila Lacan 3pt pullup jump shot missed
40 - 35
04:33
Sabrina Ionescu
OUT
40 - 35
04:33
Kelsey Plum
IN
40 - 35
04:33
Kelsey Plum turnover; bad pass
40 - 35
04:46
Valeriane Ayayi made the assist
40 - 35
04:46
Leila Lacan
+2
layup made
40 - 35
04:57
Kahleah Copper made the assist
38 - 35
04:57
Breanna Stewart
+2
2pt driving layup made
38 - 35
05:06
Kahleah Copper offensive rebound
38 - 33
05:06
Jackie Young 3pt jump shot missed
38 - 33
05:19
Leila Lacan
+1
1st free throw made
38 - 33
05:19
Leila Lacan foul drawn
37 - 33
05:19
Kelsey Plum personal foul; 1 free throw awarded
37 - 33
05:19
Leila Lacan
+2
2pt floating jump shot made
37 - 33
05:33
Jackie Young made the assist
35 - 33
05:33
Kelsey Plum
+3
3pt jump shot made
35 - 33
05:39
Kahleah Copper steal
35 - 30
05:39
Valeriane Ayayi turnover; bad pass
35 - 30
05:43
Valeriane Ayayi offensive rebound
35 - 30
05:43
Marine Johannes layup missed
35 - 30
05:54
Marieme Badiane defensive rebound
35 - 30
05:54
Kahleah Copper 3pt jump shot missed
35 - 30
05:59
Leila Lacan
OUT
35 - 30
05:59
Janelle Salaun
IN
35 - 30
05:59
Marine Johannes
OUT
35 - 30
05:59
Marine Fauthoux
IN
35 - 30
05:59
Timeout
35 - 30
05:59
Kahleah Copper foul drawn
35 - 30
05:59
Janelle Salaun personal foul
35 - 30
06:02
A'ja Wilson steal
35 - 30
06:02
Marine Fauthoux turnover; ball handling
35 - 30
06:24
Kelsey Plum made the assist
35 - 30
06:24
A'ja Wilson
+2
2pt driving layup made
35 - 30
06:30
Kelsey Plum defensive rebound
35 - 28
06:30
Valeriane Ayayi 2pt driving layup missed
35 - 28
06:44
Kahleah Copper made the assist
35 - 28
06:44
Kelsey Plum
+3
3pt jump shot made
35 - 28
07:05
Marine Fauthoux turnover; bad pass
35 - 25
07:09
Marine Fauthoux defensive rebound
35 - 25
07:09
Kahleah Copper 2pt driving layup missed
35 - 25
07:23
Marieme Badiane
+1
2nd of 2 free throws made
35 - 25
07:23
Marieme Badiane
+1
1st of 2 free throws made
34 - 25
07:23
Marieme Badiane foul drawn
33 - 25
07:23
A'ja Wilson personal foul; 2 free throws awarded
33 - 25
07:38
Marieme Badiane steal
33 - 25
07:38
Kelsey Plum turnover; bad pass
33 - 25
07:59
Kahleah Copper
OUT
33 - 25
07:59
Napheesa Collier
IN
33 - 25
07:59
Timeout
33 - 25
08:01
Gabby Williams made the assist
33 - 25
08:01
Valeriane Ayayi
+3
3pt jump shot from center made
33 - 25
08:08
Kelsey Plum
OUT
30 - 25
08:08
Chelsea Gray
IN
30 - 25
08:08
Marieme Badiane foul drawn
30 - 25
08:08
Jackie Young personal foul
30 - 25
08:24
 team defensive rebound
30 - 25
08:25
Napheesa Collier layup missed
30 - 25
08:28
Napheesa Collier offensive rebound
30 - 25
08:28
Jackie Young 2pt driving layup missed
30 - 25
08:47
Marine Fauthoux
+3
3pt pullup jump shot made
30 - 25
08:54
Marine Fauthoux offensive rebound
27 - 25
08:54
Gabby Williams 3pt pullup jump shot missed
27 - 25
09:19
Janelle Salaun defensive rebound
27 - 25
09:19
A'ja Wilson layup missed
27 - 25
09:39
Marieme Badiane made the assist
27 - 25
09:39
Valeriane Ayayi
+2
2pt pullup jump shot made
27 - 25
10:00
 jump ball situation; throw-in
25 - 25
10:00
Start of period
25 - 25


00:00
End of game
66 - 67
00:00
Marine Johannes made the assist
66 - 67
00:00
Gabby Williams
+2
2pt floating jump shot made
66 - 67
00:03
Kahleah Copper
+1
2nd of 2 free throws made
64 - 67
00:03
Kahleah Copper
+1
1st of 2 free throws made
64 - 66
00:03
Kahleah Copper foul drawn
64 - 65
00:03
Gabby Williams personal foul; 2 free throws awarded
64 - 65
00:05
Gabby Williams
+3
3pt pullup jump shot made
64 - 65
00:11
Kelsey Plum
+1
2nd of 2 free throws made
61 - 65
00:11
Kelsey Plum
+1
1st of 2 free throws made
61 - 64
00:11
Kelsey Plum foul drawn
61 - 63
00:11
Gabby Williams personal foul; 2 free throws awarded
61 - 63
00:13
Marine Johannes
+1
2nd of 2 free throws made
61 - 63
00:13
Marine Johannes
+1
1st of 2 free throws made
60 - 63
00:13
Marine Johannes foul drawn
59 - 63
00:13
Kahleah Copper personal foul; 2 free throws awarded
59 - 63
00:17
Timeout
59 - 63
00:17
A'ja Wilson
+1
2nd of 2 free throws made
59 - 63
00:17
A'ja Wilson 1st of 2 free throws missed
59 - 62
00:17
A'ja Wilson foul drawn
59 - 62
00:17
Marine Fauthoux personal foul; 2 free throws awarded
59 - 62
00:20
A'ja Wilson defensive rebound
59 - 62
00:20
Breanna Stewart blocked the shot
59 - 62
00:20
Marine Fauthoux 3pt jump shot missed
59 - 62
00:41
A'ja Wilson turnover; travelling
59 - 62
00:54
Marine Johannes
OUT
59 - 62
00:54
Janelle Salaun
IN
59 - 62
00:54
Timeout
59 - 62
00:54
 team defensive rebound
59 - 62
00:57
Gabby Williams 3pt pullup jump shot missed
59 - 62
01:19
Breanna Stewart made the assist
59 - 62
01:19
Kahleah Copper
+2
2pt driving layup made
59 - 62
01:32
Janelle Salaun
OUT
59 - 60
01:32
Marine Johannes
IN
59 - 60
01:32
Timeout
59 - 60
01:33
Gabby Williams
+2
2pt pullup jump shot made
59 - 60
01:45
Valeriane Ayayi defensive rebound
57 - 60
01:45
Kelsey Plum 3pt jump shot missed
57 - 60
01:51
Breanna Stewart offensive rebound
57 - 60
01:51
Kahleah Copper 2pt driving layup missed
57 - 60
02:08
Marine Johannes turnover; ball handling
57 - 60
02:19
Kelsey Plum
+1
2nd of 2 free throws made
57 - 60
02:19
Kelsey Plum
+1
1st of 2 free throws made
57 - 59
02:19
Kelsey Plum foul drawn
57 - 58
02:19
Marine Fauthoux personal foul; 2 free throws awarded
57 - 58
02:34
Gabby Williams
+1
2nd of 2 free throws made
57 - 58
02:34
Gabby Williams
+1
1st of 2 free throws made
56 - 58
02:34
Napheesa Collier
OUT
55 - 58
02:34
Jackie Young
IN
55 - 58
02:34
Gabby Williams foul drawn
55 - 58
02:34
Jackie Young personal foul; 2 free throws awarded
55 - 58
02:34
Marine Johannes
OUT
55 - 58
02:34
Janelle Salaun
IN
55 - 58
02:34
Marieme Badiane
OUT
55 - 58
02:34
Iliana Rupert
IN
55 - 58
02:34
 jump ball situation; throw-in
55 - 58
02:38
Gabby Williams offensive rebound
55 - 58
02:38
Iliana Rupert 3pt jump shot missed
55 - 58
02:47
Gabby Williams offensive rebound
55 - 58
02:47
Marine Fauthoux 3pt pullup jump shot missed
55 - 58
03:11
A'ja Wilson
+2
2pt step back jump shot made
55 - 58
03:24
 team defensive rebound
55 - 56
03:27
Janelle Salaun 3pt jump shot missed
55 - 56
03:45
Janelle Salaun defensive rebound
55 - 56
03:45
Breanna Stewart 2nd of 2 free throws missed
55 - 56
03:45
Breanna Stewart
+1
1st of 2 free throws made
55 - 56
03:45
Timeout
55 - 55
03:45
Breanna Stewart foul drawn
55 - 55
03:45
Valeriane Ayayi personal foul; 2 free throws awarded
55 - 55
04:00
Gabby Williams
+2
2pt driving layup made
55 - 55
04:09
Kelsey Plum made the assist
53 - 55
04:09
Kahleah Copper
+2
layup made
53 - 55
04:16
Breanna Stewart defensive rebound
53 - 53
04:16
Gabby Williams layup missed
53 - 53
04:20
Gabby Williams offensive rebound
53 - 53
04:20
Valeriane Ayayi 3pt jump shot missed
53 - 53
04:35
Kahleah Copper
+1
2nd of 2 free throws made
53 - 53
04:35
Kahleah Copper
+1
1st of 2 free throws made
53 - 52
04:35
Kelsey Plum
OUT
53 - 51
04:35
Sabrina Ionescu
IN
53 - 51
04:35
Kahleah Copper foul drawn
53 - 51
04:35
Marine Fauthoux personal foul; 2 free throws awarded
53 - 51
04:42
Kahleah Copper defensive rebound
53 - 51
04:42
Marine Fauthoux 3pt pullup jump shot missed
53 - 51
04:57
Valeriane Ayayi steal
53 - 51
04:57
Sabrina Ionescu turnover; ball handling
53 - 51
05:04
Marine Fauthoux
+1
2nd of 2 free throws made
53 - 51
05:04
Marine Fauthoux
+1
1st of 2 free throws made
52 - 51
05:04
Marine Fauthoux foul drawn
51 - 51
05:04
Sabrina Ionescu personal foul; 2 free throws awarded
51 - 51
05:15
Iliana Rupert
OUT
51 - 51
05:15
Marieme Badiane
IN
51 - 51
05:15
A'ja Wilson
+1
2nd of 2 free throws made
51 - 51
05:15
A'ja Wilson
+1
1st of 2 free throws made
51 - 50
05:15
Jackie Young
OUT
51 - 49
05:15
Kelsey Plum
IN
51 - 49
05:15
Breanna Stewart
OUT
51 - 49
05:15
Napheesa Collier
IN
51 - 49
05:15
Janelle Salaun
OUT
51 - 49
05:15
Marine Johannes
IN
51 - 49
05:15
A'ja Wilson foul drawn
51 - 49
05:15
Marieme Badiane personal foul; 2 free throws awarded
51 - 49
05:32
Valeriane Ayayi made the assist
51 - 49
05:32
Marieme Badiane
+2
layup made
51 - 49
05:54
 team defensive rebound
49 - 49
05:58
Kelsey Plum 3pt jump shot from center missed
49 - 49
06:18
Valeriane Ayayi
+1
2nd of 2 free throws made
49 - 49
06:18
Gabby Williams made the assist
48 - 49
06:18
Valeriane Ayayi
+1
1st of 2 free throws made
48 - 49
06:18
Valeriane Ayayi foul drawn
47 - 49
06:18
Napheesa Collier personal foul; 2 free throws awarded
47 - 49
06:25
Gabby Williams offensive rebound
47 - 49
06:25
Valeriane Ayayi 3pt jump shot missed
47 - 49
06:40
Sabrina Ionescu made the assist
47 - 49
06:40
A'ja Wilson
+2
2pt pullup jump shot made
47 - 49
06:51
Napheesa Collier foul drawn
47 - 47
06:51
Marine Fauthoux personal foul
47 - 47
07:07
Napheesa Collier defensive rebound
47 - 47
07:07
Valeriane Ayayi 3pt jump shot missed
47 - 47
07:23
Napheesa Collier turnover; travelling
47 - 47
07:46
Kelsey Plum
OUT
47 - 47
07:46
Alyssa Thomas
IN
47 - 47
07:46
Marieme Badiane
+1
2nd of 2 free throws made
47 - 47
07:46
Marieme Badiane
+1
1st of 2 free throws made
46 - 47
07:46
Marieme Badiane foul drawn
45 - 47
07:46
A'ja Wilson personal foul; 2 free throws awarded
45 - 47
08:01
Kahleah Copper
+1
2nd of 2 free throws made
45 - 47
08:01
Kahleah Copper
+1
1st of 2 free throws made
45 - 46
08:01
Napheesa Collier
OUT
45 - 45
08:01
Jackie Young
IN
45 - 45
08:01
A'ja Wilson
OUT
45 - 45
08:01
Breanna Stewart
IN
45 - 45
08:01
Kahleah Copper foul drawn
45 - 45
08:01
Marieme Badiane personal foul; 2 free throws awarded
45 - 45
08:25
Marine Fauthoux made the assist
45 - 45
08:25
Marieme Badiane
+2
2pt jump shot made
45 - 45
08:37
Marine Johannes foul drawn
43 - 45
08:37
Jackie Young personal foul
43 - 45
08:37
 team defensive rebound
43 - 45
08:38
Kahleah Copper 3pt jump shot missed
43 - 45
08:53
Marine Johannes turnover; out of bounds
43 - 45
09:10
Gabby Williams
OUT
43 - 45
09:10
Leila Lacan
IN
43 - 45
09:10
Marine Fauthoux
OUT
43 - 45
09:10
Sarah Michel Boury
IN
43 - 45
09:10
Valeriane Ayayi foul drawn
43 - 45
09:10
Jackie Young personal foul
43 - 45
09:10
 team defensive rebound
43 - 45
09:10
Jackie Young layup missed
43 - 45
09:19
 team turnover; 24 seconds violation
43 - 45
09:21
Marine Johannes 3pt step back jump shot missed
43 - 45
09:44
Marieme Badiane defensive rebound
43 - 45
09:44
Alyssa Thomas 2pt turnaround jump shot missed
43 - 45
10:00
 jump ball situation; throw-in
43 - 45
10:00
Start of period
43 - 45

;;;;
run;

proc sort data=CLEANUP out=SORTED; 
  by TIME ;
  where POINTS | TEXT2 in('IN','OUT') ;
run;


data YGROUPS;                                                   %* 4 Groups: Country scores, player scores, dividers, line plot;

  set SORTED end=LASTOBS; 
  where TEXT2 not in('IN','OUT') ;
  output;                                                       %* Group for per-player plot;
  
  PLAYER=COUNTRY; COUNTRYSORT=0; 
  if POINTS >= 1 then output;                             %* Group for per-country plot, top of Y axis (COUNTRYSORT=0);                                                
  
  if LASTOBS;                                                   %* At the end, write out the data needed to display the 2 other groups;
  call missing(of POINTS1-POINTS3, POINTS);                     %* No YAXISTABLE data;
  
  TIME='0:00:00't; POINTSORT=999;                               %* Group used to draw team dividers;
  PLAYER='TEAM USA'   ; COUNTRYSORT=1; output;                  %* COUNTRYSORT as needed and POINTSORT=999 to be at the top of the country players; 
  PLAYER='TEAM FRANCE'; COUNTRYSORT=2; output;

/*   PLAYER='09'x; COUNTRYSORT=4; output;                          %* Group to reserve space for sparkline plot, bottom of Y axis (COUNTRYSORT=4); */
                      
run;

proc sql;                                                       %* Derive total scores used for sorting; 
  create table POINTS_PLOT as 
  select *, sum(POINTS*(POINTS >= 1))  as TOTPOINTS , sum(POINTS1) as TOTPOINTS1
          , sum(POINTS2) as TOTPOINTS2, sum(POINTS3) as TOTPOINTS3
  from YGROUPS 
  group by PLAYER, COUNTRY
  order by COUNTRYSORT, POINTSORT desc, TOTPOINTS desc, COUNTRY, PLAYER;
quit;

proc sql;
  create table LEADTIME as select SCORE, min(TIME) as TIME 
  from SORTED 
  group by SCORE 
  order by calculated TIME ;
data LEAD_PLOT;
  set LEADTIME(keep=TIME SCORE) end=LASTOBS;
  if ^LASTOBS then set LEADTIME(keep=TIME rename=(TIME=NEXTTIME) firstobs=2);
  else NEXTTIME='0:40:00't;
  if _N_=1 then TIME=0;
  DIF=input(resolve('%eval('||SCORE||')'),8.);
run;  
  
proc sql;
  %* Get list of players for each quarter;
  create table QP as
  select unique QUARTER, PLAYER, COUNTRY  
  from CLEANUP 
  where PLAYER ne ' ' and PLAYER not like 'team%'
  order by 1, 2;  
     
 %* Get list of player swap times;
  create table INOUT as
  select QUARTER, PLAYER, TIME, COUNTRY, ifc(TEXT2='IN', 'stop', 'start')as ENTRY length=5
  from CLEANUP
  where TEXT2 in ('IN','OUT') 
  order by 1, 2, 3;
  
data QPTIME; %* Assign max play time to each player;
  set QP;
  TIME=QUARTER*'0:10:00't-'0:10:00't; ENTRY='start'; output;
  TIME=QUARTER*'0:10:00't           ; ENTRY='stop '; output;
run;
 
data QPINOUT; %* Mix max times and actual times ;
   set QPTIME
       INOUT(where=(ENTRY='start')) 
       INOUT(where=(ENTRY='stop ')) ; 
   by QUARTER PLAYER TIME;
run;

data INOUT_PLOT; 
   if 0 then set QPINOUT nobs=NOBS;
   do CURRENT=1 to NOBS; 
     NEXT=CURRENT+1;
     set QPINOUT point=CURRENT;
     if CURRENT ne NOBS then set QPINOUT(keep= QUARTER PLAYER ENTRY rename=(QUARTER=_QUARTER PLAYER=_PLAYER ENTRY=_ENTRY)) point=NEXT;
     if ENTRY='start' then do; %* lastest START possible, skip to next record if available;  
       if QUARTER=_QUARTER & PLAYER=_PLAYER & _ENTRY='start' then continue; 
       else START=TIME; 
     end;  
     if ENTRY='stop' then do; %* earliest STOP, skip next record if also STOP;
       END=TIME;
       output;
       if QUARTER=_QUARTER & PLAYER=_PLAYER & _ENTRY='stop' then CURRENT+1;
     end; 
   end;
   stop;
run;

data ANNO;                                                      %* Create line plots, line plot labels, line plot background;

  length FUNCTION LABEL FILLCOLOR LINECOLOR COMMENT X1SPACE X2SPACE Y1SPACE Y2SPACE ANCHOR $48;
  retain X1SPACE X2SPACE 'datavalue' Y1SPACE Y2SPACE 'datapercent' FUNCTION 'line' WIDTH 105 Y0LINESCORE -11; 
  
  
  X1=0; Y1=Y0LINESCORE; LINECOLOR='red'; LINETHICKNESS=.1; 
  do until (LASTOBS2);
    set SORTED(where=(COUNTRY='FRANCE' and POINTS >= 1)) end=LASTOBS2;
    P+POINTS;
    X2=ifn(LASTOBS2, '0:40:00't, TIME); 
    Y2=P*.15+Y0LINESCORE;
    COMMENT='Line Score France';
    output; 
    X1=X2; Y1=Y2; 
  end;
  
  X1=0; Y1=Y0LINESCORE; P=0; LINECOLOR='blue';
  do until (LASTOBS1);
    set SORTED(where=(COUNTRY='USA' and POINTS >= 1)) end=LASTOBS1 ;
    P+POINTS;
    X2=ifn(LASTOBS1, '0:40:00't, TIME); 
    Y2=P*.15+Y0LINESCORE; 
    COMMENT='Line Score USA';
    output; 
    X1=X2; Y1=Y2; 
  end;  
  
      
  Y0TRACKER=-17; TRACKERSCALE=0.5;
    
  X1=0; Y1=Y0TRACKER ; LINECOLOR='gray'; X2='0:40:10't; Y2=Y1; COMMENT='Line 0 Lead Tracker '; output;
        Y1=Y0TRACKER+5*TRACKERSCALE;                   Y2=Y1;  COMMENT='Line 5 Lead Tracker'; output;
        Y1=Y0TRACKER-5*TRACKERSCALE;                   Y2=Y1;  COMMENT='Line 5 Lead Tracker'; output;
  ANCHOR='right';
  FUNCTION='text'; TEXTSIZE=8; X1='0:40:45't; Y1=Y0TRACKER               ; LABEL='0'; COMMENT='Value 0 Lead Tracker '; output; 
                                              Y1=Y0TRACKER+5*TRACKERSCALE; LABEL='5'; COMMENT='Value 5 Lead Tracker'; output;
                                              Y1=Y0TRACKER-5*TRACKERSCALE; LABEL='5'; COMMENT='Value 5 Lead Tracker'; output;
  
  Y1=Y0TRACKER;
  FUNCTION='rectangle'; DISPLAY='fill'; WIDTHUNIT='data';
  do until (LASTOBS3);
    set LEAD_PLOT end=LASTOBS3 ;
    X1=TIME; WIDTH=(NEXTTIME-TIME)+0.01; 
    if DIF<0 then do; HEIGHT=-DIF*TRACKERSCALE; ANCHOR='bottomleft'; FILLCOLOR='blue'; end;
    else do;          HEIGHT=+DIF*TRACKERSCALE; ANCHOR='topleft   '; FILLCOLOR='red '; end;
    COMMENT='Bars Lead Tracker';
    if DIF then output; 
  end;
   
  WIDTH='0:42:10't; ANCHOR='Center'; LAYER='back '; DISPLAY='fill'; 
  FUNCTION='rectangle'; X1= '0:20:00't; Y1= -6; FILLCOLOR='lightyellow'; HEIGHT=11; COMMENT='yellow rectangle'; output;
  FUNCTION='rectangle'; X1= '0:20:00't; Y1=-17; FILLCOLOR='cxeeeeff   '; HEIGHT=11; COMMENT='blue rectangle  '; output;
  FILLCOLOR=' ';  
  FUNCTION='text     '; X1= '0:14:00't; Y1= -6; TEXTCOLOR='blue '; LABEL='USA       '; COMMENT='Line plot label'; output;
  FUNCTION='text     '; X1= '0:15:00't; Y1=-10; TEXTCOLOR='red  '; LABEL='France    '; COMMENT='Line plot label'; output;
  FUNCTION='text     '; X1=-'0:03:00't; Y1= -7; TEXTCOLOR='black'; LABEL='SCOREBOARD'; COMMENT='Y axis value   '; output; 
  FUNCTION='text     '; X1=-'0:03:00't; Y1=Y0TRACKER; TEXTCOLOR='black'; LABEL='LEAD TRACKER'; COMMENT='Y axis value '; output;
  
  COMMENT='legend'; FILLCOLOR=' '; LAYER='front'; X1SPACE ='datapercent'; X2SPACE ='datapercent'; Y1SPACE ='datapercent'; Y2SPACE ='datapercent'; 
  FUNCTION='text     '; X1=53  ; Y1=110; TEXTCOLOR='black'; LABEL='S  c  o  r  e  d'; output;
  FUNCTION='text     '; X1=75  ; Y1=110; TEXTCOLOR='black'; LABEL='M  i  s  s  e  d'; output;
  
  FUNCTION='oval     '; X1=67.5; Y1=114; HEIGHT=2; WIDTH=HEIGHT * 13 ; FILLCOLOR='cxfff5f5'; output;
  FUNCTION='text     '; X1=70  ; Y1=114; TEXTCOLOR='black'; LABEL='1'; FILLCOLOR=' '; output;

  FUNCTION='oval     '; X1=74  ; Y1=114; HEIGHT=3.5; WIDTH=HEIGHT *13; FILLCOLOR='cxf2f2ff'; output;
  FUNCTION='text     '; X1=76.5; Y1=114; TEXTCOLOR='black'; LABEL='2'; FILLCOLOR=' '; output;
  
  FUNCTION='oval     '; X1=81  ; Y1=114; HEIGHT=5; WIDTH=HEIGHT * 13 ; FILLCOLOR='cxf3f9f3'; output;
  FUNCTION='text     '; X1=85  ; Y1=114; TEXTCOLOR='black'; LABEL='3'; FILLCOLOR=' '; output;
 
  FUNCTION='line     '; X1=13  ; Y1=114; X2=19; Y2=Y1; LINECOLOR='cxe3e3e3'; LINETHICKNESS=5; LAYER='back'; output;
  FUNCTION='text     '; X1=26  ; Y1=114; LABEL='P l a y e r   o n   c o u r t'; WIDTH=999; output;
   
  COMMENT='IN OUT'; X1SPACE ='datavalue'; X2SPACE ='datavalue'; Y1SPACE ='datavalue'; Y2SPACE ='datavalue';
  Y1=.; Y2=.; ANCHOR='left'; FUNCTION='line';   
  do until (LASTOBS4);
   set INOUT_PLOT end=LASTOBS4;
   X1=START; X2=END; YC1=PLAYER; YC2=PLAYER; 
   if PLAYER not in('Romane Bernies','Sarah Michel Boury','Dominique Malonga') then output; %* not on graph as never attempted a shot;
  end;
run;

data ATTRMAPPOINTS;                                             %* Differentiate shot types using color and size;
  input ID $ VALUE $ FILLCOLOR :$16. MARKERSIZE MARKERTRANSPARENCY LINECOLOR $ LINEPATTERN LINETHICKNESS;
datalines;
point 1 red 12 .6 red 2 1
point 2 blue 18 .6 red 2 1
point 3 green 24 .6 red 2 1
point 0.1 red 12 .9 red 1 0
point 0.2 blue 18 .9 red 1 0
point 0.3 green 24 .9 red 1 0
;
options missing=' ';
ods graphics / reset width=14in height=8.5in noborder ;
    
proc sgplot data=POINTS_PLOT dattrmap=ATTRMAPPOINTS sganno=ANNO nowall; 
  title height=16pt "2024 Paris Olympics Women's Basketball Final - USA vs. France";
  scatter x=TIME y=PLAYER / group=POINTS attrid=point jitter filledoutlinedmarkers markeroutlineattrs=(color=darkgray) markerattrs=(symbol=circlefilled) ; %* Jitter scores for shots occuring at same clock time (e.g., free throws);
  xaxis display=(nolabel noline noticks) values=('00:00:00't to'00:40:00't by '00:02:00't) ; 
  yaxis display=(nolabel noline noticks)  valueattrs=(size=10pt) grid discreteorder=data reverse offsetmax=0.16;
  yaxistable TOTPOINTS  / stat=mean label='PTS' labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside; %* Show total points by categories;
  yaxistable TOTPOINTS3 / stat=mean label='3'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS2 / stat=mean label='2'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  yaxistable TOTPOINTS1 / stat=mean label='1'   labelattrs=(size=8pt weight=bold) valueattrs=(size=10pt) location=outside;
  keylegend / exclude=(' ' '0.1' '0.2' '0.3') sortorder=ascending noborder location=outside title="POINTS" position=top; 
  refline 'TEAM USA' 'TEAM FRANCE' / axis=y lineattrs=(thickness=6pt);   %* Draw H separator lines between teams;
  refline ('0:00:00't to '0:40:00't by '0:10:00't) / axis=x;             %* Draw V ref lines for start/end of quarters;
run;  

 

 

SAS Innovate 2025: Register Now

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!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 12 replies
  • 2435 views
  • 22 likes
  • 4 in conversation