uclahs-cds / package-BoutrosLab-plotting-general

Functions to Create Publication-Quality Plots
https://uclahs-cds.github.io/package-BoutrosLab-plotting-general
11 stars 4 forks source link

Barplot bottom covariate "follows" xlab.label #82

Open lydiayliu opened 1 year ago

lydiayliu commented 1 year ago

It seems impossible to add an xlab.label when there are bottom covariates. The covariates also occupy the same space as the xaxis label and covers it, regardless of using xlab.axis.padding, key.bottom also doesn't seem to do anything.

library(BoutrosLab.plotting.general)

# set up the data
total.counts <- apply(SNV[1:15], 2, function(x){ mutation.count <- (30 - sum(is.na(x)))});
count.nonsyn <- function(x){
    mutation.count <- length(which(x == 1));
    }
nonsynonymous.SNV <- apply(SNV[1:15], 2, count.nonsyn);
other.mutations <- total.counts - nonsynonymous.SNV;

# subset the first fifteen samples
barplot.data <- data.frame(
    samples = rep(1:15, 2),
    mutation = c(rep('nonsynonymous', 15), rep('other',15)),
    type = c(rep(1, 15), rep(2,15)),
    values = c(nonsynonymous.SNV, other.mutations),
    sex = rep(patient$sex[1:15], 2),
    stage = rep(patient$stage[1:15], 2),
    msi = rep(patient$msi[1:15], 2)
    );

# set covariate colour schemes
covariate.colours.sex <- as.character(barplot.data$sex);
covariate.colours.sex[covariate.colours.sex == 'male'] <- 'dodgerblue';
covariate.colours.sex[covariate.colours.sex == 'female'] <- 'pink';

covariate.colours.stage <- as.character(barplot.data$stage);
covariate.colours.stage[covariate.colours.stage == 'I'] <- 'plum1';
covariate.colours.stage[covariate.colours.stage == 'II'] <- 'orchid1';
covariate.colours.stage[covariate.colours.stage == 'III'] <- 'orchid3';
covariate.colours.stage[covariate.colours.stage == 'IV'] <- 'orchid4';

covariate.colours.msi <- as.character(barplot.data$msi);
covariate.colours.msi[covariate.colours.msi == 'MSS'] <- 'chartreuse4';
covariate.colours.msi[covariate.colours.msi == 'MSI-High'] <- 'chartreuse2';

# create object to draw covariates
covariates.object <- list(
    rect = list(
        col = 'white',
        fill = covariate.colours.sex,
        lwd = 1.5
        )
    );

# see BoutrosLab.plotting.general::covariates.grob() for more information
covariate.object.grob <- covariates.grob(
    covariates = covariates.object,
    ord = c(1:15),
    side = 'top',
    size = 0.8
    );

# Create legend to explain covariates
covariates.legends <- list(
    legend = list(
        colours = c('dodgerblue','pink'),
        labels = c('male','female'),
        title = 'Sex',
        border = 'white'
        )
    );

# see BoutrosLab.plotting.general::legend.grob() for more information
covariate.legend.grob <- legend.grob(
    legends = covariates.legends,
    title.just = 'left'
    );

create.barplot(
    # filename = tempfile(pattern = 'Barplot_Covariates', fileext = '.tiff'),
    formula = values ~ samples,
    data = barplot.data[barplot.data$mutation == 'nonsynonymous',],
    main = 'Covariates',
    ylab.lab = 'Mutations',
    ylimits = c(0,30),
    yat = seq(0,30,5),
    yaxis.cex = 1,
    xlab.label = 'Test Label',
    xlab.cex = 1.5,
    ylab.cex = 1.5,
    yaxis.fontface = 1,
    # removing x-axis formatting to give space to covariates
    xaxis.tck = 0,
    xaxis.lab = rep('',15),
    xaxis.cex = 0,
    # covariates
    legend = list(
        bottom = list(fun = covariate.object.grob),
        right = list(fun = covariate.legend.grob)
        ),
    key = list(
        x = 1,
        y = -0.028,
        text = list(
            lab = c('Sex')
            ),
        padding.text = 1
        ),
    xlab.axis.padding = 5,
    bottom.padding = 4,
    description = 'Barplot created by BoutrosLab.plotting.general',
    resolution = 200
    );
image

Btw this covariate example is also broken on the vignette image

stefaneng commented 1 year ago

@lydiayliu Do you want the xlab.label between the plot and the covariate like this:

image

or under the covariates like this:

image

Both options should be eventually possible but asking to provide a workaround for your specific problem.

lydiayliu commented 1 year ago

I would prefer the latter for my current applications, but you are right it would be ideal to offer both options!

I tried adding a separate key (like how Sex is added) to use as the xlab label, but wasn't able to get the font right... If you could advice on that it would be great as well XD

stefaneng commented 1 year ago

@lydiayliu Here is a workaround using multipanelplot and textGrob. You might need to mess with the options (plot.objects.heights, y in textGrob, etc) to align the label the way that you want. You can change any of the text option you want in the gp = gpar(...) argument to textGrob.

library(BoutrosLab.plotting.general)

# set up the data
total.counts <- apply(SNV[1:15], 2, function(x){ mutation.count <- (30 - sum(is.na(x)))});
count.nonsyn <- function(x){
    mutation.count <- length(which(x == 1));
    }
nonsynonymous.SNV <- apply(SNV[1:15], 2, count.nonsyn);
other.mutations <- total.counts - nonsynonymous.SNV;

# subset the first fifteen samples
barplot.data <- data.frame(
    samples = rep(1:15, 2),
    mutation = c(rep('nonsynonymous', 15), rep('other',15)),
    type = c(rep(1, 15), rep(2,15)),
    values = c(nonsynonymous.SNV, other.mutations),
    sex = rep(patient$sex[1:15], 2),
    stage = rep(patient$stage[1:15], 2),
    msi = rep(patient$msi[1:15], 2)
    );

# set covariate colour schemes
covariate.colours.sex <- as.character(barplot.data$sex);
covariate.colours.sex[covariate.colours.sex == 'male'] <- 'dodgerblue';
covariate.colours.sex[covariate.colours.sex == 'female'] <- 'pink';

covariate.colours.stage <- as.character(barplot.data$stage);
covariate.colours.stage[covariate.colours.stage == 'I'] <- 'plum1';
covariate.colours.stage[covariate.colours.stage == 'II'] <- 'orchid1';
covariate.colours.stage[covariate.colours.stage == 'III'] <- 'orchid3';
covariate.colours.stage[covariate.colours.stage == 'IV'] <- 'orchid4';

covariate.colours.msi <- as.character(barplot.data$msi);
covariate.colours.msi[covariate.colours.msi == 'MSS'] <- 'chartreuse4';
covariate.colours.msi[covariate.colours.msi == 'MSI-High'] <- 'chartreuse2';

# create object to draw covariates
covariates.object <- list(
    rect = list(
        col = 'white',
        fill = covariate.colours.sex,
        lwd = 1.5
        )
    );

# see BoutrosLab.plotting.general::covariates.grob() for more information
covariate.object.grob <- covariates.grob(
    covariates = covariates.object,
    ord = c(1:15),
    side = 'top',
    size = 0.8
    );

# Create legend to explain covariates
covariates.legends <- list(
    legend = list(
        colours = c('dodgerblue','pink'),
        labels = c('male','female'),
        title = 'Sex',
        border = 'white'
        )
    );

# see BoutrosLab.plotting.general::legend.grob() for more information
covariate.legend.grob <- legend.grob(
    legends = covariates.legends,
    title.just = 'left'
    );

xlab.label <- textGrob(
    label = 'Test Label',
    y = 0,
    gp = gpar(
        fontface = 'bold',
        cex = 1
        )
    );
my.barplot <- create.barplot(
    # filename = tempfile(pattern = 'Barplot_Covariates', fileext = '.tiff'),
    formula = values ~ samples,
    data = barplot.data[barplot.data$mutation == 'nonsynonymous',],
    main = 'Covariates',
    ylab.lab = 'Mutations',
    ylimits = c(0,30),
    yat = seq(0,30,5),
    yaxis.cex = 1,
    xlab.label = NULL,
    xlab.cex = 1.5,
    ylab.cex = 1.5,
    yaxis.fontface = 1,
    # removing x-axis formatting to give space to covariates
    xaxis.tck = 0,
    xaxis.lab = rep('',15),
    xaxis.cex = 0,
    # covariates
    legend = list(
        bottom = list(fun = covariate.object.grob),
        right = list(fun = covariate.legend.grob)
        ),
    key = list(
        x = 1,
        y = -0.028,
        text = list(
            lab = c('Sex')
            ),
        padding.text = 1
        ),
#    xlab.axis.padding = 5,
#    bottom.padding = 4,
    description = 'Barplot created by BoutrosLab.plotting.general',
    resolution = 200
    )

create.multipanelplot(
    plot.objects = list(my.barplot, xlab.label),
    plot.objects.heights = c(8, 0.3),
    layout.width = 1,
    layout.height = 2
    )

Created on 2023-01-12 with reprex v2.0.2

lydiayliu commented 1 year ago

Wow. A multipanelplot for the label itself, that's so innovative! It's cool to see XD

But if I were to use a multipanelplot I would have just made the covariate bar separately as a heatmap lol. Thank you so much for this tip!

stefaneng commented 1 year ago

But if I were to use a multipanelplot I would have just made the covariate bar separately as a heatmap lol.

Good point 😅 Probably the most natural solution would be to do multipanel plot with barplot, covariate heatmap with an x-axis label. The adding textGrob trick is useful for other situations where you want to add text sections to multipanelplots.