#' Quick plot various type of data.
#'
#' QuickPlot automatically select proper plotting functions according to the type
#' of data and arguments provided. You can always try QuickPlot first if you don't
#' know how to plot or what plotting function to use before consulting manual.
#'
#' When plotting an abf object, the type of generated plot is determined by this
#' logic: 1. Whether the abf object has only one channel, if so, a channel plot is
#' generated. 2. Whether time_unit is given, if so, plot all channels and convert
#' x axis to time_unit. 3. Whether the abf object has only one episode, if so, a
#' channel plot of time unit "tick" is generated.
#'
#' @param data data to plot, QuickPlot will try its best to figure out how to plot.
#' @param pos positions to sample and calculate values, can be interval or cursor.
#' @param intv interval compatible with PlotChannel(), also used to sample and
#' calculate values.
#' @param cursor cursor compatible with PlotChannel(), also used to sample and
#' calculate values.
#' @param time_unit unit of time.
#' @param colour whether to plot in colour mode.
#' @param title OPTIONAL, title for the plot.
#' @param legend_title OPTIONAL, legend title for the plot.
#' @param zero_intercept whether to add zero intercepts.
#' @param zero_axes whether to force position axes at 0.
#' @param line_size size of lines.
#' @param marker_size size of markers, not used when plotting abf objects.
#' @param err_bar_size size of error bars, not used when plotting abf objects.
#' @param err_bar_width width of error bars, not used when plotting abf objects.
#' @param ... not used.
#'
#' @return a ggplot object
#' @export
#'
QuickPlot <- function(data, ...) {
UseMethod("QuickPlot", data)
}
#' @rdname QuickPlot
#' @export
#'
QuickPlot.default <- function(data, ...) {
err_quick_plot()
}
#' @rdname QuickPlot
#' @export
#'
#' @method QuickPlot abf
#'
QuickPlot.abf <- function(abf, pos = NULL, intv = NULL, cursor = NULL, time_unit = NULL,
colour = FALSE, title = NULL, legend_title = NULL,
zero_intercept = TRUE, zero_axes = TRUE,
line_size = 0.5) {
if (is.null(time_unit)) {
if (nChan(abf) == 1L || nEpi(abf) == 1L) {
#time_unit is not defined, but only one channel/episode,
#only time series is possible
p <- PeekAllChannel(abf, intv = intv, cursor = cursor, colour = colour,
auto_zoom = TRUE)
} else {
abf <- list(abf)
#parse pos
#TODO: potential performance implication
if (!is.null(pos)) {
pos <- MaskIntv(pos)
}
if (!is.null(intv)) {
pos <- c(pos, MaskIntv(intv))
}
if (!is.null(cursor)) {
pos <- c(pos, cursor)
}
pos <- unique(pos)
p <- QuickPlot.list(abf, pos = pos, colour = colour,
title = title, legend_title = legend_title,
zero_intercept = zero_intercept, zero_axes = zero_axes,
line_size = line_size)
}
} else {
if (!is.null(pos)) {
warning("Argument pos is ignored. Please use intv or cursor for time series plots.")
}
#time_unit is explicitly defined, plot time series.
p <- PeekAllChannel(abf, intv = intv, cursor = cursor, colour = colour,
time_unit = time_unit, auto_zoom = TRUE)
}
p
}
#' @rdname QuickPlot
#' @export
#'
QuickPlot.matrix <- function(data, ...) {
QuickPlot(as.data.frame(data), ...)
}
#' @rdname QuickPlot
#' @export
#'
#' @method QuickPlot data.frame
#'
QuickPlot.data.frame <- function(df, colour = FALSE, ...) {
df <- list(df)
QuickPlot.list(df, colour = colour, ...)
}
#' @rdname QuickPlot
#' @export
#'
#' @method QuickPlot list
#'
QuickPlot.list <- function(data, pos = NULL, colour = TRUE,
title = NULL, legend_title = NULL,
zero_intercept = TRUE, zero_axes = TRUE,
line_size = 0.5, marker_size = line_size * 4,
err_bar_size = line_size / 1.75,
err_bar_width = marker_size * 1.25,
smooth = FALSE) {
#whether column id is present in data
id_present <- FALSE
#Data
if (IsListOf(data, "abf")) {
pos <- ExpandList(pos, data)
if (is.null(pos)) {
err_assert_len(pos, data)
}
plt_data <- list()
for (i in seq_along(data)) {
abf <- data[[i]]
intv <- pos[[i]]
plt_data[[GetTitle(abf)]] <- ParseDataFrameIV(mean(abf, intv = intv))
}
#Extract unit information from first abf object
chan_v <- GetFirstVoltageChan(data)
chan_c <- GetFirstCurrentChan(data)
chan_label <- DefaultChanLabel(data[[1]])
x_label <- chan_label[chan_v]
y_label <- chan_label[chan_c]
} else if (IsListOf(data, "data.frame") || IsListOf(data, "matrix")) {
id_present <- all(sapply(data, function(x) "id" %in% colnames(x)))
plt_data <- lapply(data, ParseDataFrameIV, has_id = id_present)
for (i in seq_along(plt_data)) {
if (all(is.na(plt_data[[i]]$Voltage))) {
err_quick_plot("No voltage data found.")
}
if (all(is.na(plt_data[[i]]$Current))) {
err_quick_plot("No voltage data found.")
}
}
if (!id_present) {
plt_data <- EnforceListNames(plt_data)
}
chan_desc <- attr(data[[1]], "ChannelDesc")
chan_unit <- attr(data[[1]], "ChannelUnit")
if (is.null(chan_desc) || is.null(chan_unit)) {
#We do not have unit information in this case
x_label <- "V"
y_label <- "I"
} else {
vol_id <- FirstElement(which(IsVoltageUnit(chan_unit)))
cur_id <- FirstElement(which(IsCurrentUnit(chan_unit)))
vol_desc <- chan_desc[vol_id]
vol_unit <- chan_unit[vol_id]
cur_desc <- chan_desc[cur_id]
cur_unit <- chan_unit[cur_id]
x_label <- GetAxisLabel(vol_desc, vol_unit, style = "%s (%s)")
y_label <- GetAxisLabel(cur_desc, cur_unit, style = "%s (%s)")
}
} else {
err_quick_plot("Element type not supported.")
}
#row bind data
if (id_present) {
df <- do.call(rbind, plt_data)
} else {
df <- BindDataFrameList(plt_data)
}
err_bar <- any(!is.na(df$SEMC))
#Mapping
if (colour) {
if (err_bar) {
p <- ggplot(df, aes(x = Voltage, y = Current, colour = id, shape = id))
} else {
p <- ggplot(df, aes(x = Voltage, y = Current, colour = id))
}
} else {
if (err_bar) {
p <- ggplot(df, aes(x = Voltage, y = Current, group = id, shape = id))
} else {
p <- ggplot(df, aes(x = Voltage, y = Current, group = id))
}
}
#Plotting
#plot lines
if (smooth) {
nsp <- Inf
for (elem in plt_data) {
tmp <- nrow(elem)
nsp <- min(tmp, nsp)
}
nsp <- nsp - 1L
#workaround for single smoothline coloured blue
n <- length(plt_data)
if (n == 1L) {
p <- p + geom_smooth(size = line_size, se = FALSE, colour = "Black",
method = "lm", formula = y ~ splines::bs(x, nsp))
} else {
p <- p + geom_smooth(size = line_size, se = FALSE,
method = "lm", formula = y ~ splines::bs(x, nsp))
}
} else {
p <- p + geom_line(size = line_size)
}
#plot error bars
if (err_bar) {
#SEM Current is available
p <- p +
geom_point(size = marker_size) +
geom_errorbar(aes(ymin = Current - SEMC, ymax = Current + SEMC),
size = err_bar_size, width = err_bar_width)
}
#plot axes
p <- p + theme_classic()
if (zero_axes) {
p <- p + ZeroAxes2(xlimit = df$Voltage, ylimit = df$Current,
xlabel = x_label, ylabel = y_label)
} else {
p <- p +
geom_vline(xintercept = 0, linetype = "dashed") +
geom_hline(yintercept = 0, linetype = "dashed") +
xlab(x_label) +
ylab(y_label)
}
#plot titles
if (!is.null(title)) {
p <- p + ggtitle(as.character(title))
}
if (is.null(legend_title)) {
p <- p + theme(legend.title = element_blank())
} else {
p <- p + labs(colour = as.character(legend_title),
shape = as.character(legend_title),
group = as.character(legend_title))
}
#remove legend if only one item
if (!id_present && length(plt_data) == 1L) {
p <- p + theme(legend.position = "none")
}
p
}
#' Quick plot I-V curves at given position
#'
#' @param abf an abf or a list of abf objects.
#' @param pos an interval/cursor or a list of intervals/cursors.
#' @param colour whether to plot in coloured mode.
#' @param title OPTIONAL, title for the plot.
#' @param legend_title OPTIONAL, title of the legend.
#' @param zero_intercept whether to add zero intercepts to the plot.
#' @param zero_axes whether to plot axes at 0.
#' @param line_size size of lines
#'
#' @return a ggplot object.
#' @export
#'
QuickPlotIV <- function(abf, pos, colour = FALSE, title = NULL, legend_title = NULL,
zero_intercept = TRUE, zero_axes = TRUE, line_size = 0.5) {
if (!IsAbf(abf) && !IsAbfList(abf)) {
err_class_abf()
}
current_channel <- GetFirstCurrentChan(abf)
voltage_channel <- GetFirstVoltageChan(abf)
if (IsAbf(abf)) {
labs <- DefaultChanLabel(abf)
} else {
labs <- DefaultChanLabel(abf[[1]])
}
melted <- MeltAbfChannel(abf, channel = c(voltage_channel, current_channel),
intv = pos, epi_id_func = NULL)
cname <- colnames(melted)
xcol <- as.name(cname[2L])
ycol <- as.name(cname[3L])
p <- ggplot(melted, aes_string(x = xcol, y = ycol)) + theme_classic()
if (colour) {
p <- p + geom_line(aes_string(colour = "id"), size = line_size)
if (is.null(legend_title)) {
p <- p + theme(legend.title = element_blank())
} else {
p <- p + labs(`colour` = as.character(legend_title))
}
} else {
p <- p + geom_line(aes_string(group = "id"), size = line_size)
}
#Add zero intercepts
if (!zero_axes && zero_intercept) {
p <- p + geom_vline(xintercept = 0, linetype = "dashed") +
geom_hline(yintercept = 0, linetype = "dashed")
}
if (zero_axes) {
p <- p + ZeroAxes2(xlimit = melted[, 2], ylimit = melted[, 3],
xlabel = labs[voltage_channel], ylabel = labs[current_channel])
}
#Get rid of ``
p <- p + xlab(as.character(xcol)) + ylab(as.character(ycol))
if (!is.null(title)) {
p <- p + ggtitle(title)
}
return(p)
}
#' Quick plot trace vs. trace curve.
#'
#' @param abf an abf object.
#' @param channelX channel of X trace.
#' @param episodeX episode of X trace.
#' @param channelY channel of Y trace.
#' @param episodeY channel of Y trace.
#' @param intv interval of the traces to be plotted.
#'
#' @return a ggplot object.
#' @export
#'
QuickPlotTrace <- function(abf, channelX, episodeX, channelY, episodeY, intv) {
if (!IsAbf(abf)) {
err_class_abf()
}
if (!AssertChannel(abf, channelX) || !AssertChannel(abf, channelY)) {
err_channel()
}
if (!AssertEpisode(abf, episodeX) || !AssertEpisode(abf, episodeY)) {
err_epi()
}
chX <- abf[[channelX]]
chY <- abf[[channelY]]
mask <- intv[1]:intv[2]
traceX <- chX[mask, episodeX]
traceY <- chY[mask, episodeY]
qplot(x = traceX, y = traceY, geom = "point") + theme_bw()
}
#' Quick plot an IV Summary table
#'
#' @param df_summary an IV summary table from IVSummary()
#' @param title OPTIONAL, title of the plot
#' @param legend_title OPTIONAL, if multiple IV summaries are to plot, title of the legend.
#' @param zero_intercept whether to add zero intercepts to the plot.
#' @param zero_axes whether to plot axes at 0.
#' @param line_size size of lines
#' @param marker_size size of markers
#' @param err_bar_size size of error bar
#' @param err_bar_width width of error bar
#'
#' @return a ggplot object.
#' @export
#'
QuickPlot_IVSummary <- function(df_summary, title = NULL, legend_title = NULL,
zero_intercept = TRUE, zero_axes = TRUE,
line_size = 0.5, marker_size = line_size * 4,
err_bar_size = line_size / 1.5,
err_bar_width = marker_size * 1.5) {
if (class(df_summary) == "data.frame") {
colnames(df_summary) <- c("Voltage", "SEMV", "Current", "SEMC")
p <- ggplot(data = df_summary, mapping = aes(x = Voltage, y = Current))
p <- p + geom_line(size = line_size)
p <- p + geom_errorbar(mapping = aes(ymin = Current - SEMC, ymax = Current + SEMC),
size = err_bar_size, width = err_bar_width)
p <- p + geom_point(size = marker_size)
if (!zero_axes && zero_intercept) {
p <- p + geom_vline(xintercept = 0, linetype = "dashed") +
geom_hline(yintercept = 0, linetype = "dashed")
}
if (!is.null(title)) {
p <- p + ggtitle(title)
}
p <- p + theme_classic()
if (zero_axes) {
p <- p + ZeroAxes2(xlimit = df_summary[, 1], ylimit = df_summary[, 3],
xlabel = "Voltage", ylabel = "Current")
}
return(p)
} else {
df_melted <- NULL
for (i in seq_along(df_summary)) {
df <- cbind(names(df_summary)[i], df_summary[[i]])
colnames(df)[1] <- "id"
df_melted <- rbind(df_melted, df)
}
colnames(df_melted) <- c("id", "Voltage", "SEMV", "Current", "SEMC")
p <- ggplot(data = df_melted, mapping = aes(x = Voltage, y = Current,
colour = id, shape = id))
p <- p + geom_line(size = line_size)
p <- p + geom_errorbar(mapping = aes(ymin = Current - SEMC, ymax = Current + SEMC),
size = err_bar_size, width = err_bar_width)
p <- p + geom_point(size = marker_size)
if (!zero_axes && zero_intercept) {
p <- p + geom_vline(xintercept = 0, linetype = "dashed") +
geom_hline(yintercept = 0, linetype = "dashed")
}
p <- p + theme_classic()
if (is.null(legend_title)) {
p <- p + theme(legend.title = element_blank())
} else {
p <- p + labs(colour = as.character(legend_title),
shape = as.character(legend_title))
}
if (!is.null(title)) {
p <- p + ggtitle(title)
}
if (zero_axes) {
p <- p + ZeroAxes2(xlimit = df_melted[, 2], ylimit = df_melted[, 4],
xlabel = "Voltage", ylabel = "Current")
}
return(p)
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.