R ggplot2 Error: Continuous value supplied to discrete scale (2 Examples)


In this article, I’ll show how to handle the “Error: Continuous value supplied to discrete scale” in the R programming language.

The tutorial will consist of these topics:

Let’s dig in…


Exemplifying Data, Packages & Default Graph

In the first place, I’ll have to create some example data:

set.seed(834759)                                             # Create example data
data <- data.frame(x = rnorm(100),
                   group = 1:5)
head(data)                                                   # Head of example data


table 1 data frame r error continuous value supplied discrete scale


Table 1 shows the structure of our example data – It is constituted of 100 rows and two columns.

The variable x contains the values we want to display in a boxplot and the variable group defines the corresponding groups of our data.

We also need to install and load the ggplot2 package, in order to use the corresponding functions and commands:

install.packages("ggplot2")                                  # Install & load ggplot2 package


Example 1: Reproduce the ggplot2 Error: Continuous value supplied to discrete scale

In this example, I’ll illustrate how to replicate the error message “Continuous value supplied to discrete scale” when drawing a graphic using the ggplot2 package in R.

Have a look at the following R code:

ggplot(data, aes(x, group = group, fill = group)) +          # Try to modify colors
  geom_boxplot() + 
  scale_fill_manual(values = c("red", "yellow",
                               "blue", "orange",
# Error: Continuous value supplied to discrete scale

As you can see, the RStudio console returns the “Error: Continuous value supplied to discrete scale” after executing the previous R syntax.

The reason for this is that our grouping variable has the numeric data class. However, to properly color the boxes of our groups, the grouping variable needs to be a factor.

So how can we solve this problem? Keep on reading!


Example 2: Fix the ggplot2 Error: Continuous value supplied to discrete scale

The following syntax shows how to avoid the “Error: Continuous value supplied to discrete scale”.

For this, we have to convert our grouping variable to the factor class using the factor() function.

Compare the last part of line one in the following code with the corresponding part in the previous example. As you can see, we are using the factor function to convert our grouping column from numeric to factor.

ggplot(data, aes(x, group = group, fill = factor(group))) +  # Properly adding colors
  geom_boxplot() + 
  scale_fill_manual(values = c("red", "yellow",
                               "blue", "orange",


r graph figure 1 r error continuous value supplied discrete scale


After executing the previous syntax the boxplot illustrated in Figure 1 has been created. As you can see, we have drawn each boxplot of our graphic in a different color.


Video & Further Resources

Do you need more information on the R programming syntax of this tutorial? Then I recommend having a look at the following video of my YouTube channel. I’m explaining the examples of this article in the video:



In addition, you might have a look at the other articles on this website. A selection of posts is shown below:


In summary: You have learned in this article how to deal with the “Error: Continuous value supplied to discrete scale” in the R programming language. In case you have further questions, let me know in the comments. Furthermore, don’t forget to subscribe to my email newsletter for regular updates on the newest articles.


Subscribe to the Statistics Globe Newsletter

Get regular updates on the latest tutorials, offers & news at Statistics Globe.
I hate spam & you may opt out anytime: Privacy Policy.

17 Comments. Leave new

  • Thank you for the great explanation! It immediatly worked with the added factor argument.

  • Hello Jacob. Thank you very much for your good content.
    I want to use discrete legend instead of continuous legend for raster maps. Can you guide me?

    • Hey,

      Thank you for the kind words! Could you share your code and describe your data?


      • Hello, Joachim.
        Yes, Sure. I have a raster data with TIFF format, which is a continuous data. Now I want to create a discrete legend with five classes for this data using ggplot. I tried to do it but failed.
        the code:

        # Load packages
        # Load data
        sample= raster(“sample.tif”)

        reclass <- c(0, 0.2, 1,
        0.2, 0.4, 2,
        0.4, 0.6, 3,
        0.6, 0.7, 4,
        0.8, 1, 5)
        reclass_m <- matrix(reclass,
        ncol = 3,
        byrow = TRUE)

        sample_classified <- reclassify(sample, reclass_m)

        sample_classified[sample_classified == 0] <- NA

        val <- getValues(sample_classified)
        xy <- as.data.frame(xyFromCell(sample_classified,1:ncell(sample_classified)))

        xy <- cbind(xy,val)

        ggplot(na.omit(xy), aes(x=x, y=y, fill=val)) +

        scale_fill_distiller(palette = "Set3", labels= c("Vl", "L", "M", "H","Vh"), name= "Class")+

        annotation_scale(location ="br", width_hint= 0.5, pad_x = unit(1, "cm") )+
        annotation_north_arrow (location="tl", which_north="true", pad_x= unit(0.4, "in"), pad_y= unit(0.3, "in"),
        style= north_arrow_fancy_orienteering)+

        theme(legend.title = element_text(colour="blue", size=10, face="bold"))+

        theme(legend.text = element_text(colour="blue", size=10, face="bold"))+

        theme(legend.background = element_rect(fill="lightblue",size=0.3, linetype="solid", colour ="darkblue"))+

        theme(legend.position="right", legend.box = "horizontal")+

  • Great tutorial, thank you, Joachim! So simple. I am learning R and working through a tutorial importing data from spss, and was running into this issue with a Year variable. My workaround before reading this was to enter the data in manually using factor(), so this simple workaround was great.

    Is there a way of making sure the label doesn’t add the prefix “(factor)…” to the variable on the ggplot graph when doing this though?

    • Hey Joe,

      Thank you so much, glad you like my tutorials!

      Please excuse the delayed response. I was on a long vacation, so unfortunately I wasn’t able to get back to you earlier. Do you still need help with your code?


    • Hi! I have the same question! How can i get rid of the prefix (factor) in the plot legend?

  • Hi Joachim,

    thank you so much for the great tutorial!

    There is one question i have to ask 🙂

    Is the different order (graph and legend) intentionally?

    I am asking because I have a problem with my own data regarding a discrepancy between the colors of the graph and the colors of the legend.

    Thank you so much for your answer!



    • Hi Jonas,

      Thank you very much for the kind feedback, glad you like the tutorial!

      Regarding your question, the ggplot2 package orders horizontal bars from the bottom to the top, that’s why the legend has the opposite order than the bars. You may reverse the order of your legend as shown here.


  • Hi Joachim, thanks a lot for your fast reply! I am sorry to bother you again.

    Something is wrong with my script and I can not find a solution yet. I get either the wrong colors for the graph or for the legend. Attached you can find the code. I would be very thankful if you can go through it quickly.

    The data frame is structured as follows:

    x y value variable
    1 -71.83764 -41.49597 80 getValues(y)
    2 -71.82931 -41.49597 92 getValues(y)
    3 -71.82097 -41.49597 92 getValues(y)
    4 -71.81264 -41.49597 104 getValues(y)
    5 -71.80431 -41.49597 104 getValues(y)
    6 -71.79597 -41.49597 103 getValues(y)

    This line ***names(BIOcolors_1981_2010) <- as.character(BIOcodes_1981_2010) *** seems to be the problem. With that particular line I get wrong colors for the legend, without I get wrong colors for the graph.


    BIO_1981_2010 <- raster("P:/Owncloud/GIS/CHELSA/BIO/Bio_1981_2010.tif")

    transects <- st_read("P:/Owncloud/GIS/Shape_Transekte/transects_MANSO_BOLSON.shp")

    Investigation_Area <- st_read("P:/Owncloud/GIS/Area_of_interest/Investigation_Area/Buffer/Investigation_Area.shp")

    func <- function(x, aggregate = 1) {
    resampleFactor <- aggregate
    inputRaster <- x
    inCols <- ncol(inputRaster)
    inRows <- nrow(inputRaster)
    # Compute numbers of columns and rows in the new raster for mapping
    resampledRaster <- raster(ncol=(inCols / resampleFactor),
    nrow=(inRows / resampleFactor))
    # Match to the extent of the original raster
    extent(resampledRaster) <- extent(inputRaster)
    # Resample data on the new raster
    y <- resample(inputRaster,resampledRaster,method='ngb')

    # Extract cell coordinates
    coords <- xyFromCell(y, seq_len(ncell(y)))
    dat <- stack(as.data.frame(getValues(y)))
    # Add names – 'value' for data, 'variable' to indicate different raster layers
    # in a stack
    names(dat) <- c('value', 'variable')
    dat <- cbind(coords, dat)

    x y value variable
    1 -71.83764 -41.49597 80 getValues(y)
    2 -71.82931 -41.49597 92 getValues(y)
    3 -71.82097 -41.49597 92 getValues(y)
    4 -71.81264 -41.49597 104 getValues(y)
    5 -71.80431 -41.49597 104 getValues(y)
    6 -71.79597 -41.49597 103 getValues(y)

    BIOcodes_1981_2010 <- c(52,53,54,64,65,66,67,68,76,77,78,79,80,81,88,89,90,91,92,93,101,102,103,104,105,106)

    BIOnames_1981_2010 <-c(
    "Upper-Arid – Lower-Supramediterranean",
    "Lower-Semiarid – Lower-Supramediterranean",
    "Upper-Semiarid – Lower-Supramediterranean",

    "Upper-Arid – Upper-Supramediterranean",
    "Lower-Semiarid – Upper-Supramediterranean",
    "Upper-Semiarid – Upper-Supramediterranean",
    "Lower-Dry – Upper-Supramediterranean",
    "Upper-Dry – Upper-Supramediterranean",

    "Upper-Arid – Lower-Oromediterranean",
    "Lower-Semiarid – Lower-Oromediterranean",
    "Upper-Semiarid – Lower-Oromediterranean",
    "Lower-Dry – Lower-Oromediterranean",
    "Upper-Dry – Lower-Oromediterranean",
    "Lower-Subhumid – Lower-Oromediterranean",

    "Upper-Arid – Upper-Oromediterranean",
    "Lower-Semiarid – Upper-Oromediterranean",
    "Upper-Semiarid – Upper-Oromediterranean",
    "Lower-Dry – Upper-Oromediterranean",
    "Upper-Dry – Upper-Oromediterranean",
    "Lower-Subhumid – Upper-Oromediterranean",

    "Lower-Semiarid – Lower-Crioromediterranean",
    "Upper-Semiarid – Lower-Crioromediterranean",
    "Lower-Dry – Lower-Crioromediterranean",
    "Upper-Dry – Lower-Crioromediterranean",
    "Lower-Subhumid – Lower-Crioromediterranean",
    "Upper-Subhumid – Lower-Crioromediterranean"

    BIOcolors_1981_2010 <- c(





    names(BIOcolors_1981_2010) <- as.character(BIOcodes_1981_2010)

    ggplot(data = BIO_1981_2010) +
    geom_raster(aes(x = x, y = y, fill = as.character(value))) +
    scale_fill_manual(name = "Bioclimates",
    values = BIOcolors_1981_2010,
    labels = BIOnames_1981_2010[-100],
    na.translate = FALSE) +
    geom_sf(data = transects, size = 1, linetype = "dashed") +
    coord_sf(expand = F) +
    theme(axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    panel.border = element_rect(colour = "black", fill = NA, size = 1),
    panel.background = element_rect(fill = "white", color = "black"))

    • Hi Jonas,

      No problem at all, this is what the comment section is made for!

      Is there a specific reason why you are specifying the name, labels, and na.translate arguments within the scale_fill_manual function?

      I have just created some example code that changes the colors of a barchart and the corresponding legend. All I had to do was to assign a vector of colors to the values argument.

      Have a look at the example code below:

      data <- data.frame(x = LETTERS[1:5],    # Create example data
                         y = c(4, 2, 7, 3, 5))
      data                                    # Print example data
      #   x y
      # 1 A 4
      # 2 B 2
      # 3 C 7
      # 4 D 3
      # 5 E 5
      library("ggplot2")                      # Load ggplot2 package
      your_colors <- c("#353436",             # Specify colors
      ggplot(data, aes(x, y, fill = x)) +     # Barplot with manual colors
        geom_bar(stat = "identity") +
        scale_fill_manual(values = your_colors)

      barplot ggplot2

      I have developed this code based on this tutorial, so maybe you could also have a look at the other tutorial to learn more on how to manually specify colors of a ggplot2 barplot.


  • Hi Joachim,

    Thanks again for the fast answer!

    I think, I specified the name, labels, etc. because I want to use my own colour sheme. Not sure if this is the right way to do it.

    However, I just used fill = factor(value) instead of fill = as.character(value) and it seems to work now.

    Best regards and many thanks for your help,



Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.