project.point

project.point is a helper function. In many graphics in Schoon, Melamed, and Breiger (2024) and those generated by rio.plot, the points for predictor variables are projected to the line running through the origin (0,0) and the fitted values from the regression model. Given the point coordinates for the point you want to project onto that line, and the coordinates for the fitted values, project.point computes the point at which your point is projected onto the line - at a 90 degree angle - running through the origin (0,0) and the fitted values. You can then connect those points in graphs using a line segment. See below for an example.

We begin this example by defining a rio.plot with all the predictor variables suppressed. We will add them, using project.point in the process.

library(rioplot)
data(Kenworthy99)
m1 <- lm(scale(dv) ~ scale(gdp) + scale(pov) + scale(tran) -1,data=Kenworthy99)
# Create plot with just the fitted values
rp1 <- rio.plot(m1,include.int="no",exclude.vars=1:3,col.names = "PRED.POV") 
rp1$gg.obj

In order to add the predictor or independent variables to the plot, we need their coordinates. Below we define a second rio.plot object, and then build a data.frame with the coordinates for the variables (or columns). We then print the data.frame to show the coordinates. Finally, we use those coordinates to add the points to the rio.plot$gg.obj. Next, we will use project.point to connect the points for the variables to the rio.plot line.

# Create object with coordinates for all variables
rp2 <- rio.plot(m1,include.int="no")
# pull out those coordinates and put them into a data.frame
pdat <- data.frame(vars=c("gdp","prepov","tran","yhat"),
                   x=rp2$col.dimensions[,1],y=rp2$col.dimensions[,2])
pdat
##     vars          x          y
## 1    gdp -0.4978672  0.3622994
## 2 prepov  0.6609921  0.1332760
## 3   tran  0.1532521 -0.8283859
## 4   yhat  0.5401217  0.4058982
rp1$gg.obj + 
  scale_x_continuous(limits=c(-.6,1.15)) + 
  scale_y_continuous(limits=c(-.85,.5)) +
  geom_point(data=pdat[1:3,],aes(x=x,y=y)) +
  geom_text(data=pdat[1:3,],aes(x=x,y=y,label=vars),nudge_y=.1,nudge_x=.1)

project.point computes the point at which your point is projected onto the line - at a 90 degree angle - running through the origin (0,0) and the fitted values. In the first example below, project.point computes the point at which gdp is projected onto the line. We then define three objects - one for each predictor variable. We then compile the new points with the coordinates for the predictors, along with a grouping variable that defines the line segments. Finally, we use these new data to connect the points for the predctors to the rio.plot line.

project.point(pdat[1,2:3],pdat[4,2:3]) # gdp
## $newpoint
## $newpoint$y
## [1] -0.1441779
## 
## $newpoint$y
## [1] -0.1083488
# points for each predictor
a1<-project.point(pdat[1,2:3],pdat[4,2:3])$newpoint # gdp
a2<-project.point(pdat[2,2:3],pdat[4,2:3])$newpoint # prepov
a3<-project.point(pdat[3,2:3],pdat[4,2:3])$newpoint # tran
# compile those points into a data.frame
p1 <- data.frame(x=as.numeric(a1[1]),y=as.numeric(a1[2]),gr=1) 
# output from project.point
p2 <- data.frame(pdat[1,2:3],gr=1) # gdp's coordinates
p3 <- data.frame(x=as.numeric(a2[1]),y=as.numeric(a2[2]),gr=2) 
# output from project.point
p4 <- data.frame(pdat[2,2:3],gr=2) # prepov's coordinates
p5 <- data.frame(x=as.numeric(a3[1]),y=as.numeric(a3[2]),gr=3) 
# output from project.point
p6 <- data.frame(pdat[3,2:3],gr=3) # tran's coordinates
pdat2 <- rbind(p1,p2,p3,p4,p5,p6)
pdat2
##             x          y gr
## 1  -0.1441779 -0.1083488  1
## 2  -0.4978672  0.3622994  1
## 3   0.4864365  0.3655541  2
## 21  0.6609921  0.1332760  2
## 11 -0.2999054 -0.2253771  3
## 31  0.1532521 -0.8283859  3
# the groups denote the two points that define the beginning and 
# end of the line segments.  
rp1$gg.obj + 
  scale_x_continuous(limits=c(-.6,1.15)) + 
  scale_y_continuous(limits=c(-.85,.5)) +
  geom_line(data=pdat2,aes(x=x,y=y,group=gr),color="grey65") + 
  # line segments from project.point
  geom_point(data=pdat[1:3,],aes(x=x,y=y)) +
  geom_text(data=pdat[1:3,],aes(x=x,y=y,label=vars),nudge_y=.1,nudge_x=.1)