Reputation: 6116
I have a couple of 10x10 matrices that are filled with five values, namely: 0, 0.5, 1, 1.5, and 2. Not all matrices have all of these values.
I want to make plots, with the same values always having the same colours. I have five specific colours that I want linked to the specific values, namely:
Currently, the code looks like this:
example_mat <- matrix(sample(c(0,0.5,1,1.5,2),100, replace = TRUE), nrow = 10, ncol = 10)
# make rotate function for plot
rotate <- function(x) t(apply(x, 2, rev))
# plot
image(rotate(example_mat), col=c("white","light blue","blue","lightpink1","red"), xaxt= "n", yaxt= "n")
grid(nx = 10, ny = 10, col = "black", lty = "solid")
box(which = "plot", lty = "solid")
This produced the following plot:
This seems to work well, except I have a lot of these plots, and sometimes not all 5 values (0, 0.5, 1, 1.5, and 2) are present in the matrix, and he then assigns different colours to the values. How do I make this plot always have the same colours for the same values?
Upvotes: 2
Views: 5774
Reputation: 16871
I would approach this with a couple dplyr
and tidyr
functions to create a data frame shaped appropriately for ggplot2
, then use ggplot2
's tile. I'm treating the value column as a character to make it explicitly discrete. If you had more values, you might instead use cut
to break into factor levels.
First off, I've made the named vector of colors that will go into scale_fill_manual
—colors are the vector elements, and corresponding numbers are the names, as is the expected setup for the scale's values
argument.
library(ggplot2)
library(dplyr)
library(tidyr)
set.seed(324)
example_mat <- matrix(sample(c(0,0.5,1,1.5,2),100, replace = TRUE), nrow = 10, ncol = 10)
colors <- c("white", "lightblue", "blue", "lightpink1", "red") %>%
setNames(c(0, 0.5, 1, 1.5, 2))
Then to reshape the data for plotting, I make a data frame, add row numbers, and convert to a long shape with gather
. The automatic column names were given as V1
, V2
,..., so I extract the numeric part of that text with the regex \\d+
to get column numbers.
rotate <- function(x) t(apply(x, 2, rev))
mat_long <- rotate(example_mat) %>%
as_tibble() %>%
mutate(row = row_number()) %>%
gather(key = col, value = value, -row) %>%
mutate(col = stringr::str_extract(col, "\\d+") %>% as.numeric())
mat_long
#> # A tibble: 100 x 3
#> row col value
#> <int> <dbl> <dbl>
#> 1 1 1 1
#> 2 2 1 1.5
#> 3 3 1 1.5
#> 4 4 1 2
#> 5 5 1 1.5
#> 6 6 1 0.5
#> 7 7 1 0
#> 8 8 1 1
#> 9 9 1 0.5
#> 10 10 1 0.5
#> # … with 90 more rows
Then plotting is fairly straightforward, with the values treated as character, and the named color palette given for the fill.
ggplot(mat_long, aes(x = col, y = row, fill = as.character(value))) +
geom_tile(color = "black") +
scale_fill_manual(values = colors) +
theme_void()
Created on 2019-03-24 by the reprex package (v0.2.1)
Upvotes: 1
Reputation: 6567
Using base R, there is the zlim
parameter to the image
function which does the job.
set.seed(42)
example_mat1 <- matrix(sample(c(0,0.5,1,1.5,2),100, replace = TRUE), nrow = 10, ncol = 10)
example_mat2 <- example_mat1
example_mat2[example_mat2 == 2] = 0 # remove one of the values
# make rotate function for plot
rotate <- function(x) t(apply(x, 2, rev))
# plot
image(rotate(example_mat1), col=c("white","light blue","blue","lightpink1","red"), zlim=c(0,2), xaxt= "n", yaxt= "n")
grid(nx = 10, ny = 10, col = "black", lty = "solid")
box(which = "plot", lty = "solid")
image(rotate(example_mat2), col=c("white","light blue","blue","lightpink1","red"), zlim=c(0,2), xaxt= "n", yaxt= "n")
grid(nx = 10, ny = 10, col = "black", lty = "solid")
box(which = "plot", lty = "solid")
This makes the following plots...
Upvotes: 3
Reputation: 32558
One way would be to use ggplot
and pre-define the fill color for each tile based on its value.
#Define colors using named vector
mycols = c(white = 0, lightblue = 0.5, blue = 1, pink = 1.5, red = 2)
#DATA
set.seed(42)
example_mat = matrix(sample(c(0,0.5,1,1.5,2),100, replace = TRUE), nrow = 10, ncol = 10)
rotate <- function(x) t(apply(x, 2, rev))
m1 = rotate(example_mat)
library(ggplot2)
#Convert to long format
d = data.frame(Values = as.vector(m1),
fillcol = names(mycols[match(m1, mycols)]),
X = as.vector(row(m1)),
Y = as.vector(col(m1)))
graphics.off()
ggplot(d, aes(x = X, y = Y)) +
geom_tile(color = "black", fill = d$fillcol) +
theme_light() +
coord_equal()
Upvotes: 3