Consistent Color Scale and Legend Between Plots When Not All Levels of a Grouping Variable Are Present in the Data

Consistent color scale and legend between plots when not all levels of a grouping variable are present in the data

Set the factor levels of Colours to include all possible values, whether present or not in the data at hand, then add drop=FALSE to scale_colour_manual:

all.data=data.frame(Date=dates15, Data=ex.data, Colours=colours)
g.cols=c("black", "blue", "pink", "purple")
all.data$Colours = factor(all.data$Colours, levels=sort(c(unique(colours), "Pink Points")))

ggplot(all.data, aes(Date, Data, colour=Colours, group=1)) +
geom_line() +
scale_color_manual(values=g.cols, drop=FALSE) +
xlim(as.POSIXct("2015-01-01 00:00:00"), as.POSIXct("2015-02-12 23:45:00"))

Colouring by variable when using tidy graph in R?

Since each plot doesn't know anything about the other plots, it's best to assign colors yourself. First you can extract all the node names and assign them a color

nodenames <- unique(na.omit(unlist(lapply(myList, .%>%activate(nodes) %>% pull(name) ))))
nodecolors <- setNames(scales::hue_pal(c(0,360)+15, 100, 64, 0, 1)(length(nodenames)), nodenames)
nodecolors
# x4 x2 x1
# "#F5736A" "#00B734" "#5E99FF"

We use scales::hue_pal to get the "default" ggplot colors but you could use whatever you like. Then we just need to customize the color/fill scales for the plots with these colors.

plotFun <- function(List, colors=NULL){
plot <- ggraph(List, "partition") +
geom_node_tile(aes(fill = name), size = 0.25) +
geom_node_label(aes(label = label, color = name)) +
scale_y_reverse() +
theme_void() +
theme(legend.position = "none")
if (!is.null(colors)) {
plot <- plot + scale_fill_manual(values=colors) +
scale_color_manual(values=colors, na.value="grey")
}
plot
}
allPlots <- lapply(myList, plotFun, colors=nodecolors)
n <- length(allPlots)
nRow <- floor(sqrt(n))
do.call("grid.arrange", c(allPlots, nrow = nRow))

plot with coordinating node name colors

Same color for legends in different ggplot

You can set up a custom color scale and add it to your plot. Before your loop you could add something like the following:

cat.colors <- c("green", "blue",    "pink", "yellow") # assign a color for each level of your factor variable Categorie
names(cat.colors) <- levels(mydata$Categorie)
mycolourscale <- scale_fill_manual(name = "Categorie",values = cat.colors )

Then add:

      + mycolourscale 

to your ggplot code and the coloring will be consistent across plots

How can I maintain a color scheme across ggplots, while dropping unused levels in each plot?

The most effective way is to set a named variable of colors for each level (species) and use that in each plot.

Here, you can use the same colors you used above, but by adding names to the variable, you ensure that they always match up correctly:

irisColors <-
setNames( c('red', 'forestgreen', 'blue')
, levels(iris$Species) )

Gives

setosa     versicolor     virginica 
"red" "forestgreen" "blue"

And then you can use that to set your colors:

First with all colors:

ggplot(data = iris,
mapping = aes(x = Sepal.Length,
y = Sepal.Width,
color = Species)) +
geom_point() +
scale_color_manual(values = irisColors)

Sample Image

Then each of the subsets from your question:

ggplot(data = iris %>% filter(Species != 'virginica'),
mapping = aes(x = Sepal.Length,
y = Sepal.Width,
color = Species)) +
geom_point() +
scale_color_manual(values = irisColors)

Sample Image

ggplot(data = iris %>% filter(Species != 'setosa'),
mapping = aes(x = Sepal.Length,
y = Sepal.Width,
color = Species)) +
geom_point() +
scale_color_manual(values = irisColors)

Sample Image

Match ggsurvplot legend text color to line color, include risk table

While I appreciate your effort the ggtext package offers an easy option to achieve your desired result. Besides making it easier to set the legend text colors the final result could simply assigned back to the plot element of the ggurvplot object:

library(survival)
library(survminer)
library(ggtext)

fit <- survfit(Surv(time, status) ~ sex, data = lung)
fitgraph <- ggsurvplot(fit, risk.table = TRUE, risk.table.y.text.col = TRUE)

cols <- scales::hue_pal()(2)

labels <- function(x, cols) {
glue::glue("<span style = 'color: {cols}'>{x}</span>")
}

fitgraph$plot <- fitgraph$plot +
scale_color_discrete(labels = ~labels(.x, cols)) +
theme(legend.text = element_markdown())

fitgraph

Sample Image

UPDATE In case you pass a custom color palette we have to switch to scale_color_manual and pass the colors to the values argument. One drawback is that in that case we get a warning as we replace the already existing scale_color_manual:

library(survival)
library(survminer)
library(ggtext)

cols <- c("#B79F00", "#619CFF")

fit <- survfit(Surv(time, status) ~ sex, data = lung)
fitgraph <- ggsurvplot(fit, risk.table = TRUE, risk.table.y.text.col = TRUE, palette=cols)

labels <- function(x, cols) {
glue::glue("<span style = 'color: {cols}'>{x}</span>")
}

fitgraph$plot <- fitgraph$plot +
scale_color_manual(values = cols, labels = ~labels(.x, cols)) +
theme(legend.text = element_markdown())
#> Scale for 'colour' is already present. Adding another scale for 'colour',
#> which will replace the existing scale.

fitgraph

Sample Image

ggplot: change color of bars and not show all labels in legend

In setting the fill attribute you can group all other levels of the factor together (here using forcats::fct_other to collapse Years 1-9 into one level) to give your two levels of fill colours. At the same time, using group = cohort will keep bars separate:

library(forcats)

# plot data
df_data %>%
ggplot() +
geom_bar (aes(
x = factor(lab, levels = c("lab1", "lab2", "lab3", "lab4")),
y = data_rel,
group = cohort,
fill = fct_other(cohort, "year10", other_level = "year01")
),
stat = "identity",
position = position_dodge()) +
scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
theme_classic() +
theme(
legend.position = "bottom",
plot.title = element_text(hjust = 0.5,
size = 14,
face = "bold"),
plot.subtitle = element_text(hjust = 0.5),
plot.caption = element_text(hjust = 0.5),
) +
geom_text(
data = subset(df_data, cohort == "year10"),
aes(
x = lab,
y = data_rel,
label = paste0(sprintf("%.1f", data_rel * 100), "%")
),
vjust = -1,
hjust = -1.5,
size = 3
) +
scale_fill_manual(
values = c("#7822CC", "#389DC3"),
limits = c("year01", "year10"),
labels = c("Year 1 - 9", "Year 10")
) +
labs(
subtitle = paste(subtit),
title = str_wrap(tit, 45),
x = "",
y = "",
fill = ""
)

Sample Image

(Changed manual fill colour to distinguish from unfilled bars)

It's also possible to do by creating a new 2-level cohort_lumped variable before passing to ggplot(), but this way helps keep your data as consistent as possible up to the point of passing into graphing stages (and doesn't need extra columns storing essentially same information).

ggplot how to set fill value for non-exist integer while plotting a raster

Define Z as a factor with levels from 0 to 7 and use drop=FALSE inside scale_fill_manual:

XYZ.1$Z <- factor(XYZ.1$Z, levels=0:7)

p1 <- ggplot(XYZ.1)+ geom_raster(aes(X,Y,fill=Z)) +
coord_equal() + theme_bw() + xlab("") + ylab("") +
scale_fill_manual(values = c("grey50","#f7f7f7","#80b1d3","#7fc97f","#ffff99",
"#beaed4","red","#f0027f"),
name= "Integer", guide=guide_legend(reverse=TRUE), drop=FALSE) +
geom_polygon(data=shp.Kabini.basin.bndry, aes(long,lat,group=group),
colour="black", fill=NA)+
scale_x_continuous(breaks=seq(75.625,77.125, 0.25),
labels=c(paste(seq(75.625,77.125, 0.25),"°E", sep="")),expand = c(0, 0))+
scale_y_continuous(breaks=seq(11.375,12.625,0.25),
labels=c(paste(seq(11.375,12.625,0.25),"°N", sep="")),expand = c(0, 0)) +
theme(axis.text.x = element_text(angle = 90, hjust = 1),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()) +
theme(plot.title = element_text(hjust = 0.5,size = 10, face = "plain"),
legend.title=element_text(size=10), legend.text=element_text(size=9))
print(p1)

Sample Image

Seaborn set color for unique categorical over several pair-plots

For this use case, seaborn allows a dictionary as palette. The dictionary will assign a color to each hue value.

Here is an example of how such a dictionary could be created for your data:

from matplotlib import pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

df1 = pd.DataFrame({'tsne_one': np.random.randn(10),
'tsne-two': np.random.randn(10),
'mode': np.random.choice(['foot', 'metro', 'bike'], 10)})
df2 = pd.DataFrame({'tsne_one': np.random.randn(10),
'tsne-two': np.random.randn(10),
'mode': np.random.choice(['car', 'metro', 'bike'], 10)})
df3 = pd.DataFrame({'tsne_one': np.random.randn(10),
'tsne-two': np.random.randn(10),
'mode': np.random.choice(['foot', 'bus', 'metro', 'bike'], 10)})
df4 = pd.DataFrame({'tsne_one': np.random.randn(10),
'tsne-two': np.random.randn(10),
'mode': np.random.choice(['car', 'bus', 'metro', 'bike'], 10)})
modes = pd.concat([df['mode'] for df in (df1, df2, df3, df4)], ignore_index=True).unique()
colors = sns.color_palette('hls', len(modes))
palette = {mode: color for mode, color in zip(modes, colors)}

fig, axs = plt.subplots(2, 2, figsize=(12,6))
for df, ax in zip((df1, df2, df3, df4), axs.flatten()):
sns.scatterplot(x='tsne_one', y='tsne-two', hue='mode', data=df, palette=palette, legend='full', alpha=0.7, ax=ax)

plt.tight_layout()
plt.show()

sns.scatterplot with dictionary as palette



Related Topics



Leave a reply



Submit