Skip to content

Instantly share code, notes, and snippets.

@echasnovski
Created February 22, 2019 09:13
Show Gist options
  • Save echasnovski/a8760e5b9cc96e78b558269bf99f934d to your computer and use it in GitHub Desktop.
Save echasnovski/a8760e5b9cc96e78b558269bf99f934d to your computer and use it in GitHub Desktop.
Updated version of https://gist.github.com/andrewheiss/29057150cc6466f0f4d9c39236c19aa6 . It has three main changes: 1) Model variables are swapped for convenience, 2) Adding tangent line wrapped into function with extra functionality, 3) Plot is done for a new model with swapped variables and then coordinates are flipped.
library(tidyverse)
library(Deriv)
library(scales)
# Here we change variable names: x is "Work effort", y is "Wage per hour"
response_curve <- function(x) 60*x^4 + 5*x + 6
response_deriv <- Deriv(response_curve)
# Function for tangent line becomes very simple. For more information, see:
# https://en.wikipedia.org/wiki/Tangent#More_rigorous_description
response_tangent <- function(x, effort) {
response_curve(effort) + response_deriv(effort) * (x - effort)
}
add_tangent <- function(effort, x_width = 0.25, y_width = 15) {
# Compute the x limits which will be used to plot tangent line. It is computed
# as minimum of simmetrical intervals (with `effort` in the middle) which
# give the input plotting width along x and y axis.
half_plot_width_x <- 0.5 * x_width
# This is computed from the following equation:
# `abs(g(effort + d) - g(effort)) = 0.5 * y_width` (here `g` is
# `response_tangent` and `d` is what we're looking)
half_plot_width_y <- 0.5 * y_width / abs(response_deriv(effort))
half_plot_width <- min(half_plot_width_x, half_plot_width_y)
x_lim <- effort + half_plot_width * c(-1, 1)
# Return a `stat_function()` output wrapped in the list so that we can use it
# as "normal" 'ggplot2' layer function
list(
stat_function(
fun = response_tangent, args = list(effort = effort),
color = "darkred", size = 1, xlim = x_lim
)
)
}
response_curve_points <- tibble(x = seq(0, 1, 0.01)) %>%
mutate(y = response_curve(x))
ggplot(data = tibble(x = c(0, 1)), aes(x = x)) +
# Add polynomial curve
geom_line(data = response_curve_points, aes(x = x, y = y),
size = 0.5, color = "grey30") +
# Add tangent lines
add_tangent(effort = 0.5) +
add_tangent(effort = 0.25) +
add_tangent(effort = 0.8) +
# Add dots at tangent points
annotate(geom = "point", x = 0.5, y = response_curve(0.5)) +
annotate(geom = "point", x = 0.25, y = response_curve(0.25)) +
annotate(geom = "point", x = 0.8, y = response_curve(0.8)) +
# Labels and scale stuff
labs(x = "Work effort from employee", y = "Wage per hour") +
scale_x_continuous(labels = percent_format(accuracy = 1), expand = c(0, 0)) +
scale_y_continuous(labels = dollar, expand = c(0, 0)) +
# The main trick: plot of inverse function is made by straightforward
# coordinate flipping
coord_flip(xlim = c(0, 1), ylim = c(0, 50)) +
theme_minimal()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment