Coloring a specific label in ggplot depending on the value of the id variable on long data (regardless of the line number)
Let's say I have a long dataset and I would like to color a specific label along the x axis. In the case of the example below, I would like to color the shortcut for Valiant.
# Packs
require(ggplot2)
require(reshape2)
# Data and trans
data(mtcars)
mtcars$model <- rownames(mtcars)
mtcars <- melt(mtcars, id.vars = "model")
# Some chart
ggplot(data = subset(x = mtcars, subset = mtcars$variable == "cyl"),
aes(x = model, y = value)) +
geom_bar(stat = "identity") +
theme(axis.text.x = element_text(angle = 90,
colour =
ifelse(mtcars$model == "Valiant",
"red","black")))
The code below shows the diagram below which is erroneous because the wrong label is colored.
The reason is quite simple, since the created one ifelse
does not correspond to the order on the axis. I can fix the code by forcing to ggplot
color a specific line. The code below colors the right label as in the specific data.frame
used for the chart, the line with the value Valiant 31 .
# Fixed chart
ggplot(data = subset(x = mtcars, subset = mtcars$variable == "cyl"),
aes(x = model, y = value)) +
geom_bar(stat = "identity") +
theme(axis.text.x = element_text(angle = 90,
colour =
ifelse(as.numeric(rownames(mtcars)) == 31,
"red","black")))
It is clear that this solution is highly impractical. In fact, I have a huge number of observations with multiple columns (geo, gender, indicator, value, etc.). This data is then filtered through the subset, and various parameters are passed to the settings aes
. Trying to figure out which line should be colored is a nightmare. I am looking for a solution that would allow me to:
- It is pointed out relatively effortlessly that a particular observation should be colored without trying to use line numbers.
- Ideally, I would like to use
id
with some line to indicate the text that I want to highlight - I would like to encapsulate the solution in code
ggplot2
, I do not want to create separate subsets of the data just to get the coloration vector as I will be doing this several times. This will result in unnecessary multiple objects. - In practice, I want the solution to work like this: no matter what's on the graph, when you find that line on the x-axis, make it red
source to share
The reason the first one is incompatible is that it is mtcars$model
much longer than the subset you are drawing, so the color vector ifelse(mtcars$model == "Valiant","red","black")
is 352 long, but the subset you are drawing is 32 in length. The same problem exists with your second example, although in this in the case of additional elements colour
(they are all "black") are discarded anyway, so you won't notice.
Unfortunately it theme(...)
doesn't seem to be evaluated with the data column names available to it (i.e. can't just do colour=ifelse(model == "Valiant", "red", "black")
directly in the call theme(...)
)
One option is to make a model
factor and filter by levels(..) == "Valiant"
. If you have a long dataframe, your id variable is most likely a factor anyway (or it would make sense to have one).
mtcars$model = factor(mtcars$model)
ggplot(data=subset(mtcars, variable == 'cyl'), aes(x=model, y=value)) +
geom_bar(stat="identity") +
theme(axis.text.x=element_text(angle=90,
colour=ifelse(levels(mtcars$model) == 'Valiant', 'red', 'black')))
(your problem has to do with feeding subset()
to ggplot as your data and then not being able to revert to that particular subset in the call theme
. I don't know if there is a tricky way to do this).
source to share