I have a table with several binary variables. Is it possible to make a table such that all cells with 1s would be black. Like this
-
1Welcome to SO. This is a very appropriate use of a picture (it conveys the output needs well!). If you are familiar with `ggplot2`, the `geom_tile` and `geom_text` functions can do this. If you provide some data (Read https://stackoverflow.com/tags/r/info and links it provides for how to do that) SO contributors may be able to show you how for your specific case. – hrbrmstr Nov 20 '18 at 11:51
2 Answers
Using gridExtra
to create a gtable.
library(grid)
library(gridExtra)
set.seed(1)
sample.data <- matrix(data=sample(0:1, 5*5, r=TRUE), nrow=5, ncol=5)
colnames(sample.data) <- LETTERS[1:5]
rownames(sample.data) <- letters[1:5]
# for cut() to work data has to be of class matrix or table.
# data.frame will cause error
fcol <- as.character(cut(
sample.data, c(0, 0.5, 1), include.lowest=TRUE,
labels=c("black", "white")))
bcol <- as.character(cut(
sample.data, c(0, 0.5, 1), include.lowest=TRUE,
labels=c("white", "black")))
# building a theme.
# core specifies the features of the main field,
# rowhead the row titles, and colhead the column titles.
# fg_params specifies the features of the foreground, namely the text,
# bg_params specifies the features of the background, like the fill
# and border colors.
t1 <- ttheme_minimal(base_size=20,
core=list(
fg_params=list(col=fcol),
bg_params=list(fill=bcol, col="black", lwd=2)
),
rowhead=list(
fg_params=list(fontface=1)
),
colhead=list(
fg_params=list(fontface=1, rot=90)
)
)
grid.newpage()
grid.table(sample.data, theme=t1)

- 8,153
- 2
- 21
- 34
-
1This OP is obviously a new contributor and pretty obviously new to R, perhaps provide some (_any_?) context to what you're doing above for them? Your "solution" doesn't even plot it for them (and they likely do not know to use `grid.newpage()` on their own). – hrbrmstr Nov 20 '18 at 12:07
-
1
-
Thank you for your suggestion. Error in cut.default(Data1, c(0, 0.5, 1), include.lowest = TRUE, labels = c("black", : x should be numeric, but all my columns numeric I chekced by classes – Maria Zeltser Nov 20 '18 at 18:44
-
@MariaZeltser: Could you share `Data1` with us? Do `dput(Data1)` and copy-paste the result into your question. – AkselA Nov 20 '18 at 18:56
We'll use the data from the image (though this is likely not your use-case). This will simulate it:
library(tidyverse)
set.seed(2018-11-20)
# expand.grid just creates a data frame out of all the combinations
# of the provided vectors.
# tbl_df just turns the output into a data frame that (oversimplifying)
# prints better
# set_names is just setting column names
# the mutate line is where we generate the 0/1s
expand.grid(
sprintf("Address%s", 1:9),
sprintf("Transaction%s", 1:16),
stringsAsFactors = FALSE
) %>%
tbl_df() %>%
set_names(c("address", "transaction")) %>%
mutate(value = sample(0:1, n(), replace=TRUE)) -> xdf
xdf
## # A tibble: 144 x 3
## address transaction value
## <chr> <chr> <int>
## 1 Address1 Transaction1 0
## 2 Address2 Transaction1 1
## 3 Address3 Transaction1 1
## 4 Address4 Transaction1 0
## 5 Address5 Transaction1 1
## 6 Address6 Transaction1 1
## 7 Address7 Transaction1 0
## 8 Address8 Transaction1 0
## 9 Address9 Transaction1 1
## 10 Address1 Transaction2 0
## # ... with 134 more rows
If your data is "wide" vs "long" (like the above) take a look at the tidyr::gather
function.
Now, it's just a wee bit more data wrangling and some basic ggplot2. First, we'll use your logic and define cell fill and text color for each cell. And, since we want the X axis plotted in the reverse direction we also order it so that ggplot2 will honor that need.
mutate(
xdf,
fill = ifelse(value == 1, "black", "white"),
color = ifelse(value == 1, "white", "black"),
address = factor(address, levels = sort(unique(address), decreasing = TRUE))
) -> xdf
Now, we use a tile layer and put a text layer on top of it. We used "real" color names in the mutate
call above so we can take advantage of a ggplot2 "hack" by surrounding the mapped column aesthetic with I()
which tells ggplot2 to use the value as-is and also don't bother giving us a legend (we can generate a legend if you want but that wasn't in the sparse question).
Then, we remove some whitespace between labels and the plot, stick the Y labels on top and rotate them (though this is not a good practice since making folks twist their head to read your plot is not cool).
ggplot(xdf, aes(x = transaction, y = address)) +
geom_tile(
aes(fill = I(fill)),
color = "#2b2b2b", size=0.125,
) +
geom_text(
aes(label = value, color = I(color))
) +
scale_x_discrete(expand=c(0,0), position = "top") +
scale_y_discrete(expand=c(0,0)) +
labs(x = NULL, y = NULL) +
hrbrthemes::theme_ipsum_rc(grid="XY") +
theme(axis.text.x = element_text(angle=90, vjust=0.5, hjust=1))

- 77,368
- 11
- 139
- 205
-
thank you very much for you suggestion! I have the table already in talbe view. I am not an expert in R, so a little bit hard to understnad how to change your code – Maria Zeltser Nov 20 '18 at 18:53