Plot.new Has Not Been Called Yet

5 min read

The error message plot.Because of that, understanding why this happens requires a grasp of how R’s base graphics system manages the "current device" and the plotting region. It typically appears when you attempt to add elements to a plot—such as points, lines, text, or a legend—before a plotting window or device has actually been initialized. Here's the thing — new has not been called yet is one of the most common stumbling blocks for R users, ranging from absolute beginners to seasoned data scientists. This article breaks down the causes, the mechanics behind the scenes, and the practical solutions to resolve and prevent this frustrating error.

Understanding the Base Graphics Pipeline

To fix the error, you first need to understand the architecture of R’s base graphics system. Unlike ggplot2, which builds a complete plot object before rendering, base R graphics operate on a stateful, imperative pipeline. This means functions execute immediately and modify the current active graphics device.

The pipeline generally follows this sequence:

  1. Device Initialization: A graphics device is opened (e.Region Setup: plot., windows(), quartz(), x11(), pdf(), png(), or automatically via RStudio’s plot pane). Consider this: 2. new() sets up the coordinate system, margins, and the plotting region. High-Level Plot Call: A function like plot(), hist(), boxplot(), or barplot() is called. new()internally. In practice, 4. 3. This triggersplot.g.Low-Level Annotations: Functions like points(), lines(), text(), abline(), legend(), axis(), and title() add layers to the existing region.

Not obvious, but once you see it — you'll see it everywhere.

The error plot.new has not been called yet fires explicitly at step 4 if step 2 (or a manual plot.new() call) has not successfully completed.

Common Scenarios That Trigger the Error

While the root cause is always a missing active plot region, the specific coding patterns that lead there vary. Here are the most frequent culprits:

1. Calling Low-Level Functions First

This is the classic beginner mistake. You open a script and immediately type abline(h=0) or text(1, 1, "Label") before calling plot().

# ❌ ERROR: No plot exists yet
abline(h = 0, col = "red")
text(0.5, 0.5, "Center")

Fix: Always start with a high-level plotting function.

# ✅ CORRECT
plot(1, 1, type = "n", xlim = c(0, 1), ylim = c(0, 1)) # Sets up the canvas
abline(h = 0, col = "red")
text(0.5, 0.5, "Center")

2. The "Empty Plot" Trap (type = "n")

Users often create an empty canvas using plot(x, y, type = "n") intending to build a custom plot layer by layer. If the plot() call fails silently or is commented out during debugging, the subsequent points() or lines() calls will throw the error.

3. Device Closure or Switching

This is the most insidious cause for intermediate users. If you explicitly close the graphics device using dev.off() or switch devices using dev.set(), the current device becomes null (or switches to a device that hasn't had plot.new called on it yet).

plot(1:10)
dev.off() # Closes the active device
lines(1:10, 10:1) # ❌ ERROR: The device is gone; no plot.new active

In RStudio, this often happens when the "Plots" pane is cleared manually (the broom icon) or when a script runs graphics.off() at the top to clean the slate, but the subsequent code assumes a device is still open from a previous run.

4. Errors Inside High-Level Plot Calls

If your plot() call throws an error before it finishes setting up the region (e.g., invalid data types, missing values causing limits calculation to fail), plot.new() might have been called internally, but the environment state might be left in a limbo, or the error halts execution before you reach your annotation code. On the flip side, strictly speaking, if plot() errors out, you usually see that error first. The "plot.new not called" error usually implies the high-level function didn't run at all or ran on a different device Worth keeping that in mind..

5. Non-Interactive Scripts and Rscript

When running R scripts via command line (Rscript my_script.R), no interactive graphics device opens by default. If your script contains plot() followed by lines(), it works because plot() opens a default device (usually a PDF file named Rplots.pdf in the working directory). That said, if you only have low-level commands, or if you manually open a device like pdf("out.pdf") but forget to call plot() before lines(), you hit this error No workaround needed..

Deep Dive: What plot.new() Actually Does

The function plot.new() is the gatekeeper of the plotting region. When invoked (usually implicitly by plot(), hist(), etc The details matter here. And it works..

  1. Checks/Opens Device: If no device is open, it attempts to open the default one (screen device on interactive, PDF on batch).
  2. Resets Graphics Parameters: It resets most par() settings to defaults unless par("new") = TRUE.
  3. Calculates Plot Region: It computes usr (user coordinates), plt (plot region as fraction of figure), and fig (figure region as fraction of device) based on margins (mar/mai) and axis requirements.
  4. Advances Frame: In multi-figure layouts (mfrow, mfcol), it advances to the next figure region.

If you call plot.You must then manually define the coordinate system using plot.Still, window(xlim, ylim) before adding axes or data. On the flip side, new() manually, you get a completely blank slate with default margins. This is rarely done manually unless building highly custom grid-based graphics.

Practical Solutions and Workflows

Solution A: The Defensive Coding Pattern

Always structure your base R plotting code in a strict order: Device -> High-Level Plot -> Low-Level Annotations -> Close Device (if file).

# 1. Setup Device (Explicit is better for scripts)
pdf("my_plot.pdf", width = 7, height = 5)

# 2. High-Level Plot (Triggers plot.new)
plot(mtcars$wt, mtcars$mpg,
     main = "MPG vs Weight",
     xlab = "Weight (1000 lbs)",
     ylab = "Miles Per Gallon",
     pch = 19, col = "steelblue")

# 3. Low-Level Annotations (Safe to call now)
abline(lm(mpg ~ wt, data = mtcars), col = "red", lwd = 2)
legend("topright", legend = c("Data", "Linear Fit"), 
       col = c("steelblue", "red"), pch = c(19, NA), lty = c(NA, 1))

# 4. Close Device
dev.off()

Solution B: Checking for an Active Device

If you are writing a function that adds elements to a plot (like a custom add_confidence_interval() function), you should defensively check if a plot exists That's the part that actually makes a difference..

add_my_line <- function(slope, intercept) {
  # Check if a graphics device is active AND a plot region exists
  if (dev.cur() == 1) { 
    # dev.cur() returns 1 (null device) if no
Out Now

Latest Additions

Readers Went Here

Still Curious?

Thank you for reading about Plot.new Has Not Been Called Yet. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home