Érico Patto
Érico Patto

Reputation: 1015

Manual color scale function for ggplot2

Please, don't run away. All I need is to set a function that gives the fill color given the parameter (which I set in fill = it).

I have an algorithm that will output a number (iterations needed) for every input in the complex plane for the Mandelbrot set.

In terms of what's important, I'll get a numeric output, and I'd like to color it a certain way. My outputs will vary from 1 to max, which in this post, I'll set to be 80.

Without setting my color scale (actually, I'm using the viridis palette, but still), this is how it looks:

ggplot(coord, aes(x = Re(coord), y = Im(coord), fill = it))+
  geom_raster()+
  theme_void()+
  coord_equal()+
  scale_fill_viridis_c(direction = -1)

enter image description here

This looks nice and all, but I want that the color when it == max (in this case, 80) to be black, and all the others to have their own palette.

As an example, these are two identical functions I'm thinking of using if I can to set the color scales:

col <- function(iter){  # Just used a different name because it's a different variable, but the value will be it
  if(iter == max)
    return("#000000")
  
  hsv(iter/max, 1, 1)
}
col2 <- function(iter){
  h <- iter/max
  v <- ifelse(iter == max, 0, 1)
  
  hsv(h, 1, v)
}

This should give me something like this (got it from another place):

enter image description here

Nicer, right?

By the way, if you want to replicate my data, this is the code:

# Function #####################################
library(tidyverse)

check <- function(c, max){
  z <- complex(real = 0, imaginary = 0)
  for(i in 1:max){
    z <- z^2 + c
    if(Mod(z) >= 2){
      return(i)
    }
  }
  return(max)
}

# Inputs #######################################
width <- 1000
height <- 1000
max <- 80

reMin <- -2
reMax <- 1
imMin <- -1
imMax <- 1

coord <- expand.grid(u = seq(reMin, reMax, length.out = width), v = seq(imMin, imMax, length.out = height)) %>% as_tibble()
coord <- complex(real = coord$u, imaginary = coord$v)
coord <- tibble(coord, it = vapply(coord, check, 1, max))

It runs reasonably fast. You don't have to understand it; just know that it outputs it for any coord. But if you want to, the inputs mean this: width will give a sort of resolution for the x axis, height does the same for the y axis, max is the maximum number of iterations (as I mentioned above), and the other four set the coordinates limits.

Upvotes: 0

Views: 840

Answers (1)

Allan Cameron
Allan Cameron

Reputation: 173793

You can play around with scale_fill_gradientn.

I think this gets you pretty close as a starting point:

ggplot(coord, aes(x = Re(coord), y = Im(coord), fill = it))+
  geom_raster()+
  theme_void()+
  coord_equal()+
  scale_fill_gradientn(colors = c("red", "orange", "gold", "yellow", "green", 
                                  "lightblue", "purple", "black"),
                       values = c(0, 0.3, 0.35, 0.4, 0.5 ,0.6, 0.99,1))

enter image description here

Upvotes: 4

Related Questions