Search code examples
rggplot2plotaxisaxis-labels

How to get axis scale and ticks in this plot using ggplot2?


I am trying to make a classic Von Neumann Morgenstern concave utility function plot using ggplot2, but are having some trouble with the getting the axis ticks in the plot.

This is my complete code. There is no need for a dataset.


library(ggplot2)
library(tidyverse)
library(hrbrthemes)
library(ggforce)


utility2 = function(c, A){
  ret = ((c^(1-A))/(1-A))
}

risk_grid <- 1:20/10

risk_aversion = 1.2

return2 = utility2(risk_grid, risk_aversion)
return2 <- as.data.frame(return2)
return2 <- cbind(return2, risk_grid)


name <- data.frame(c(0.165,1.512, 0.77), c(-6.92, -4.5, -5.17))
points <- data.frame(c(0.188,1.512, 0.8, 0.8), c(-7, -4.6, -5.88, -5.23))
line <- data.frame(c(.188, 1.512),c(-7, -4.6))
line2 <- data.frame(c(0.8, 0.8), c(-5.88, -5.23))
axis_lineA <- data.frame(c(0.188,0.188,0.1), c(-7, -Inf, -7))
axis_lineB <- data.frame(c(1.512, 1.512, 0.1), c(-4.6, -Inf, -4.6))
axis_lineC <- data.frame(c(0.8, 0.8, 0.1), c(-5.23, -Inf, -5.23))
axis_lineD <- data.frame(c(0.8, 0.1), c(-5.88, -5.88))
ticks <- data.frame(c(0.188,1.512), c(-7.5, -7))

colnames(name) <- c("x", "y")
colnames(points) <- c("x", "y")
colnames(line) <- c("x", "y")
colnames(line2) <- c("x", "y")
colnames(axis_lineA) <- c("x", "y")
colnames(axis_lineB) <- c("x", "y")
colnames(axis_lineC) <- c("x", "y")
colnames(axis_lineD) <- c("x", "y")
colnames(ticks) <- c("x", "y")

jpeg(file = "Utility_plot.jpeg", width = 800, height = 800)


P_Utility <- ggplot()+
  geom_line(data = return2, aes(x=risk_grid, y = return2), size = 1, color = "steelblue")+
  #scale_x_continuous(breaks = return2$risk_grid, labels = return2$risk_grid) +
  geom_text(data = name, aes(x=x, y = y), label = c("a", "b", "c"), size = 7, family = "serif")+
  geom_line(data = line, aes(x=x, y = y), size = .5, color = "black")+
  geom_line(data = line2, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
  geom_line(data = axis_lineA, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
  geom_line(data = axis_lineB, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
  geom_line(data = axis_lineC, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
  geom_line(data = axis_lineD, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
  geom_point(data = points, aes(x=x, y = y), size = 4, color = "red")+
  #geom_point(data = ticks, aes(x=x, y = y), size = 4, color = "red")+
  theme_ipsum()+
  #theme(legend.text = element_text(size = 12))+
  #theme(legend.title = element_blank())+
  #theme(axis.ticks=element_line(size = 2))+
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+
  theme(axis.text.x = element_blank()) +
  theme(axis.text.y = element_blank())+
  scale_x_continuous(expand = c(0,0))+
  xlab("c") + ylab("u(c)")+
  theme(axis.title.y = element_text(size = 20, vjust = .5, angle = 0, family = "serif"),
        axis.title.x = element_text(size = 20, hjust = .5, family = "serif"))+
  theme(axis.line = element_line(arrow = arrow(length = unit(3, 'mm'))))+
  theme(text=element_text(family="serif"))
P_Utility

dev.off()

The code might not be optimal but it works so far. I am happy with the plot, but would like to have scale ticks and labels where the dashed lines cross the x- and y-axis.


Solution

  • This could be achieved like so:

    1. Set the breaks for the axis to be unique x and y values from you line dfs
    2. To get the you have to set axis.ticks.x/y = element_line(). Using axis.ticks will not do the job as in theme_ipsum axis.ticks.x/y are both set to element_blank()
    library(ggplot2)
    library(tidyverse)
    library(hrbrthemes)
    library(ggforce)
    
    
    utility2 = function(c, A){
      ret = ((c^(1-A))/(1-A))
    }
    
    risk_grid <- 1:20/10
    
    risk_aversion = 1.2
    
    return2 = utility2(risk_grid, risk_aversion)
    return2 <- as.data.frame(return2)
    return2 <- cbind(return2, risk_grid)
    
    
    name <- data.frame(c(0.165,1.512, 0.77), c(-6.92, -4.5, -5.17))
    points <- data.frame(c(0.188,1.512, 0.8, 0.8), c(-7, -4.6, -5.88, -5.23))
    line <- data.frame(c(.188, 1.512),c(-7, -4.6))
    line2 <- data.frame(c(0.8, 0.8), c(-5.88, -5.23))
    axis_lineA <- data.frame(c(0.188,0.188,0.1), c(-7, -Inf, -7))
    axis_lineB <- data.frame(c(1.512, 1.512, 0.1), c(-4.6, -Inf, -4.6))
    axis_lineC <- data.frame(c(0.8, 0.8, 0.1), c(-5.23, -Inf, -5.23))
    axis_lineD <- data.frame(c(0.8, 0.1), c(-5.88, -5.88))
    ticks <- data.frame(c(0.188,1.512), c(-7.5, -7))
    
    colnames(name) <- c("x", "y")
    colnames(points) <- c("x", "y")
    colnames(line) <- c("x", "y")
    colnames(line2) <- c("x", "y")
    colnames(axis_lineA) <- c("x", "y")
    colnames(axis_lineB) <- c("x", "y")
    colnames(axis_lineC) <- c("x", "y")
    colnames(axis_lineD) <- c("x", "y")
    colnames(ticks) <- c("x", "y")
    
    breaks_x <- unique(c(axis_lineA$x, axis_lineB$x, axis_lineC$x, axis_lineD$x))
    breaks_y <- unique(c(axis_lineA$y, axis_lineB$y, axis_lineC$y, axis_lineD$y))
    ggplot()+
      geom_line(data = return2, aes(x=risk_grid, y = return2), size = 1, color = "steelblue")+
      geom_text(data = name, aes(x=x, y = y), label = c("a", "b", "c"), size = 7, family = "serif")+
      geom_line(data = line, aes(x=x, y = y), size = .5, color = "black")+
      geom_line(data = line2, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
      geom_line(data = axis_lineA, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
      geom_line(data = axis_lineB, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
      geom_line(data = axis_lineC, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
      geom_line(data = axis_lineD, aes(x=x, y = y), size = 1, color = "grey", linetype = "dashed")+
      geom_point(data = points, aes(x=x, y = y), size = 4, color = "red") +
      scale_x_continuous(breaks = breaks_x, expand = c(0,0))+
      scale_y_continuous(breaks = breaks_y, expand = c(0,0))+
      theme_ipsum() +
      theme(panel.grid.major = element_blank(), 
            panel.grid.minor = element_blank(),
            axis.ticks.x = element_line(),
            axis.ticks.y = element_line(),
            axis.ticks.length = unit(5, "pt")) +
      theme(axis.text.x = element_blank()) +
      theme(axis.text.y = element_blank())+
      
      xlab("c") + ylab("u(c)")+
      theme(axis.title.y = element_text(size = 20, vjust = .5, angle = 0, family = "serif"),
            axis.title.x = element_text(size = 20, hjust = .5, family = "serif"))+
      theme(axis.line = element_line(arrow = arrow(length = unit(3, 'mm'))))+
      theme(text=element_text(family="serif"))