set x axis on ggtree heatmap in R - r

I would like to set x axis on a heatmap ggtree.
This is my code
ggtree(working_tree,open.angle=15, size=0.1) %<+% avian %<+% color +
aes(color = I(colour)) +
geom_tippoint(size = 2,) +
geom_tiplab(size = 3, colour = "black") +
theme_tree2()
# I want to rotate the x axis and get the positive number
p1 <- revts(p) + scale_x_continuous(labels = abs)
h1 <- gheatmap(p1, landuse,
offset = 15, width = 0.05, font.size = 3, colnames_position = "top", colnames_angle = 0,
colnames_offset_y = 0, hjust = 0) +
scale_fill_manual(breaks = c("Forest", "Jungle rubber", "Rubber", "Oil palm"),
values = c("#458B00", "#76EE00", "#1874CD", "#00BFFF"), name = "Land use system",
na.value = "white")
, and I got this picture
The problem is that when I showed the heatmap, the x axis automatically changes the range itself from 0 to 60. However, the range I want is from 0 to 80.
Does anyone know how to do this or have any experiences for this?

Updated
I already solved the case by using the function scale_x_continous like this
scale_x_continuous(breaks = seq(-80,0,20), labels = abs(seq(-80,0,20)))
For anyone interested in geological timescale in R, I suggest to use the package deeptime

Related

Problem with colouring a GG Plot Histogram

I`ve got an issue with colouring a ggplot2 histogram.
R-Junk
ggplot(Hospital, aes(x=BodyTemperature)) +
geom_histogram(aes(fill = factor(BodyTemperature))) +
scale_x_continuous(breaks = seq(0, 100, by = 10)) +
ylab("prevalence") +
xlab("BodyTemperature") +
ggtitle("Temperature vs. prevalence")
So the histogram should plot the information (x-axis), that as higher the temperature gets, the worse it is. So for example „temperature“ at 36°C should be green, 38°C yellow, 40° red - going from left to right on the x-axis.
Y-Axis should provide how often these temperatures ocures in the Patientdata of the Hospital. The Data "BodyTemperature" is a list of 200+ Data like: "35.3" or "37.4" etc.
How can this chunk be fixed to provide the color changes? For a non-ggplot version ive already written this r-junk positiv:
```{r, fig.width=8}
color1 <- rep(brewer.pal(1, "Greens"))
color2 <- rep("#57c4fa", 0)
color3 <- brewer.pal(8, "Reds")
hist(Hospital$BodyTemperature[-357],
breaks = seq(from = 0, to = 100, by = 10),
main = "Temperature vs. prevalence",
ylab = "prevalence",
xlab = "Temperature",
col = c(color1, color2, color3))
```
The key is to make sure the bin intervals used for the fill scale match those used for the x axis. You can do this by setting the binwidth argument to geom_histogram(), and using ggplot2::cut_width() to break BodyTemperature into the same bins for the fill scale:
set.seed(13)
library(ggplot2)
# example data
Hospital <- data.frame(BodyTemperature = 36.5 + rchisq(100, 2))
ggplot(Hospital, aes(BodyTemperature)) +
geom_histogram(
aes(fill = cut_width(BodyTemperature, width = 1)),
binwidth = 1,
show.legend = FALSE
) +
scale_fill_brewer(palette = "RdYlGn", direction = -1) +
labs(
title = "Temperature vs. Prevalence",
x = "Body Temperature (°C)",
y = "Prevalence"
) +
theme_minimal()
Created on 2022-10-24 with reprex v2.0.2

When using a color transformation in ggplot2, change the legend gradient instead of the legend break positions

Suppose I have a raster plot where the fill color gradient isn't used very efficiently because the values are skewed, like this:
library(ggplot2)
set.seed(20)
d = expand.grid(x = seq(0, 10, len = 100), y = seq(0, 10, len = 100))
d = transform(d, z =
1e-4 * ((x - 2)^2 + (2*y - 4)^2 + 10*rnorm(nrow(d)))^2)
ggplot(d) +
geom_raster(aes(x, y, fill = z)) +
scale_fill_distiller(palette = "Spectral",
limits = c(0, 12), breaks = 0 : 12) +
theme(legend.key.height = unit(20, "mm"))
I can quantile-transform the color scale like this:
ggplot(d) +
geom_raster(aes(x, y, fill = z)) +
scale_fill_distiller(palette = "Spectral",
limits = c(0, 12), breaks = 0 : 12,
trans = scales::trans_new("q",
function(x) ecdf(d$z)(x),
function(x) unname(quantile(d$z, x)))) +
theme(legend.key.height = unit(20, "mm"))
I like what this does for the main part of the plot, but not the legend. The legend uses the same gradient as the original, while moving the breaks according to the transformation. I'd prefer to keep the breaks where they are, while transforming the gradient instead. Also, I'd like to avoid the floating-point noise that's been added to the break labels. How can I accomplish these changes?
I had a very similar idea to chemdork123, but wanted to stay a bit closer to the quantile idea. The idea is to set an exact palette of colours (i.e., one colour for every value) and space this out such that it follows the data.
library(ggplot2)
library(scales)
#> Warning: package 'scales' was built under R version 4.0.3
set.seed(20)
d = expand.grid(x = seq(0, 10, len = 100), y = seq(0, 10, len = 100))
d = transform(d, z =
1e-4 * ((x - 2)^2 + (2*y - 4)^2 + 10*rnorm(nrow(d)))^2)
# The 'distiller' palette outside of the scale,
# we need this to generate `length(d$z)` number of colours.
pal <- gradient_n_pal(brewer_pal(palette = "Spectral", direction = -1)(7))
ggplot(d) +
geom_raster(aes(x, y, fill = z)) +
scale_fill_gradientn(
colours = pal(c(0, rescale(seq_along(d$z)), 1)), # <- extra 0, 1 for out-of-bounds
limits = c(0, 12), breaks = 0:12,
values = c(0, rescale(sort(d$z), from = c(0, 12)), 1) # <- extra 0, 1 again
) +
theme(legend.key.height = unit(10, "mm"))
Created on 2021-03-31 by the reprex package (v1.0.0)
You can use the values argument for the scale_fill_distiller() function. The distiller scales extend brewer to continuous scales by interpolating 7 colors from any palette. By default, the scaling is linearly applied from 0 (lowest value on the scale) to 1 (highest value on the scale). You can recreate this mapping via: scales::rescale(1:7). If you supply a new vector to the values argument, you can remap each of the 7 colors to a new location. You do not have to supply 7 values - the rest are interpolated linearly - just as long as you specify the max at 1 (or you'll cut the scale).
Best way is to play around with it - I've tried mapping to specific functions before, but honestly it tends to work for me the best when I just mess with the numbers until I get something I like:
ggplot(d) +
geom_raster(aes(x, y, fill = z)) +
scale_fill_distiller(palette = "Spectral", values = c(0,0.05,0.1, 0.5,1)) +
theme(legend.key.height = unit(20, "mm"))

divide the y axis to make part with a score <25 occupies the majority in ggplot

I want to divide the y axis for the attached figure to take part with a score <25 occupies the majority of the figure while the remaining represent a minor upper part.
I browsed that and I am aware that I should use scale_y_discrete(limits .I used this p<- p+scale_y_continuous(breaks = 1:20, labels = c(1:20,"//",40:100)) but it doesn't work yet.
I used the attached data and this is my code
Code
p<-ggscatter(data, x = "Year" , y = "Score" ,
color = "grey", shape = 21, size = 3, # Points color, shape and size
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
add = "loess", #reg.line
conf.int = T,
cor.coef = F, cor.method = "pearson",
xlab = "Year" , ylab= "Score")
p<-p+ coord_cartesian(xlim = c(1980, 2020));p
Here is as close as I could get getting a fake axis break and resizing the upper area of the plot. I still think it's a bad idea and if this were my plot I'd much prefer a more straightforward axis transform.
First, we'd need a function that generates a transform that squeezes all values above some threshold:
library(ggplot2)
library(scales)
# Define new transform
my_transform <- function(threshold = 25, squeeze_factor = 10) {
force(threshold)
force(squeeze_factor)
my_transform <- trans_new(
name = "trans_squeeze",
transform = function(x) {
ifelse(x > threshold,
((x - threshold) * (1 / squeeze_factor)) + threshold,
x)
},
inverse = function(x) {
ifelse(x > threshold,
((x - threshold) * squeeze_factor) + threshold,
x)
}
)
return(my_transform)
}
Next we apply that transformation to the y-axis and add a fake axis break. I've used vanilla ggplot2 code as I find the ggscatter() approach confusing.
ggplot(data, aes(Year, Score)) +
geom_point(color = "grey", shape = 21, size = 3) +
geom_smooth(method = "loess", fill = "lightgray") +
# Add fake axis lines
annotate("segment", x = -Inf, xend = -Inf,
y = c(-Inf, Inf), yend = c(24.5, 25.5)) +
# Apply transform to y-axis
scale_y_continuous(trans = my_transform(25, 10),
breaks = seq(0, 80, by = 10)) +
scale_x_continuous(limits = c(1980, 2020), oob = oob_keep) +
theme_classic() +
# Turn real y-axis line off
theme(axis.line.y = element_blank())
You might find it informative to read Hadley Wickham's view on discontinuous axes. People sometimes mock weird y-axes.

Let data reach limits in ggplot instead of going NA

I'm attempting to plot some standard error (SE) bars using ggplot2. In this set-up, I have thick bars displaying typical SE bars, but on top of those bars, I overlay thin bars showing "alternative" SEs (which are under the heading "se2" in the data). These alternative SE bars are always larger than the data.
The issue that I'm running into is that the large alternative SEs get removed, with the warning message telling me that 2 rows are removed since they were containing missing values. What I would like is simply for these values to be displayed anyway, where if the alternative SE bar reaches the limit I've set, then it stops there, still showing up (with the implication for the reader then that it continues past).
I've posted a simplified version of what I'm working with:
# Load packages
library(dplyr)
library(ggplot2)
library(ggpubr)
# Make dataframe for group 1
df_values1 <- data.frame(
beta = c(0.07,0.04,0.3),
se = c(.01,0.01,0.008),
se2 = c(0.1,0.05,0.2),
outcome = c("Name 1",
"Name 2",
"Name 3"),
sample = c(rep("Group1",3))
)
# Make dataframe for group 2
df_values2 <- data.frame(
beta = c(0.15,-0.04,0.03),
se = c(.01,0.01,0.008),
se2 = c(0.1,.2,0.05),
outcome = c("Name 1",
"Name 2",
"Name 3"),
sample = c(rep("Group2",3))
)
# Make dataframe for group 3
df_values3 <- data.frame(
beta = c(0.22,0.18,-0.03),
se = c(.01,0.01,0.008),
se2 = c(1,0.05,0.01),
outcome = c("Name 1",
"Name 2",
"Name 3"),
sample = c(rep("Group3",3))
)
# Position dodge
pd <- position_dodge(0.7)
# Merge datasets
df_all <- rbind(df_values1, df_values2, df_values3)
# NOTE: use the levels of outcome from one of the non-merged datasets
df_all$outcome <- factor(df_all$outcome, levels = df_values1$outcome)
# Because the coordinates will be flipped, the order of the levels is 'reversed' here
df_all$sample <- factor(df_all$sample, levels = c('Group3', 'Group2', 'Group1'))
# Plot
picture <- ggplot(df_all, aes(x = outcome, y = beta, group = sample, colour = sample)) +
geom_hline(yintercept = c(-0.375, -0.125, 0.125, 0.375), size = 0.25, colour = 'grey95') +
geom_errorbar(aes(ymin = beta-1.96*se, ymax = beta+1.96*se), width = 0, alpha = 1, size = 2, position = pd) +
geom_errorbar(aes(ymin = beta-1.96*se2, ymax = beta+1.96*se2), width = 0, alpha = 1, size = 0.5, position = pd) +
geom_hline(yintercept = 0, size = 0.25) +
guides(colour = guide_legend(reverse = TRUE), shape = guide_legend(reverse = TRUE)) +
ylim(-0.5,0.5) +
coord_flip() +
scale_x_discrete(limits = rev(levels(df_all$outcome)))
picture
Here is the picture of the result
I'm hoping there's a solution that will accommodate both situations in the example above: 1) the pink alternative SEs for "Name 1" are too large, so ideally they would be from end-to-end of the graph; 2) the blue alternative SEs for "Name 3" are too large on the right but on the left should stop within the plot. So on the left it stops in the plot but on the right continues until it hits the limit. Thanks!
See both answers here: How to set limits for axes in ggplot2 R plots? Normally coord_cartesian is used to prevent data being clipped but if you are using coord_flip then limits can be set within this:
picture <- ggplot(df_all, aes(x = outcome, y = beta, group = sample, colour = sample)) +
geom_hline(yintercept = c(-0.375, -0.125, 0.125, 0.375), size = 0.25, colour = 'grey95') +
geom_errorbar(aes(ymin = beta-1.96*se, ymax = beta+1.96*se), width = 0, alpha = 1, size = 2, position = pd) +
geom_errorbar(aes(ymin = beta-1.96*se2, ymax = beta+1.96*se2), width = 0, alpha = 1, size = 0.5, position = pd) +
geom_hline(yintercept = 0, size = 0.25) +
guides(colour = guide_legend(reverse = TRUE), shape = guide_legend(reverse = TRUE)) +
coord_flip(ylim = c(-0.5,0.5)) +
scale_x_discrete(limits = rev(levels(df_all$outcome)))

r: ggplot2 and shiny: how to make text more readable without using geom_label?

I use shiny to create some reactive plots. When I use geom_text to put the intercepts of geom_vlines next to the lines, I can hardly read the text because of the colors of the plot. I have tried with various colours, none work well.
When I use geom_label instead of geom_text from the {ggplot2} package, my plots take much longer to load. The time basically triples. I have read the article on geom_label and it says that it takes longer to create the plot.
So my question is, how could I make text more readable on the plot without using geom_label and thus slowing down the time to create the plot? Does anybody have any ideas? I know there are solutions, but which one is the ideal one in terms of the time it takes to create the plot. Thank you!
EDIT
Here is an example. I can not change the colors of the plot or text. I could change the position along the y axis of the text.
set.seed(1)
df <- data.frame(numbers = rnorm(1000, 1000, 500))
p123 <- ggplot(data = df, aes(x = numbers))+
geom_histogram(bins = 15, fill = "#000D62")+
geom_vline(xintercept = mean(df$numbers)*2.5)+
geom_text(label = paste0("value = ", round(mean(df$numbers)*2.5, 0),
"€"), x = mean(df$numbers)*2.5, y = 4,
size = 4, colour = "#FFBA18")+
labs(x = "Numbers", y = "number of observations")
plot(p123)
Option 1
One option is to replicate the geom_text() layer and put a copy of it below in white and bold to serve as a makeshift dropshadow. I don't know if that would actually improve your performance, but it does technically avoid using geom_label(). Also I've found that it can be used with plotly::ggplotly() which is not true of geom_label().
library(tidyverse)
# sim data
set.seed(1)
df <- data.frame(numbers = rnorm(1000, 1000, 500))
# base plot
p <- ggplot(data = df, aes(x = numbers)) +
geom_histogram(bins = 15, fill = "#000D62") +
geom_vline(xintercept = mean(df$numbers) * 2.5) +
labs(x = "Numbers", y = "number of observations")
## with plain ggplot2 using two geom_text layers
p +
geom_text(label = paste0("value = ", round(mean(df$numbers) * 2.5, 0), "€"),
x = mean(df$numbers) * 2.5, y = 4, size = 4,
colour = "white", fontface = "bold") +
geom_text(label = paste0("value = ", round(mean(df$numbers) * 2.5, 0), "€"),
x = mean(df$numbers) * 2.5, y = 4, size = 4,
colour = "#FFBA18")
Option 2
Another option is to use the {shadowtext} package which directly addresses this issue.
## with shadowtext library
library(shadowtext)
p +
geom_shadowtext(
label = paste0("value = ", round(mean(df$numbers) * 2.5, 0), "€"),
x = mean(df$numbers) * 2.5, y = 4, size = 4, colour = "#FFBA18")
Created on 2022-05-18 by the reprex package (v2.0.1)

Resources