3

I would like to conditionally alter the color/face/etc of a continuous tick mark label using logic instead of hard coding. For example:

library(tidyverse)
library(viridis)
xx=rpois(1000,lambda = 40)
y=density(xx,n=3600,from=0)

ggplot(data.frame(x = y$x, y = y$y), aes(x, y)) + 
  geom_line() + 
  geom_segment(aes(xend = x, yend = 0, colour = y)) + 
  scale_color_viridis() +
  labs(y='Density',x='Count',colour='Density')+
  geom_vline(xintercept=40,color='red') +
  scale_x_continuous(breaks=c(0,40,seq(25,100,25)),limits=c(0,100))+
  theme(axis.text.x = element_text(face=c('plain','bold',rep('plain',4)),
                                   color=ifelse(y$x==60,'red','black')))

So in my example above, hard coding is seen in the face function and that works (I can do the same thing for color). It's not a big deal here since I only have a few breaks. In future scenarios, though, I may have significantly more breaks or a less simple coloring scheme needed for my axes. Is there a more efficient solution to create this labeling based on conditional logic? My first attempt is seen in color function but that does not work . The issue is identifying the object to use in the logical statement. Maybe there is a behind the scenes variable I can call for the breaks (similar to using ..level.. for a density plot). If that's the case, bonus points if you can teach me how to find it/figure that out on my own

zx8754
  • 52,746
  • 12
  • 114
  • 209
c.custer
  • 407
  • 5
  • 13
  • "Behind the scenes" variables like `..level..` are generally only available inside `aes()`. – Gregor Thomas Mar 02 '18 at 20:14
  • 2
    I don't think you can do it programmatically within `theme`. But if you already have specified a `breaks` vector, just use it to create also the face vector in advance. See also: [Change color of specific tick in ggplot2](https://stackoverflow.com/questions/34841470/change-color-of-specific-tick-in-ggplot2) – Henrik Mar 02 '18 at 20:15
  • Thanks! These helped out a lot. I took your advice and defined my `breaks` vector before the plot. I was then able to use the `ifelse` logic within theme... i.e. `ifelse(breaks==40,'red','black')` I'm not sure it's any better than defining the color (or face) vector before the plot like the breaks vector but I thought it was interesting to see it work. – c.custer Mar 02 '18 at 20:49
  • @godzilla you should write your solution as an answer and accept it to mark this question answered. It's an interesting question! :) – Djork Mar 03 '18 at 22:14

1 Answers1

1

Quick thanks to Djork for teaching me some QnA etiquette...

I was able to solve this problem by defining my break points outside of ggplot and then using ifelse logic within the theme function to create my desired outcome. The updated (and working) example of my original code is below:

library(tidyverse)
library(viridis)
xx=rpois(1000,lambda = 40)
y=density(xx,n=3600,from=0)

med_x=median(xx)
breakers = c(seq(0,100,25),med_x)

ggplot(data.frame(x = y$x, y = y$y), aes(x, y)) + 
  geom_line() + 
  geom_segment(aes(xend = x, yend = 0, colour = y)) + 
  scale_color_viridis() +
  labs(y='Density',x='Count',colour='Density')+
  geom_vline(xintercept=40,color='red') +
  scale_x_continuous(breaks=breakers,limits=c(0,100))+
  theme(axis.text.x = element_text(face=ifelse(breakers==med_x,'bold','plain'),
                                   color=ifelse(breakers==med_x,'red','black')))

I haven't tried this on more complicated logic yet but I assume that this approach will work across all logical formatting.

c.custer
  • 407
  • 5
  • 13