6

I want to plot a simple bar chart in plotly R and by default it will skip the NA observations. In ggplot we have a parameter to disable the default NA removal, or we can customize the axis limits. However I cannot get it done in plotly.

dt_plot <- data.frame(categories = letters[1:10], values = c(rep(NA_integer_, 3), 1:5, rep(NA_integer_, 2)))
plot_ly(data = dt_plot) %>%
  add_bars(x = ~categories, y = ~values)

I want to show the x axis as the consistent letters 1:10, because I'm actually including this plot in a shiny app with dynamic data selection. Some data have values in all x values, some only have values in a subset. I want to keep the plot to be consistent and always show complete x values.

There is a similar question here, but the answer doesn't apply to my case, because I'm using a category type x axis:

https://plot.ly/r/reference/#layout-xaxis

If the axis type is "category", it should be numbers, using the scale where each category is assigned a serial number from zero in the order it appears.

I tried different range combinations but it didn't work. plotly seemed always remove NA observations first.

There is a related issue where Carson Sievert suggested a hack, but it didn't really work me either.

# this do show all the x values but the plot is wrong
layout(xaxis = list(type = "category", tickvals = 1:10/10, ticktext = letters[1:10], range = c(0, 1)))

By inspecting the plot object, it looks like the NA data is removed before constructing the plot:

{
  "visdat": {
    "7abc7354f619": ["function () ", "plotlyVisDat"]
  },
  "cur_data": "7abc7354f619",
  "attrs": {
    "7abc7354f619": {
      "alpha_stroke": 1,
      "sizes": [10, 100],
      "spans": [1, 20],
      "x": {},
      "y": {},
      "type": "bar",
      "inherit": true
    }
  },
  "layout": {
    "margin": {
      "b": 40,
      "l": 60,
      "t": 25,
      "r": 10
    },
    "xaxis": {
      "domain": [0, 1],
      "automargin": true,
      "range": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9],
      "title": "categories",
      "type": "category",
      "categoryorder": "array",
      "categoryarray": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
    },
    "yaxis": {
      "domain": [0, 1],
      "automargin": true,
      "title": "values"
    },
    "hovermode": "closest",
    "showlegend": false
  },
  "source": "A",
  "config": {
    "showSendToCloud": false
  },
  "data": [
    {
      "x": ["d", "e", "f", "g", "h"],
      "y": [1, 2, 3, 4, 5],
      "type": "bar",
      "marker": {
        "color": "rgba(31,119,180,1)",
        "line": {
          "color": "rgba(31,119,180,1)"
        }
      },
      "error_y": {
        "color": "rgba(31,119,180,1)"
      },
      "error_x": {
        "color": "rgba(31,119,180,1)"
      },
      "xaxis": "x",
      "yaxis": "y",
      "frame": null
    }
  ],
...

1 Answer 1

5

There is info in reference: https://plotly.com/r/reference/layout/xaxis/#layout-xaxis-range, but not so obvious.

But first of all: categorical variable needs to be factor.

Second you need to specify range from 0 to number of levels -1. To better looking use +-0.5 on ends

dt_plot <- data.frame(categories = letters[1:10], values = c(rep(NA_integer_, 3), 1:5, rep(NA_integer_, 2)))
dt_plot$categories <- as.factor(dt_plot$categories)
plot_ly(data = dt_plot) %>%
  add_bars(x = ~categories, y = ~values)%>% 
  layout(xaxis = list(range = list(-0.5, 9.5)))
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.