How do I plot a graph of performance against goals?
If you have a revenue goal that you want to achieve for the year, it's very important to visualize how you're performing against your goal each month. Performance against goals The graphs help me see how I'm doing each month, and at a glance I can see how much I've overachieved at the end of the year.

Today we'll be using Visualizing revenue goals and performance monthly with Rand finally create a case that exceeds the goal by 101 TP3T. The full code is at the very bottom of the post, so if you want to check out the picture above right away, just copy and paste it.
1. Create goals and performance data
First, we'll generate goal and performance data for each month. We'll set the goal to be a steady increase each month, and the performance to be a slight increase over the goal, resulting in data that ultimately exceeds the annual goal by 101 TP3T.
# Load the required packages
library(ggplot2) # Load the ggplot2 package to use functions for plotting graphs.
library(scales) # Load the scales package to facilitate axis settings such as number formatting (e.g., adding commas).
Generate # data
set.seed(123) # Use the set.seed() function to fix the seed of the random number so that you get the same random number result every time you run it.
months <- 1:12 # Stores the numbers 1 through 12 in the months variable to represent 12 months.
monthly_goal <- 1000000 # Set the monthly sales goal to 1,000,000 KRW.
goals <- cumsum(rep(monthly_goal, 12)) # Calculates the goal as a cumulative total to represent the yearly goal as a cumulative monthly total.
# achievements as a cumulative total by multiplying by a random number that is 51 TP3T to 151 TP3T above the goal.
achievements <- cumsum(goals * runif(12, min = 1.05, max = 1.15))
Create a # data frame
data <- data.frame(
Month = factor(months, levels = months, labels = month.name), # Create a Month column by converting values from 1 to 12 to month names (e.g. January, February).
Goal = goals, # Store the cumulative goals for each month in the Goal column.
Achievement = achievements # Stores the cumulative achievements by month in the Achievement column.
)
# Calculate the sum of the annual goal and achievements
annual_goal <- tail(goals, 1)[[1]] Set the # annual goal to the last value of goals (i.e., the final value of the cumulative total).
annual_achievement <- tail(achievements, 1)[[1]] # Set the annual achievement to the last value of achievements (i.e., the final value of the cumulative total).
achievement_rate <- (annual_achievement / annual_goal) * 100 # Calculate the achievement rate against the goal, expressed as a percentage.
Code description:
- set.seed(123): to fix a random number and get the same result every time you run it.
- goals: Accumulate the target amount each month to calculate the annual goal.
- achievements: Calculate and accumulate performance with random values that slightly exceed the goal each month.
- data.frame(): Use goals and performance data in the
datawhich is used to build the graph. - annual_goal, annual_achievementCalculates and stores the final cumulative value of annual goals and performance.
- achievement_rate: Calculates the percentage of performance against the goal.
2. Generate an R-graph of performance against goals
Now let's compare our goals and performance by visualizing them in one graph. The goal is the red dotted lineBy, Performance is the blue lineso you can see the difference at a glance.
Generate a graph of performance against the # goal
ggplot(data, aes(x = Month)) +
geom_line(aes(y = Goal), color = "red", linetype = "dashed", size = 1, label = "Goal") +
geom_line(aes(y = Achievement), color = "blue", size = 1, label = "Achievement") +
labs(title = "Goal vs. Achievement graph",
subtitle = paste("Annual Goal:", annual_goal, "circle, Annual Achievement:", round(annual_achievement), "circle\nAchievement Rate:", round(achievement_rate, 2), "%"),
x = "month", y = "cumulative sales (KRW)") +
annotate("text", x = 12, y = max(data$Achievement), label = paste("Yearly overachievement:", round(achievement_rate - 100, 2), "%"), vjust = -1, color = "blue") +
theme_minimal()Code description:
- geom_line(aes(y = Goal)): Plot the target sales for each month as a red dashed line.
- geom_line(aes(y = Achievement)): Plots each month's achievement as a blue solid line, making it easy to compare performance against goals.
- labs(): Shows the graph title, yearly goals and performance, and percentage achieved as a subtitle.
- annotate(): Adds a yearly overachievement percentage to the graph to visually show how much you've overachieved against your goal.
3. Visualize performance vs. goal graphs more elegantly
Once you've created a basic goal-versus-performance R graph, let's visualize it in a more polished way. Let's make our graph more visually rich by adding colors, backgrounds, highlighting elements, and more. This will make our graph more readable and help us convey our message more strongly.
Below is some additional code and explanation to spruce up your graphs.
Generate a graph of performance against the # goal
ggplot(data, aes(x = Month)) +
geom_line(aes(y = Goal, group = 1), color = "red", linetype = "dashed", size = 1.5) + # Show the goal line as a red dashed line, thickness 1.5
geom_line(aes(y = Achievement, group = 1), color = "blue", size = 1.5) + # Show achievement line as a solid blue line, weight 1.5
labs(title = "Performance vs. Goal Graph", # Set graph title
subtitle = paste("Annual Goal:", comma(annual_goal), "KRW, Annual Achievement:", comma(round(annual_achievement)), "KRW\nAchievement Rate:", round(achievement_rate, 2), "%"),
# Set graph subtitle: Show annual goals, performance, and achievement rate
x = "Month", y = "Cumulative Sales (KRW)") + # Set x-axis and y-axis labels
scale_y_continuous(labels = comma, limits = c(0, max(c(annual_goal, annual_achievement)) * 1.2)) + # Display the y-axis in comma format and set the range to 120% of the maximum value
annotate("text", x = 12, y = max(achievements) * 1.1, label = paste("Annual Exceedance:", round(achievement_rate - 100, 2), "%"),
vjust = -1, hjust = 1, color = "blue") + # Display the annual exceedance rate as text and reposition it
theme_minimal() # Apply a minimal theme
Code description:
- geom_line(): Shows goals and performance with red dashed and blue solid lines, respectively.
- labs(): Set the graph title and subtitle. Subheadings include Annual goal, Annual performance, and Percent achieved.
- scale_y_continuous(): displays the y-axis in comma format, and sets the y-axis range to a maximum value of 120% to make the graph look sparse.
- annotate("text", ...): Shows the overachievement text in the upper right corner of the graph, and adjusts its position.
theme_minimal(): Apply a minimalistic theme to make the graph look clean.
Wrapping up: Analyze your performance with a performance vs. goals graph
This graph makes it easy to see how you're doing by comparing your performance against your goals each month. At the end of the year, you can highlight your performance by showing the percentage of goals exceeded, which is a great way to analyze your yearly performance. You too can use this code to visualize your goals and track your performance against them!
#Full Code
# Load required packages
library(ggplot2)
library(scales)
Generate # data
set.seed(123)
months <- 1:12
monthly_goal <- 1000000 # monthly sales goal
goals <- cumsum(rep(monthly_goal, 12)) # goals as a cumulative total
achievements <- cumsum(goals * runif(12, min = 1.05, max = 1.15)) # achievements as a cumulative total
Create a # data frame
data <- data.frame(
Month = factor(months, levels = months, labels = month.name),
Goal = goals,
Achievement = achievements
)
# Calculate the sum of annual goals and achievements
annual_goal <- tail(goals, 1)[[1]]
annual_achievement <- tail(achievements, 1)[[1]]
achievement_rate <- (annual_achievement / annual_goal) * 100
Generate a graph of performance against the # goal
ggplot(data, aes(x = Month)) +
geom_line(aes(y = Goal, group = 1), color = "red", linetype = "dashed", size = 1.5) +
geom_line(aes(y = Achievement, group = 1), color = "blue", size = 1.5) +
labs(title = "Performance vs. Goal Graph",
subtitle = paste("Annual Goal:", comma(annual_goal), "KRW, Annual Achievement:", comma(round(annual_achievement)), "KRW\nAchievement Rate:", round(achievement_rate, 2), "%"),
x = "Month", y = "Cumulative Sales (KRW)") +
scale_y_continuous(labels = comma, limits = c(0, max(c(annual_goal, annual_achievement)) * 1.2)) +
annotate("text", x = 12, y = max(achievements) * 1.1, label = paste("Annual Exceedance:", round(achievement_rate - 100, 2), "%"), vjust = -1, hjust = 1, color = "blue") +
theme_minimal()# Additional description
Scales package: number formats and axis settings made easy!
scales PackagesThe ggplot2and provides a number of functions to make setting the number format and axes of a graph more intuitive. In this section, we'll use the scales packageand how this package can help you present numeric data in a cleaner, more readable way.
1. Why use the Scales package
In general, large numbers in the millions and above are less readable if they're not separated by commas. Especially if your data contains a lot of large numbers, such as sales or financial data, making the numbers appear comma-separated can make the data more intuitive to understand. For example, 1000000rather than 1,000,000would be easier to read, right?
scales package's comma() function can use these Improve number readabilityin your code. If your code has comma()large numbers are automatically separated by commas.
2. Example usage in code
In the example code provided in this post, the scales package to make the axes and labels on the graph more readable.
# Show annual goals and performance in comma-separated format
labs(title = "Performance vs. Goal Graph",
subtitle = paste("Annual Goal:", comma(annual_goal), "KRW, Annual Achievement:", comma(round(annual_achievement)), "KRW\nAchievement Rate:", round(achievement_rate, 2), "%"),
x = "Month", y = "Cumulative Sales (KRW)")In this code, the comma(annual_goal)and comma(round(annual_achievement))to ensure that the annual goal and performance values are output in comma-separated format.
In addition, the number on the y-axis is also comma()to display them in comma-separated format:
scale_y_continuous(labels = comma, limits = c(0, max(c(annual_goal, annual_achievement)) * 1.2))This will output all numbers displayed on the y-axis in comma format, which greatly improves readability.
3. summarize the benefits of the Scales package
- Improve readability: Separates large numbers with commas to make them easier to read.
- Simplify your code:
comma()Easily format large numbers with a single function. - Increase data intuitiveness: Consistently format numbers so you can intuitively understand your data.




