How to Clean up Donut Chart? - r

I need to clean up the donut chart below, by getting rid of the double data labels, and rounding the percents. I would like the final graph to have one data label with a % and no decimal place. Anyone know how I accomplish this?
df <- data.frame(
group = cc("DoDEA", "ERAC", "Evaluator", "Project Director", "Project Staff - Finance",
"Project Staff - Other"),
value = c(3,7, 10, 43, 12, 25))
head(df)
ggdonutchart(df, label = "group")
ggdonutchart(df, "value",
color = "white",fill = "group",
palette = c("yellow", "steelblue3","slategray3", "dodgerblue4",
"yellowgreen", "sienna2") ) +
labs(fill = "") + #THIS DELETS GROUP FROM LEGEND
geom_text(aes(label = scales::percent(value/sum(value))),
position = position_stack(vjust = 0.5))`

You can add a new column to your dataframe to create the labels. This code will put the % on a new line. Then add these labels in the ggdonutchart function using the label argument. The function then has additional arguments to adjust the label position.
df <- data.frame(
group = c("DoDEA", "ERAC", "Evaluator", "Project Director", "Project Staff - Finance",
"Project Staff - Other"),
value = c(3,7, 10, 43, 12, 25))
# create labels
df$label <- paste(df$group,
scales::percent(df$value/sum(df$value), accuracy = 1), sep = "\n")
ggdonutchart(df, "value",
label = "label", # add labels
color = "white",fill = "group",
palette = c("yellow", "steelblue3","slategray3", "dodgerblue4",
"yellowgreen", "sienna2")) +
theme(legend.position = "none")

Related

How to make a functioning pie chart, R

I am trying to make a pie chart in R that displays the percent of each section as a label. I was following this tutorial, (https://www.geeksforgeeks.org/r-pie-charts/). I modified it a little bit to make it similar to the data frame I am actually working with. When I try and run my code I get the error, "Error in edges * dx[i] : non-numeric argument to binary operator". It seems the error is coming from legend(), when I comment it out I get no error. Where am I going wrong?
Thanks in advance for any help.
df <- data.frame( geeks = c(23, 56, 20, 63),
labels = c("Mumbai", "Pune", "Chennai", "Bangalore"))
df <- mutate(df, percent = round(df$geeks/sum(df$geeks)*100, 1))
df_pie <- pie(df$geeks,
round(df$percent,1),
main = "City pie chart",
col = rainbow(length(df$geeks)),
legend("topright", c(df$labels),
cex = 0.5, fill = rainbow(length(df$geeks))))
legend is a stand-alone function, not an argument to pie
pie(df$geeks,
round(df$percent,1),
main = "City pie chart",
col = rainbow(length(df$geeks)))
legend("topright", c(df$labels), fill = rainbow(length(df$geeks)))
You might get a nicer look with ggplot though:
library(ggplot)
ggplot(df, aes(x = 1, y = percent, fill = labels)) +
geom_col() +
coord_polar(theta = "y") +
geom_text(aes(label = paste(percent, "%")),
position = position_stack(vjust = 0.5),
size = 8) +
theme_void(base_size = 20) +
scale_fill_brewer(name = NULL, palette = "Pastel2")

How to adjust barchart in ggplotly?

I have barchart with dual-axis in order to visualize 3 numerical variables. All these work pretty nice in ggplot. However, when I convert ggplot to ggplotly, there are issues:
in the legend, there are strange 1s (highlighted in yellow)
in the hover, there are double values (highlighted in yellow)
changes of hjust=0, vjust=-0.5 in geom_text are not reflected on the plot
Could anybody help me to adjust these issues?
df <- data.frame (model = c("A", "B", "C","D","E","F"),
share = c(12,20,15,9,60,20),
sale = c(16,25,18,14,67,28),
cost = c(14,19,28,24,57,28))
#set levels of model by cost
df$model <- factor(df$model, levels = arrange(df, desc(df$cost))$model)
library(tidyverse)
df_long <- df %>%
pivot_longer(
cols = -model
)
plt <- ggplot(df_long, aes(x = model, y= value, label=value))+
geom_col(data = filter(df_long, name != "cost"), aes(fill=name), position = position_dodge())+
scale_fill_manual(values = c("blue", "grey"))+
geom_line(data = filter(df_long, name == "cost"), aes(color = name, group = 1), size = 1)+
scale_color_manual(values = "red")+
geom_text(data = filter(df_long, name == "cost"), size = 3,hjust=0, vjust=-0.5)+
geom_label(data = filter(df_long, name == "cost"), hjust=0, vjust=-0.5)+
scale_y_continuous(
name = "Sale and Share",
sec.axis = sec_axis(~., name ="Cost")
)+
theme_minimal()+
theme(legend.title=element_blank())
ggplotly(plt)
Further approach from #Quinten's answer,
to handle 'name name' and 'value value' things,
try
tooltip = c("value", "name", "model")
plt1$x$layout$legend$title$text <- "name"
Full code is
plt <-
ggplot(df_long, aes(x = model, y= value, label = NA))+
geom_col(data = filter(df_long, name != "cost"), aes(fill=name), position = position_dodge())+
scale_fill_manual(values = c("blue", "grey"))+
geom_line(data = filter(df_long, name == "cost"), aes( group = 1, color = name), size = 1)+
scale_color_manual(values = "red")+
#geom_text(data = filter(df_long, name == "cost"), size = 3,hjust=0, vjust=-0.5)+
geom_label(data = filter(df_long, name == "cost"), hjust=0, vjust=-0.5)+
scale_y_continuous(
name = "Sale and Share",
sec.axis = sec_axis(~., name ="Cost")
)+
theme_minimal()
plt1 <- ggplotly(plt, tooltip = c("value", "name", "model"))
for (i in 1:length(plt1$x$data)){
if (!is.null(plt1$x$data[[i]]$name)){
plt1$x$data[[i]]$name = gsub("\\(","",str_split(plt1$x$data[[i]]$name,",")[[1]][1])
}
}
plt1$x$layout$legend$title$text <- "name"
It looks like you've got some great information so far. This addresses all of the things you identified. Although, at this point, it would be a LOT easier to just make the plot in Plotly!
The first thing I did is comment out the call for geom_text and geom_label. Plotly doesn't tend to play well here. It is going back into the plot, but not here.
Next, I built your plot and looked at the names and legend groups that were assigned by the conversion. This doesn't change anything—this is just looking.
plt2 <- plotly_build(plt)
invisible(
lapply(1:length(plt2$x$data),
function(j) {
message(j, " ", plt2$x$data[[j]]$name, " & ",
plt2$x$data[[j]]$legendgroup)
})
)
# 1 (sale,1) & (sale,1)
# 2 (share,1) & (share,1)
# 3 (cost,1) & (cost,1)
#Quinten addressed this issue, but this is how you can just look. Once I saw what Plotly "made", I was sure I knew what I needed to change.
This code changes these strings. It also prints the update to the console so that you can inspect what you expect.
invisible(
lapply(1:length(plt2$x$data),
function(j) {
x <- plt2$x$data[[j]]$name # find the name
y <- str_extract(x, "[a-z]+") # remove anything that's not a letter
plt2$x$data[[j]]$name <<- y # put it back
plt2$x$data[[j]]$legendgroup <<- y
message(j, " ", plt2$x$data[[j]]$name, " & ",
plt2$x$data[[j]]$legendgroup)
})
)
# 1 sale & sale
# 2 share & share
# 3 cost & cost
You can use this sort of look/change/check to validate the information that ends up in the tooltips, as well. Instead of $name or $legendgroup, you'll look at $text.
This next chunk of code doesn't check the input and print it out (I figured that would be redundant). This just changes it. (I did use that process to build this though.)
tx = " "
invisible(
lapply(1:length(plt2$x$data),
function(k){
tx <<- plt2$x$data[[k]]$text # tooltip for each trace
lapply(1:length(tx),
function(m) {
tr <- strsplit(tx[[m]], "<br />") # tooltip for each point
tr2 <- unique(tr[[1]]) # remove redundancy
str <- paste0(tr2, collapse = "<br />")
tx[[m]] <<- str # put it back together
})
plt2$x$data[[k]]$text <<- tx # change the plot
})
)
Now on to the labels-if you want a background or border, you have to use annotations in Plotly. Like annotation in the ggplot package, annotations in Plotly has less 'rules' per se.
You have an odd order for the model, so that has to be addressed, as well. When data moves between ggplot and Plotly, things tend to be awry. So it's unlikely that you'd be able to connect to the original data.
One thing to keep in mind, I used paper space for the x-axis. The default paper space (domain) in Plotly is [0,1]. Your graph is evenly spaced along the x, with your values in the middle of each of the six categories, so everything on the x is in terms of 1/6th space.
So first, put the data in order as it needs to appear in the plot. Then add the annotations (labels) to the plot. I've also removed the name of the legend here.
# to add labels, we need to have the order the data appears on the plot
df2 <- df_long %>%
arrange(desc(value)) %>%
filter(name == "cost")
plt2 %>%
layout(legend = list(title = "")) %>% # remove legend name
add_annotations(x = c(1/12, 1/6 + 1/12, 1/3 + 1/12, # using domain for x-axis
1/2 + 1/12, 2/3 + 1/12, 5/6 + 1/12),
y = df2$value,
text = df2$value,
xshift = 20, # shift right 20 px
yshift = 15, # shift up 15 px
hoverinfo = "skip",
bgcolor = "white",
bordercolor = "black",
xref = "paper", yref = "y", # cat x, use domain for annot x
showarrow = F)
After all of that, here's your plot.
This is straight plotly. I think the labels would look a bit better with padding (which can be added).
df_long %>%
filter(name != "cost") %>%
plot_ly(x = ~model, y = ~value, color = ~name, type = "bar",
customdata = ~name, colors = c("blue", "gray"),
hovertemplate = paste0("Model: %{x}<br>Value: %{y}<br>",
"Name: %{customdata}<extra></extra>")) %>%
add_lines(inherit = F, data = df, x = ~model,
y = ~cost, color = I("red"),
name = "cost",
hovertemplate = paste0("Model: %{x}<br>Value: %{y}<br>",
"Name: cost<extra></extra>")) %>%
add_annotations(data = df, x = ~model, y = ~cost, text = ~cost,
bgcolor = "white", bordercolor = "black",
xshift = 15, yshift = 15, showarrow = F) %>%
layout(barmode = "group")
Pretty much the same as the converted plot.
Legend issue:
Using the code in this post: Strange formatting of legend in ggplotly in R . You can change the legend in ggplotly like this:
library(plotly)
myplot = ggplotly(plt)
for (i in 1:length(myplot$x$data)){
if (!is.null(myplot$x$data[[i]]$name)){
myplot$x$data[[i]]$name = gsub("\\(","",str_split(myplot$x$data[[i]]$name,",")[[1]][1])
}
}
myplot
Output:

geom_dumbell spacing, legends in different places, and multiple aesthetics (timelines)

I saw this interesting way of creating a publication timeline using geom_dumbell, so I created my own by first loading the libraries:
library(tidyverse)
library(ggalt)
library(ggrepel)
Entering in some data:
# create data frame
df <- data.frame(
paper = c("Paper 1", "Paper 1", "Paper 2", "Paper 2", "Paper 3", "Paper 3", "Paper 3", "Paper 3"),
round = c("first","revision","first","revision","first","first","first","first"),
submission_date = c("2019-05-23","2020-12-11", "2020-08-12","2020-10-28","2020-12-10","2020-12-11","2021-01-20","2021-01-22"),
journal_type = c("physics", "physics","physics","physics","chemistry","chemistry","chemistry","chemistry"),
journal = c("journal 1", "journal 1", "journal 2", "journal 2", "journal 3", "journal 4", "journal 5", "journal 6"),
status = c("Revise and Resubmit", "Waiting for Decision", "Revise and Resubmit", "Accepted", "Desk Reject","Desk Reject", "Desk Reject","Waiting for Decision"),
decision_date = c("2019-09-29", "2021-01-24", "2020-08-27", "2020-10-29", "2020-12-10","2021-01-05","2021-01-22","2021-01-24"),
step_complete = c("yes","no","yes","yes","yes","yes","yes", "no"),
duration_days = c(129,44,15,1,0,25,2,2))
# convert variables to dates
df$decision_date = as.Date(df$decision_date)
df$submission_date = as.Date(df$submission_date)
and, finally, creating my own basic timeline using this code:
ggplot(df, aes(x = submission_date, xend = decision_date,
y = paper, label = duration_days,
color = status)) +
geom_dumbbell(size = 1, size_x = 1) +
scale_color_manual(values=c("green", "red", "darkolivegreen4", "turquoise1")) +
labs(x=NULL, color = 'Status:',
y=NULL,
title="Timeline of Journal Submissions",
subtitle="Start date, decision date, and wait time (in days) for my papers.") +
#theme_ipsum_tw() +
ggrepel::geom_label_repel(nudge_y = -.25, show.legend = FALSE) +
theme(legend.position = 'top')
As you can see from the above image, I can't see the x-axis. Additionally, I'd like to put another aesthetic and legend on the right side for the journal, perhaps putting a different shape on each line. Any other bells and whistles using the above data would be fun, too. Thanks!
Ok, I finally found some time to figure this out with help from this terrific post. To start, let's load the revised list of packages:
library(tidyverse)
library(ggalt)
library(ggrepel)
library(gridExtra)
library(gtable)
library(grid)
For comprehensiveness, let's reload the data:
# create dataframe
df <- data.frame(
paper = c("Paper 1", "Paper 1", "Paper 2", "Paper 2", "Paper 3", "Paper 3", "Paper 3", "Paper 3"),
round = c("first","revision","first","revision","first","first","first","first"),
submission_date = c("2019-05-23","2020-12-11", "2020-08-12","2020-10-28","2020-12-10","2020-12-11","2021-01-20","2021-01-22"),
journal_type = c("physics", "physics","physics","physics","chemistry","chemistry","chemistry","chemistry"),
Journal = c("journal 1", "journal 1", "journal 2", "journal 2", "journal 3", "journal 4", "journal 5", "journal 6"),
status = c("Revise and Resubmit", "Waiting for Decision", "Revise and Resubmit", "Accepted", "Desk Reject","Desk Reject", "Desk Reject","Waiting for Decision"),
decision_date = c("2019-09-29", "2021-01-24", "2020-08-27", "2020-10-29", "2020-12-10","2021-01-05","2021-01-22","2021-01-24"),
step_complete = c("yes","no","yes","yes","yes","yes","yes", "no"),
duration_days = c(129,44,15,1,0,25,2,2)
)
# convert variables to dates
df$decision_date = as.Date(df$decision_date)
df$submission_date = as.Date(df$submission_date)
First, let's create the plot with the color legend and extract it. Because I want that legend to be on top, I make sure indicate that as my legend position. Note that I specify my preferred colors using the scale_color_manual argument:
# make plot with color legend
p1 <- ggplot(df, aes(x = submission_date, xend = decision_date,
y = paper, label = duration_days,
color = status)) +
geom_dumbbell(size = 1, size_x = 1) +
scale_color_manual(values=c("green", "red", "darkolivegreen4", "turquoise1")) +
labs(x=NULL, color = 'Status:',
y=NULL,
title="Timeline of Journal Submissions",
subtitle="Start date, decision date, and wait time (in days) for my papers.") +
ggrepel::geom_label_repel(nudge_y = -.25, show.legend = FALSE) +
theme(legend.position = 'top')
# Extract the color legend - leg1
leg1 <- gtable_filter(ggplot_gtable(ggplot_build(p1)), "guide-box")
Second, let's make the plot with the shape legend and extract it. Because I want this legend to be positioned on the right side, I don't need to even specify the legend position here. Note that I specify my preferred shapes using the scale_shape_manual argument:
# make plot with shape legend
p2 <- ggplot(df, aes(x = submission_date, xend = decision_date,
y = paper, label = duration_days,
shape = Journal)) +
geom_dumbbell(size = 1, size_x = 1) +
scale_shape_manual(values=c(15, 16, 17, 18, 19,25))+
labs(x=NULL, color = 'Status:',
y=NULL,
title="Timeline of Journal Submissions",
subtitle="Start date, decision date, and wait time (in days) for my papers.") +
ggrepel::geom_label_repel(nudge_y = -.25, show.legend = FALSE)
# Extract the shape legend - leg2
leg2 <- gtable_filter(ggplot_gtable(ggplot_build(p2)), "guide-box")
Third, let's make the full plot with no legend, specifying both the scale_color_manual and scale_shape_manual arguments as well as theme(legend.position = 'none'):
# make plot without legend
plot <- ggplot(df, aes(x = submission_date, xend = decision_date,
y = paper, label = duration_days,
color =status, shape = Journal)) +
geom_dumbbell(size = 1, size_x = 3) +
scale_color_manual(values=c("green", "red", "darkolivegreen4", "turquoise1")) +
scale_shape_manual(values=c(15, 16, 17, 18, 19,25))+
labs(x=NULL, color = 'Status:',
y=NULL,
title="Timeline of Journal Submissions",
subtitle="Start date, decision date, and wait time (in days) for my papers.") +
ggrepel::geom_label_repel(nudge_y = -.25, nudge_x = -5.25, show.legend = FALSE) +
theme(legend.position = 'none')
Fourth, let's arrange everything according to our liking:
# Arrange the three components (plot, leg1, leg2)
# The two legends are positioned outside the plot:
# one at the top and the other to the side.
plotNew <- arrangeGrob(leg1, plot,
heights = unit.c(leg1$height, unit(1, "npc") - leg1$height), ncol = 1)
plotNew <- arrangeGrob(plotNew, leg2,
widths = unit.c(unit(1, "npc") - leg2$width, leg2$width), nrow = 1)
Finally, plot and enjoy the final product:
grid.newpage()
grid.draw(plotNew)
As everyone will no doubt recognize, I relied very heavily on this post. However, I did change a few things, I tried be comprehensive with my explanation, and some others spent time trying to help, so I think it is still helpful to have this answer here.

how do I change color in a plot with 3 columns?

So I have a data set with 3 columns (notCrammed, Hours, total grade)
I am plotting the hours against the total grade.
The notCrammed has only "0" for crammed and "1" for notCrammed.
I am plotting and trying to change the color for the people who crammed.
for example if 80 people did not cram and 20 did. I would like to change the color so i can see 80 green dots and 20 red dots. Or any color to differentiate them.
color <- 1
if(my.data$Studied<-1){
color <- 2
}
plot(my.data$Hours,my.data$Grade,xlab = "notCrammed",ylab = "Grade Scale",main = "Student Report",col =color)
EDIT 2, uploaded new plot, since the previous one had wrong par-settings.
You could do something like this:
#Simulating some data
set.seed(10)
my.data = data.frame("Hours" = sample(1:50, 10, replace = T),
"total grade" = sample(c(0,2,4,7,10,12), 10, replace = T),
"notCrammed" = rbinom(10, 1, prob = 0.5))
#Creating the plot
plot(my.data$Hours, my.data$total.grade, xlab = "notCrammed",ylab = "Grade Scale",
main = "Student Report", col = (my.data$notCrammed + 1))
In this case "not crammed" is the zeroes and is colored black, while crammed are colored red.
EDIT: Alternatively this should work if you want green and red:
plot(my.data$Hours, my.data$total.grade, xlab = "notCrammed",ylab = "Grade Scale", main = "Student Report",
col = c("green", "red")[as.factor(my.data$notCrammed)]))
Using #Qwethm's base dataset, you can preset colours using ggplot. This also allows you to change colours using plain language.
set.seed(10)
my.data = data.frame("Hours" = sample(1:50, 10, replace = T),
"total grade" = sample(c(0,2,4,7,10,12), 10, replace = T),
"notCrammed" = rbinom(10, 1, prob = 0.5))
library(ggplot2)
library(viridis)
my.data$notCrammed <- as.factor(my.data$notCrammed) #Change to a factor so it's discrete output
cols <- c("0" = "darkgreen","1"="red")
ggplot()+
geom_point(data=my.data,aes(x=Hours,y=total.grade,colour=notCrammed))+
scale_colour_manual(
values = cols,
aesthetics = c("colour", "fill")
)+
xlab("notCrammed")+
ylab("Grade Scale")+
ggtitle("Student Report")

Ordering of items within a stacked geom_bar

I want, for reasons which seems good to me, to plot a stacked bar chart, with the bars in a specific, data dependent order. For reasons which are obscure to me, it does not seem to work. Specifically, while I can readily arrange the rows of my dataframe in the right order, and make the column of names identifying the bars an ordered factor, so getting the bars in the order I desire, the graph does not list the columns of the dataframe in the order I desire.
An example
tab <- structure(list(Item = c("Personal", "Peripheral", "Communication", "Multimedia", "Office", "Social Media"), `Not at all` = c(3.205128, 18.709677, 5.844156, 31.578947, 20.666667, 25.827815), Somewhat = c(30.76923, 23.87097, 24.67532, 18.42105, 30, 16.55629), `Don't know` = c(0.6410256, 2.5806452, 1.9480519, 11.1842105, 2.6666667, 5.9602649), Confident = c(32.69231, 29.67742, 33.11688, 17.10526, 23.33333, 27.15232), `Very confident` = c(32.69231, 25.16129, 34.41558, 21.71053, 23.33333, 24.50331)), .Names = c("Item", "Not at all", "Somewhat", "Don't know", "Confident", "Very confident"), row.names = c(NA, -6L), class = "data.frame")
Title <- 'Plot title'
ResponseLevels <- c("Not at all", "Somewhat", "Don't know", "Confident", "Very confident") # Labels for bars
pal.1 <- brewer.pal(category, 'BrBG') # Colours
tab <- tab %>% arrange(.[,2]) # Sort by first columns of responses
tab$Item <- factor(tab$Item, levels = tab$Item[order(tab[,2])], ordered = TRUE) # Reorder factor levels
tab.m <- melt(tab, id = 'Item')
tab.m$col <- rep(pal.1, each = items) # Set colours
g <- ggplot(data = tab.m, aes(x = Item, y = value, fill = col)) +
geom_bar(position = "stack", stat = "identity", aes(group = variable)) +
coord_flip() +
scale_fill_identity("Percent", labels = ResponseLevels,
breaks = pal.1, guide = "legend") +
labs(title = Title, y = "", x = "") +
theme(plot.title = element_text(size = 14, hjust = 0.5)) +
theme(axis.text.y = element_text(size = 16,hjust = 0)) +
theme(legend.position = "bottom")
g
The stacked pieces of the bars run from right to left, from 'Not at all' to 'Very confident'. The items are in the correct order, from 'Multimedia' to 'Personal', ordered by the proportion of those who said 'Not at all' to each item.
What I want to get is this graph with the responses ordered the other way, the same way as the legend, that is from 'Not at all' on the left, to 'Very confident' on the right. I cannot figure out how this ordering is set, nor how to change it.
I've read through the 'similar questions', but can see no answer to this specific query. Suggestions, using ggplot, not base R graphics, welcome.
Ok, building on the useful, and much appreciated answer from allstaire, I try the following
library(tidyverse)
tab <- structure(list(Item = c("Personal", "Peripheral", "Communication", "Multimedia", "Office", "Social Media"), `Not at all` = c(3.205128, 18.709677, 5.844156, 31.578947, 20.666667, 25.827815), Somewhat = c(30.76923, 23.87097, 24.67532, 18.42105, 30, 16.55629), `Don't know` = c(0.6410256, 2.5806452, 1.9480519, 11.1842105, 2.6666667, 5.9602649), Confident = c(32.69231, 29.67742, 33.11688, 17.10526, 23.33333, 27.15232), `Very confident` = c(32.69231, 25.16129, 34.41558, 21.71053, 23.33333, 24.50331)), .Names = c("Item", "Not at all", "Somewhat", "Don't know", "Confident", "Very confident"), row.names = c(NA, -6L), class = "data.frame")
tab <- tab %>% select(1,6,5,4,3,2,1) ## Re-order the columns of tab
tab.m <- tab %>% arrange(`Not at all`) %>%
mutate(Item = factor(Item, levels = Item[order(`Not at all`)])) %>%
gather(variable, value, -Item, factor_key = TRUE)
ggplot(data = tab.m, aes(x = Item, y = value, fill = variable)) +
geom_col() +
coord_flip() +
scale_fill_brewer("Percent", type = 'cat', palette = 'BrBG',
guide = guide_legend(reverse = TRUE)) +
labs(title = 'Plot title', y = NULL, x = NULL) +
theme(legend.position = "bottom")
And this is exactly the graph I want, so my pressing problem is solved.
However, if I say instead
ggplot(data = tab.m, aes(x = Item, y = value, fill = variable)) +
geom_col() +
coord_flip() +
scale_fill_brewer("Percent", type = 'cat', palette = 'BrBG',
guide = guide_legend(reverse = FALSE)) +
labs(title = 'Plot title', y = NULL, x = NULL) +
theme(legend.position = "bottom")
The picture I get is this
Here the body of the chart is correct, but the legend is going in the wrong direction.
This solves my problem, but does not quite answer my question. I start with a dataframe, and to get what I want I have to reverse the order of the data columns, and reverse the guide legend. This evidently works, but it's perverse.
So, how does a stacked bar chart decide in what order to present the stacked items? It's clearly related to their order in the melted dataset, but simply changing the order leaves the legend going in the wrong direction. Looking at the melted dataset, tab.m, from top to bottom, the responses are in the order 'Very confident' to 'Not at all', but the default legend is the reverse order 'Not at all' to 'Very confident'.
If you pass guide_legend instead of just a string, you can set its reverse parameter to TRUE. Simplifying a bit,
library(tidyverse)
tab <- structure(list(Item = c("Personal", "Peripheral", "Communication", "Multimedia", "Office", "Social Media"), `Not at all` = c(3.205128, 18.709677, 5.844156, 31.578947, 20.666667, 25.827815), Somewhat = c(30.76923, 23.87097, 24.67532, 18.42105, 30, 16.55629), `Don't know` = c(0.6410256, 2.5806452, 1.9480519, 11.1842105, 2.6666667, 5.9602649), Confident = c(32.69231, 29.67742, 33.11688, 17.10526, 23.33333, 27.15232), `Very confident` = c(32.69231, 25.16129, 34.41558, 21.71053, 23.33333, 24.50331)), .Names = c("Item", "Not at all", "Somewhat", "Don't know", "Confident", "Very confident"), row.names = c(NA, -6L), class = "data.frame")
tab.m <- tab %>% arrange(`Not at all`) %>%
mutate(Item = factor(Item, levels = Item[order(`Not at all`)])) %>%
gather(variable, value, -Item, factor_key = TRUE)
ggplot(data = tab.m, aes(x = Item, y = value, fill = variable)) +
geom_col() +
coord_flip() +
scale_fill_brewer("Percent", palette = 'BrBG',
guide = guide_legend(reverse = TRUE)) +
labs(title = 'Plot title', y = NULL, x = NULL) +
theme(legend.position = "bottom")
For the edit:
Bar order is determined by factor level order, which in the above is determined by column order due to the use of gather to create the factor, thoughcoord_flip is making it less obvious. It's easy to reverse level order with levels<- or by reassembling the factor, though. To keep the colors with the same levels, pass direction = -1 to scale_fill_brewer to reverse their order, as well.
tab.m <- tab %>% arrange(`Not at all`) %>%
mutate(Item = factor(Item, levels = Item[order(`Not at all`)])) %>%
gather(variable, value, -Item, factor_key = TRUE) %>%
mutate(variable = factor(variable, levels = rev(levels(variable)), ordered = TRUE))
ggplot(data = tab.m, aes(x = Item, y = value, fill = variable)) +
geom_col() +
coord_flip() +
scale_fill_brewer("Percent", palette = 'BrBG', direction = -1,
guide = guide_legend(reverse = TRUE)) +
labs(title = 'Plot title', y = NULL, x = NULL) +
theme(legend.position = "bottom")

Resources