Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding Slight curve (or bend) in ggplot geom_path to make path easier to read

Tags:

plot

r

ggplot2

This question is a new question from a previously answered question located here: Plot mean of data within same ggplot

As you can see in the .jpg picture below-- the red line geom_path gets squeezed together making the line harder to interpret. Is there a way to "bend" the curve slightly so that there is less overlap / bunching? Some kind of smoothing or bending around the points so the lines don't overlap? Red-line geom_paths are squeezed together

Here is my syntax:

orbit.plot <- ggplot(orbit.data, aes(x=OpM, y=INVT, colour=Subj, label=Year)) +
  geom_point(size=7, shape=20) + 
  geom_path(size=1.5) +
  ggtitle("Title Orbits") +
  geom_text(data=subset(orbit.data,Year==2006 | Year==2014), aes(label=Year, vjust=1, hjust=1)) +
  theme(panel.background = element_rect(fill = 'white', colour = 'red'),  
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()) +
  geom_vline(xintercept=0, size=1) +
  geom_hline(yintercept=7, size=1) +
  scale_y_continuous(limits = c(7, 15), breaks=seq(7,15,1/2))

Here is dput of the data set:

structure(list(Year = c(2006L, 2006L, 2007L, 2007L, 2008L, 2008L, 
2009L, 2009L, 2010L, 2010L, 2011L, 2011L, 2012L, 2012L, 2013L, 
2013L, 2014L, 2014L), Subj = structure(c(2L, 1L, 2L, 1L, 2L, 
1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L), .Label = c("TMC", 
"HMC"), class = "factor"), OPM = c(0.088, 0.09, 0.095, 0.078, 
0.085, 0.08, -0.023, 0.019, 0.009, 0.043, 0.025, 0.065, 0.0199, 
0.029, 0.06, 0.055, 0.088, 0.065), Invt = c(14.5, 10.3, 13.8, 
10, 13.3, 9.5, 12.3, 8, 13.5, 8, 14.3, 10, 13.2, 8.5, 13.8, 9.5, 
13.8, 9.75)), .Names = c("Year", "Subj", "OpM", "INVT"
), class = "data.frame", row.names = c(NA, -18L))

Thank you kindly.

EDIT: UPDATE: Essentially, the reason for this plot is to show x/y variable "motion" over time. On the X axis-- I'm plotting a ratio (operating margin in this case). On the Y-axis-- I'm showing a cycle measure (inventory turns in this case.) The "bending" of the curve will certainly "bend" the data itself-- but with the X/Y measures I'm using, the data is understood to two (2) decimals-- so "slight" bending of the data would not contaminate the "essence" of what the data is trying to portray.

like image 889
user5509057 Avatar asked Oct 21 '25 03:10

user5509057


1 Answers

You could spline it:

library(ggplot2)
orbit.data <- structure(list(Year = 
   c(2006L, 2006L, 2007L, 2007L, 2008L, 2008L,  2009L, 2009L,  2010L, 2010L, 
     2011L, 2011L, 2012L, 2012L, 2013L,  2013L, 2014L, 2014L), 
   Subj = structure(c(2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 
                      2L, 1L, 2L, 1L, 2L, 1L), 
          .Label = c("TMC", "HMC"), class = "factor"), 
   OPM = c(0.088, 0.09, 0.095, 0.078,  0.085, 0.08, -0.023, 0.019, 0.009, 
           0.043, 0.025, 0.065, 0.0199, 0.029, 0.06, 0.055, 0.088, 0.065), 
   Invt = c(14.5, 10.3, 13.8, 10, 13.3, 9.5, 12.3, 8, 13.5, 8, 14.3, 
            10, 13.2, 8.5, 13.8, 9.5, 13.8, 9.75)), 
   .Names = c("Year", "Subj", "OpM", "INVT"), class = "data.frame", 
   row.names = c(NA, -18L))

lsdf <- list()
plot.new()
for (f in unique(orbit.data$Subj)){
  psdf <- orbit.data[orbit.data$Subj==f,]
  newf <- sprintf("%s - xspline",f)
  lsdf[[f]] <- data.frame(xspline(psdf[,c(3:4)], shape=-0.6, draw=F),Subj=newf)
}
sdf <- do.call(rbind,lsdf)   
orbit.plot <- ggplot(orbit.data, aes(x=OpM, y=INVT, colour=Subj, label=Year)) +
  geom_point(size=5, shape=20) + 
  geom_point(data=orbit.data,size=7, shape=20,color="black") + 
  geom_path(size=1) +
  geom_path(data=sdf,aes(x=x,y=y,label="",color=Subj),size=1) + 
  ggtitle("Title Orbits") +
  geom_text(data=subset(orbit.data,Year==2006 | Year==2014), 
             aes(label=Year, vjust=1, hjust=1)) +
  theme(panel.background = element_rect(fill = 'white', colour = 'red'),  
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()) +
  geom_vline(xintercept=0, size=1) +
  geom_hline(yintercept=7, size=1) +
  scale_y_continuous(limits = c(7, 15), breaks=seq(7,15,1/2))
print(orbit.plot)

Which gives:

enter image description here

There are lots of ways to do this, I doubt this is the best. You can play with the shape parameter in the xspline call to get different amounts of curvature.

like image 182
Mike Wise Avatar answered Oct 27 '25 07:10

Mike Wise