get_data_plot_time_avg_power = function(wt, event=FALSE) {
## Return the data to plot the time-averaged wavelet spectrum.
## Default excludes the COI.
if(event) {
power = wt$power.corr * ifelse(wt$event_timing$mask$event, 1, NA)
} else {
power = wt$power.corr * ifelse(wt$event_timing$mask$coi, 1, NA)
}
time_avg_power = data.frame(
period=wt$period,
Period=length(wt$period):1,
Power=rowMeans(power, na.rm=TRUE)
)
if(event) {
event_cluster_count =
wt$event_timing$all[, .(event_count= uniqueN(period_clusters)), by = period]
time_avg_power = merge(time_avg_power, event_cluster_count, by='period', all.x=TRUE)
time_avg_power$event_count[which(is.na(time_avg_power$event_count))] = 0
time_avg_power$Power[which(is.nan(time_avg_power$Power))] = 0
time_avg_power = plyr::rename(time_avg_power, c('Power'='Avg Power'))
time_avg_power$`Avg over` = 'events'
} else {
time_avg_power = plyr::rename(time_avg_power, c('Power'='Avg Power'))
time_avg_power$`Avg over` = 'all'
}
time_avg_power$avg_power_values = time_avg_power$`Avg Power`
return(time_avg_power)
}
get_data_plot_power = function(wt, input_data, wt_field=NULL, event=FALSE) {
## Return the data to plot the wavelet power spectrum
## The wt_field allows an arbitray field to be combined with the
## COI and significance of a different field.
input_obs = subset(input_data, Streamflow == 'obs')
input_obs$chunk_renum = input_obs$chunk - min(input_obs$chunk) +1
input_obs = input_obs[ chunk_renum %in% unique(wt$chunk) ]
if(is.null(wt_field)) {
wps_matrix = wt$power.corr
} else {
wps_matrix = wt_field
}
rownames(wps_matrix) = length(wt$period):1
colnames(wps_matrix) = input_obs$POSIXct
wps = setNames(reshape2::melt(wps_matrix), c('Period', 'Time', 'Power'))
plot_df = wps
chunk_matrix = wps_matrix
for(pp in 1:length(wt$period)) chunk_matrix[pp,] = input_obs$chunk
chunk = setNames(reshape2::melt(chunk_matrix), c('Period', 'Time', 'chunk'))
plot_df$chunk = chunk$chunk
chunk = NULL
coi_matrix = wt$event_timing$mask$coi
rownames(coi_matrix) = 1:length(wt$period)
colnames(coi_matrix) = input_obs$POSIXct
coi = setNames(reshape2::melt(coi_matrix), c('Period', 'Time', 'COI'))
plot_df$COI = coi$COI
coi = NULL
signif_matrix = wt$event_timing$mask$signif * 1
rownames(signif_matrix) = 1:length(wt$period)
colnames(signif_matrix) = input_obs$POSIXct
signif = setNames(reshape2::melt(signif_matrix), c('Period', 'Time', 'Significance'))
plot_df$Significance = signif$Significance
signif = NULL
period_df = data.frame(Period=length(wt$period):1, period=wt$period)
plot_df = merge(plot_df, period_df, by='Period')
return(plot_df)
}
merge_data_plot = function(
...,
time_axis_len=1,
time_trans=NULL,
time_breaks=NULL,
time_label_format=NULL,
avg_power_axis_len=1/6,
avg_power_trans=NULL,
avg_power_breaks=NULL,
avg_power_label_format=NULL,
period_axis_len=1,
period_trans=NULL,
period_breaks=NULL,
period_label_format=NULL,
streamflow_axis_len=1/2,
streamflow_trans=NULL,
streamflow_breaks=NULL,
streamflow_label_format=NULL
) {
raw_data = list(...)
x_levels = c('Time', 'Avg Power', 'Event Avg Power')
y_levels = c('Period', 'Streamflow (cms)')
plot_list = list()
for(item in 1:length(raw_data)) {
plot_list[[item]] = raw_data[[item]]
for(dim in c('x', 'y')) {
dim_levels = list(x=x_levels, y=y_levels)[[dim]]
for(var_name in intersect(dim_levels, names(plot_list[[item]]) )) {
plot_list[[item]][[dim]] = plot_list[[item]][[var_name]]
plot_list[[item]][[var_name]] = NULL
plot_list[[item]][[paste0(dim,'_var')]] = factor(var_name, levels=dim_levels)
}
}
}
## Now homogenize with empty cols/vars to perform a rbind.
all_var_names = unlist(plyr::llply(plot_list, function(list) names(list)))
for(item in 1:length(raw_data)) {
for(absent_var in setdiff(all_var_names, names(plot_list[[item]]))){
plot_list[[item]][[absent_var]] = NA
}
}
plot_data = plyr::ldply(plot_list)
## -------------------------------------------------------
## What dimensions do we have?
wh_time = which(plot_data$x_var == 'Time')
wh_avg_power = which(plot_data$x_var == 'Avg Power')
wh_period = which(plot_data$y_var == 'Period')
wh_streamflow = which(plot_data$y_var == 'Streamflow (cms)')
## -------------------------------------------------------
## Axis Breaks and Labels
## x - time
if(length(wh_time)) {
use_time = if('POSIXct' %in% names(plot_data)) "POSIXct" else "x"
if(is.null(time_breaks))
time_breaks = scales::pretty_breaks()(subset(plot_data, x_var == 'Time')[[use_time]])
if(is.null(time_label_format)) {
time_labels = time_breaks
if(use_time == 'x')
time_labels = as.POSIXct(time_breaks, tz='UTC', origin=rwrfhydro::PosixOrigin())
time_labels = scales::date_format('%d %b\n%Y')(time_labels)
} else {
time_labels = time_label_format(time_breaks)
}
}
## x - avg_power
if(length(wh_avg_power)) {
if(is.null(avg_power_breaks))
avg_power_breaks =
scales::pretty_breaks()(subset(plot_data, x_var == 'Avg Power')$avg_power_values)
avg_power_labels = avg_power_breaks
if(!is.null(avg_power_label_format))
avg_power_labels = avg_power_label_format(avg_power_breaks)
}
## y - period
if(length(wh_period)) {
if(is.null(period_breaks))
period_breaks =
scales::pretty_breaks()(subset(plot_data, y_var == 'Period')$y)
## The breaks probably need rounded, or the nearest neighbor in the set needs found.
period_labels = as.character(period_breaks * NA)
plot_period = subset(plot_data, y_var == 'Period' & !is.na(period))
for(bb in 1:length(period_breaks))
period_labels[bb] =
plot_period$period[which(plot_period$y == period_breaks[bb])[1]]
## Do NOT allow transform of period?
if(is.null(period_label_format)) {
period_labels = scales::number_format()(as.numeric(period_labels))
} else {
period_labels = period_label_format(as.numeric(period_labels))
}
}
## y - streamflow
if(length(wh_streamflow)) {
if(is.null(streamflow_breaks))
streamflow_breaks =
scales::pretty_breaks()(subset(
plot_data,
y_var == 'Streamflow (cms)'
)$streamflow_values)
streamflow_labels = streamflow_breaks
if(!is.null(streamflow_label_format))
streamflow_labels = streamflow_label_format(streamflow_breaks)
}
## -------------------------------------------------------
## Transformations of axis values.
## Transform Avg Power axis:
if(!is.null(avg_power_trans)) {
plot_data$x[wh_avg_power] = avg_power_trans()$trans(plot_data$x[wh_avg_power])
avg_power_breaks = avg_power_trans()$trans(avg_power_breaks)
}
## Transform Period axis:
if(!is.null(period_trans)) {
plot_data$y[wh_period] = period_trans()$trans(plot_data$y[wh_period])
period_breaks = period_trans()$trans(period_breaks)
}
## Transform streamflow axis:
if(!is.null(streamflow_trans)) {
plot_data$y[wh_streamflow] = streamflow_trans()$trans(plot_data$y[wh_streamflow])
streamflow_breaks = streamflow_trans()$trans(streamflow_breaks)
}
## -------------------------------------------------------
## Axis scaling for relative plot sizes
## x-axis: Time vs Avg Power
if(length(wh_time) & length(wh_avg_power)) {
time_range = diff(range(plot_data$x[wh_time], na.rm=TRUE))
avg_power_range = diff(range(plot_data$x[wh_avg_power], na.rm=TRUE))
# scales::trans_new()$domain[1] is the lower-bound on transformed values.
if(!is.null(avg_power_trans))
avg_power_range =
diff(range( pmax(plot_data$x[wh_avg_power], avg_power_trans()$domain[1]) ))
## Leave the time range alone, scale the avg_power_range to be above the time range.
xform_avg_power_absc = function(data) {
max(plot_data$x[wh_time])*2 +
data *
time_range/avg_power_range * avg_power_axis_len/time_axis_len
}
plot_data$x[wh_avg_power] = xform_avg_power_absc(plot_data$x[wh_avg_power])
avg_power_breaks = xform_avg_power_absc(avg_power_breaks)
}
#stop()
## y-axis: Period vs Streamflow, Relative sizes in plot
if(length(wh_period) & length(wh_streamflow)) {
period_range = diff(range(plot_data$y[wh_period], na.rm=TRUE))
streamflow_range = diff(range(plot_data$y[wh_streamflow], na.rm=TRUE))
if(!is.null(period_trans))
period_range =
diff(range( pmax(plot_data$y[wh_period], period_trans()$domain[1]) ))
if(!is.null(streamflow_trans)) {
streamflow_range =
diff(range( pmax(plot_data$y[wh_streamflow], streamflow_trans()$domain[1]) ))
# streamflow_range = streamflow_trans()$inverse(streamflow_range)
}
## Leave the streamflow_range alone, scale the period_range to be above the time range.
xform_period_axis = function(data) {
max(plot_data$y[wh_streamflow])*3 + # This multiplier needs to be >2
data *
(streamflow_range/period_range) * (period_axis_len/streamflow_axis_len)
}
plot_data$y[wh_period] = xform_period_axis(plot_data$y[wh_period])
period_breaks = xform_period_axis(period_breaks)
}
x_breaks = as.numeric(c())
x_labels = as.character(c())
if(length(wh_time)) {
x_breaks = c(x_labels, time_breaks)
x_labels = c(x_labels, time_labels)
}
if(length(wh_avg_power)) {
x_breaks = c(x_breaks, avg_power_breaks)
x_labels = c(x_labels, avg_power_labels)
}
attr(plot_data, 'x_breaks') = x_breaks
attr(plot_data, 'x_labels') = x_labels
y_breaks = as.numeric(c())
y_labels = as.character(c())
if(length(wh_streamflow)) {
y_breaks = c(y_labels, streamflow_breaks)
y_labels = c(y_labels, streamflow_labels)
}
if(length(wh_period)) {
y_breaks = c(y_breaks, period_breaks)
y_labels = c(y_labels, period_labels)
}
attr(plot_data, 'y_breaks') = y_breaks
attr(plot_data, 'y_labels') = y_labels
return(plot_data)
}
plot_wavelet_events = function(plot_data, do_plot=TRUE, base_size=9) {
library(ggplot2)
gg = ggplot()
##-------------------------------------------------------
## Wavelet spectrum plots
subset_power = subset(plot_data, x_var == 'Time' & y_var == 'Period' & is.na(period_clusters))
if(nrow(subset_power) > 0) {
gg =
gg +
geom_raster(
data=subset_power,
aes(x=x, y=y, fill=Power),
interpolate=FALSE
) +
stat_contour(
data=subset_power,
aes(x=x, y=y, z=Significance, group=chunk),
bins=1,
color='grey40',
breaks=.5,
size=.5
) +
geom_raster(
data=subset_power,
aes(x=x, y=y, alpha=COI),
interpolate=FALSE,
fill='white'
) +
scale_fill_distiller(
palette = "Accent", #"Set3", #"Accent", #"BrBG","PiYG", #"PRGn", #"Spectral",
direction=-1,
trans='log2',
labels = scales::scientific_format(digits=2),
na.value="transparent"
) +
## Abstract this out? at lest the FALSE level.
scale_alpha_manual(values=c('TRUE'=0, 'FALSE'=.6), guide=FALSE)
}
## -------------------------------------------------------
## Input timeseries
n_timeseries = length(unique(plot_data$Streamflow))
if(n_timeseries > 1) {
subset_input = subset(plot_data, x_var=='Time' & y_var=='Streamflow (cms)')
streamflow_colors =
RColorBrewer::brewer.pal('Paired', n=3)[c(2, setdiff(1:n_timeseries,2))]
names(streamflow_colors) = c('obs', setdiff(unique(subset_input$Streamflow), 'obs'))
} else {
subset_input = subset(plot_data,
x_var=='Time' &
y_var=='Streamflow (cms)' &
Streamflow=='obs')
streamflow_colors =
RColorBrewer::brewer.pal('Paired', n=3)[2]
names(streamflow_colors) = unique(subset_input$Streamflow)
}
if(nrow(subset_input) > 0) {
gg =
gg +
geom_line(
data=subset_input,
aes(x=x, y=y, color=Streamflow),
size=1.1
) +
scale_color_manual(
values=streamflow_colors
)
}
## -------------------------------------------------------
## Time-averaged power plots
## Avg power
subset_t_avg = subset(plot_data, x_var=='Avg Power' & y_var == 'Period')
if(nrow(subset_t_avg) > 0) {
gg =
gg +
geom_path(
data=subset_t_avg,
aes(x=x, y=y, linetype=`Avg over`)
) +
scale_linetype_discrete(name="Time avg over")
## Event power
##geom_path(data=subset(plot_data, x_var=='Event Avg Power'),
## aes(x=x, y=y)) + #, size=event_count)) +
##geom_point(data=subset(data, x_var=='Event Avg Power'),
## aes(x=x, y=y, shape=as.factor(event_count))) +
}
## -------------------------------------------------------
## Plot layout/style
##my_breaks = function(x) { if (max(x) < 6000) seq(0, 5000, 1000) else seq(0, 15000, 5000) }
x_breaks = as.numeric(attr(plot_data, 'x_breaks'))
x_labels = attr(plot_data, 'x_labels')
y_breaks = as.numeric(attr(plot_data, 'y_breaks'))
y_labels = attr(plot_data, 'y_labels')
gg =
gg +
facet_grid(y_var ~ x_var, scales='free', space='free', switch='y') +
scale_y_continuous(
expand = c(0, 0),
position = "right",
breaks=y_breaks,
labels=y_labels
) +
scale_x_continuous(
expand = c(0, 0),
breaks=x_breaks,
labels=x_labels
) +
theme_bw(base_size=base_size) +
theme(
legend.position="left",
##legend.key.height=unit(3, "line"),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.spacing = unit(.25, "lines"),
strip.background = element_rect(fill = 'grey90')
)
## handle the grob... only if plotting.
## extract this as a useful funciton
if(
do_plot &
nrow(subset_power) > 0 &
nrow(subset_input) > 0 &
nrow(subset_t_avg) > 0
) {
## https://stackoverflow.com/questions/49521848/remove-unused-facet-combinations-in-2-way-facet-grid
suppressMessages(library(grid))
suppressMessages(library(gtable))
grob = ggplotGrob(gg)
## remove lower right panel
idx = which(grob$layout$name %in% c("panel-2-2"))
for (i in idx) grob$grobs[[i]] = nullGrob()
## move x-axis on right panels up one panel
idx = which(grob$layout$name %in% c("axis-b-2"))
grob$layout[idx, c("t", "b")] = grob$layout[idx, c("t", "b")] - c(2, 1)
## move the y-axis on the lower right panel left one panel
idx = which(grob$layout$name %in% c("axis-r-2"))
grob$layout[idx, c("l", "r")] = grob$layout[idx, c("l", "r")] - c(1.1, 1.1)
#grid.newpage()
grid.draw(grob)
return(invisible(grob))
} else {
if(do_plot) print(gg)
return(invisible(gg))
}
}
facet_grob_adj = function(gg,
del=NULL,
adj=NULL) {
## Del is a vector of grob$layout$names to delete.
## adj is a named list in grob$layout$name names each containing a
## list with 2 vectors, positions and values.
suppressMessages(library(grid))
suppressMessages(library(gtable))
if(!('grob' %in% class(gg))) {
grob = ggplotGrob(gg)
} else {
grob = gg
}
if(!is.null(del)) {
for(to_del in del) {
idx = which(grob$layout$name %in% to_del)
for (i in idx) grob$grobs[[i]] = nullGrob()
}
}
if(!is.null(adj)) {
for(the_name in names(adj)) {
to_adj = adj[[the_name]]
idx = which(grob$layout$name %in% the_name)
grob$layout[idx, to_adj$position] =
grob$layout[idx, to_adj$position] + to_adj$values
}
}
return(invisible(grob))
}
cluster_palette = function(brewer_pal="Accent") {
pal6 = RColorBrewer::brewer.pal(name=brewer_pal, n=6)
return(colorRampPalette(pal6, space='Lab'))
}
##' @export
step1_figure = function(wt_event, cluster_maxima=FALSE) {
library(dplyr)
library(ggplot2)
library(relayer) ## git hash 8a1d49e1707d9fcc1aaa83476a3d9a15448a1065
library(ggplotify)
obs_power = get_data_plot_power(wt_event$obs$wt, wt_event$input_data)
obs_t_avg_power = get_data_plot_time_avg_power(wt_event$obs$wt)
obs_event_t_avg_power = get_data_plot_time_avg_power(wt_event$obs$wt, event=TRUE)
## Should include the ar1 spectrum
## Data to plot the maxima on the time-avg spectra with this dataframe
event_t_avg_max_data = wt_event$obs$wt$event_timing$time_avg[local_max == TRUE,]
setnames(event_t_avg_max_data, 'power_corr', 'Avg Power')
event_t_avg_max_data = merge(
event_t_avg_max_data,
obs_event_t_avg_power[, c('period', 'Period', 'Avg over')],
by=c('period'),
all.x=TRUE, all.y=FALSE
)
# =============================================================================
## Plot the cluster numbers
max_periods = wt_event$obs$wt$event_timing$time_avg[local_max == TRUE]$period
max_period_clusters = wt_event$obs$wt$event_timing$all[ period %in% max_periods ]
event_t_avg_max_period_clusters = merge(
max_period_clusters,
wt_event$input_data[ Streamflow == 'obs', c('Time', 'input_index', 'POSIXct')],
by.x='time',
by.y='input_index',
all.x=TRUE, all.y=FALSE
)
event_t_avg_max_period_clusters$time = NULL
event_t_avg_max_period_clusters = merge(
event_t_avg_max_period_clusters,
obs_power[, c('period', 'Time', 'Period')],
by=c('period', 'Time'),
all.x=TRUE, all.y=FALSE
)
## Have to include the y-limits or it will be squashed and have to sample
## all the raster coordinates to build the raster.
minmax = as.data.table(obs_power)[
period == min(period) | period == max(period) | Time == min(Time)
]
## hmmmm.... is it guaranteed that the min(Time) is all in the COI?
minmax = minmax[, period_clusters := as.integer(-1) ]
event_t_avg_max_period_clusters = merge(
event_t_avg_max_period_clusters,
minmax[, c('period', 'Time', 'period_clusters', 'Period')],
by=c('period', 'Time', 'period_clusters', 'Period'),
all.x=TRUE, all.y=TRUE
)
plot_data =
merge_data_plot(
subset(wt_event$input_data, Streamflow=='obs'),
obs_power,
event_t_avg_max_period_clusters,
obs_t_avg_power,
obs_event_t_avg_power,
event_t_avg_max_data,
avg_power_axis_len=1/5,
avg_power_breaks=c(10000, 100000),
avg_power_label_format=scales::scientific_format(digits=0),
##avg_power_breaks = c(1e2, 1e3, 1e4, 1e5),
##avg_power_trans = scales::log10_trans,
streamflow_axis_len=2/3
#streamflow_breaks=c(.1,1,10,100,1000),
#streamflow_trans=scales::log2_trans
## avg_power_axis_trans=scales::log10_trans
)
## Add a new vertical facet for showing the "event cluster"
new_y_levels = c('Streamflow (cms)', 'Period', 'c Period', 'd Period')
new_y_labels = c('Streamflow (cms)', 'Timescale', 'Timescale', 'Timescale')
y_labeller = function(string) {
labs = new_y_labels
names(labs) = new_y_levels
labs[string]
}
## Copy the data (same fill values, different mask) for the new
## plot, showing the event cluster.
wt_copy = subset(plot_data, x_var == 'Time' & y_var == 'Period')
wt_copy$y_var = ordered("c Period", levels=new_y_levels)
wt_copy$Power[which(wt_copy$COI == FALSE | wt_copy$Significance == 0)] = NA
## Transform the factor levels on the original data.
plot_data$y_var = ordered(plot_data$y_var, levels=new_y_levels)
plot_data$y_var[which(!is.na(plot_data$period_clusters))] =
ordered("d Period", levels=new_y_levels)
plot_data$period_clusters[which(plot_data$period_clusters < 0)] = NA
## Put the event spectrum on the new axis.
wh_events = which(plot_data$`Avg over` == 'events')
plot_data$y_var[wh_events]= ordered(new_y_levels[3], levels=new_y_levels)
## Merge the new and old data.
pd = rbind(plot_data, wt_copy)
## Get the standard plot
gg = plot_wavelet_events(pd, do_plot=FALSE)
## Extend the standard plot.
## Use annotations for units labels on the y-axes.
plot_data = as.data.table(plot_data)
y_labs =
plot_data[,
.(y_center=min(y, na.rm=TRUE)+.5*(max(y, na.rm=TRUE)-min(y, na.rm=TRUE)),
x_loc=.1*(max(x, na.rm=TRUE)-min(x, na.rm=TRUE))+max(x, na.rm=TRUE)
),
by=c('y_var', 'x_var')
]
y_labs = subset(y_labs, x_var == 'Avg Power' | y_var == 'Streamflow (cms)')
relab = c(
`c Period`="Timescale (hours)",
`Period`='Timescale (hours)',
`Streamflow (cms)`='Streamflow (cms)'
)
y_labs$lab = relab[y_labs$y_var]
## Use the facet titles/labels to enumerate the steps in the process.
new_y_levels =
c('Streamflow (cms)', 'Period', 'c Period', 'TimePer', 'Time', 'd Period')
new_y_labels =
c('a. Timeseries', 'b. Obs WT', 'c. Obs WT Events', 'd. Timing Errors', '', 'd. Timescale Clusters')
the_labeller = function(string) {
labs = new_y_labels
names(labs) = new_y_levels
labs[string]
}
clust_numbers = sort(as.integer(setdiff(plot_data$period_clusters, "None")))
clust_fill_colors = c(NA, cluster_palette()(length(clust_numbers)))
names(clust_fill_colors) = c('None', clust_numbers)
shape_color = 'grey80'
gg2 =
gg +
geom_raster(
data=subset(pd, y_var == new_y_levels[3] & is.na(period_clusters)),
aes(x=x, y=y, fill=Power),
interpolate=FALSE,
na.rm=TRUE
) +
geom_path(
data=subset(plot_data, y_var == new_y_levels[3] & is.na(local_max)),
aes(x=x, y=y, linetype=`Avg over`)
) +
geom_point(
data=subset(plot_data, local_max == TRUE),
aes(x=x, y=y, shape="Time Avg\nEvent Power"),
color=shape_color
) +
geom_raster(
data=subset(plot_data, y_var == new_y_levels[6]), # & !is.na(period_clusters)),
aes(x=x, y=y, fill_cluster=factor(period_clusters)),
interpolate=FALSE, na.rm=FALSE
) %>% rename_geom_aes(new_aes = c("fill" = "fill_cluster"))
if(cluster_maxima) {
we_stats = we_hydro_stats(wt_event)
max_stats = we_stats[[1]]$xwt$event_timing$cluster_max
max_stats$x_var = factor('Time', levels=levels(plot_data$x_var))
max_stats$y_var = ordered('d Period', levels=new_y_levels)
max_stats$x = min(plot_data$x, na.rm=TRUE) + 3600*(max_stats$time)
period_y_cols = c('y', 'period')
period_y_map = unique(plot_data[ y_var =='d Period', ..period_y_cols ])
max_stats = merge(max_stats, period_y_map, by='period')
gg2 = gg2 +
geom_point(
data=max_stats,
aes(x=x, y=y, shape='Cluster'),
color=shape_color,
size=2) +
scale_shape_manual(
values=c('Time Avg\nEvent Power'=19, 'Cluster'=8),
name='Maxima')
}
if(cluster_maxima) {
gg2 = gg2 +
guides(
color = guide_legend(order = 1),
fill = guide_colorbar(order = 2),
linetype = guide_legend(order=3),
shape = guide_legend(order=4))
} else {
gg2 = gg2 +
guides(
color = guide_legend(order = 1),
fill = guide_colorbar(order = 2),
linetype = guide_legend(order=3),
shape = FALSE)
}
gg2 = gg2 +
facet_grid(
y_var ~ x_var,
labeller = labeller(y_var=y_labeller),
scales='free',
space='free',
switch='y'
) +
scale_fill_distiller(
aesthetics = "fill", guide = "legend",
palette = "Spectral", #Accent", #"Set3", #"Accent", #"BrBG","PiYG", #"PRGn"
##direction=-1,
##trans='log2',
labels = scales::scientific_format(digits=2),
na.value="transparent"
) +
scale_fill_manual(
name='Cluster Number',
aesthetics="fill_cluster",
guide="legend",
##palette=cluster_palette(),
values=clust_fill_colors,
na.translate=FALSE,
na.value="transparent"
) +
theme(legend.title=element_text(size=rel(0.8)))
## Deal with the unused bits.
## daGrob = ggplotGrob(gg2)
## gtable::gtable_show_layout(daGrob)
## daGrob
grob = facet_grob_adj(
gg2,
del=c("panel-2-4", "panel-1-3"),
adj=list(
`axis-r-1`=list(
position=c('l', 'r'),
values=c(-1.1, -1.1)
),
`axis-r-4`=list(
position=c('l', 'r'),
values=c(-1.1, -1.1)
) ,
`strip-t-2`=list(
position=c('t', 'b'),
values=(c(0, 0) + 2)
),
`axis-b-2`=list(
position=c('t', 'b'),
values=(c(0, 0) - 2)
)
)
)
text_color = 'grey30'
text_size = 11
text_grob_1 = grid.text(
'Streamflow (cms)', x=-1.25, y=.6, hjust=.50, vjust=-3.5, rot=-90,
gp=gpar(col=text_color, fontsize=text_size))
## size = rel(0.8), colour = "grey30"
t = unique(grob$layout[grepl("panel-1-1",grob$layout$name), "t"])
l = unique(grob$layout[grepl("panel-1-1",grob$layout$name), "l"])
g = gtable::gtable_add_grob(grob, grobs=text_grob_1, t=t, l=l+1, clip='off')
text_grob_4 = grid.text(
'Timescale (hours)', x=0, y=.5, hjust=.5, vjust=-3.5, rot=-90,
gp=gpar(col=text_color, fontsize=text_size) )
t = unique(grob$layout[grepl("panel-2-2",grob$layout$name), "t"])
l = unique(grob$layout[grepl("panel-2-2",grob$layout$name), "l"])
g = gtable::gtable_add_grob(g, grobs=text_grob_4, t=t, l=l+1, clip='off')
## Insert a new column for labels
g = gtable::gtable_add_cols(g, grid::unit(1,"line"), pos = -1)
text_grob_2 = grid.text(
'Timescale (hours)', x=0, y=.5, hjust=.5, vjust=.5, rot=-90,
gp=gpar(col=text_color, fontsize=text_size))
t = unique(grob$layout[grepl("panel-2-1",grob$layout$name), "t"])
g = gtable::gtable_add_grob(g, grobs=text_grob_2, t=t, l=ncol(g), clip='off')
text_grob_3 = grid.text(
'Timescale (hours)', x=0, y=.5, hjust=.5, vjust=.5, rot=-90,
gp=gpar(col=text_color, fontsize=text_size))
t = unique(grob$layout[grepl("panel-1-4",grob$layout$name), "t"])
g = gtable::gtable_add_grob(g, grobs=text_grob_3, t=t, l=ncol(g), clip='off')
return(as.ggplot(g))
}
##' @export
step2_figure = function(
wt_event,
n_phase_along_x=70,
base_size=9,
ylab_spacer=.035,
cluster_maxima=FALSE) {
library(dplyr)
library(ggplot2)
library(relayer) ## git hash 8a1d49e1707d9fcc1aaa83476a3d9a15448a1065
library(ggplotify)
## Currently this is only configured to handle a single modeled timeseries.
model_name = setdiff(names(wt_event), c("input_data", "obs"))
if(length(model_name) > 1)
stop('Currently this is only configured to handle a single modeled timeseries.')
wt_power = get_data_plot_power(wt_event$obs$wt, wt_event$input_data)
xwt_power = get_data_plot_power(wt_event[[model_name]]$xwt, wt_event$input_data)
## Sub phase for power...
xwt_phase = get_data_plot_power(
wt_event[[model_name]]$xwt,
wt_event$input_data,
wt_field=wt_event[[model_name]]$xwt$phase
)
## Timing is associate with the obs COI/signif
xwt_timing = get_data_plot_power(
wt_event$obs$wt,
wt_event$input_data,
wt_field=wt_event[[model_name]]$xwt$event_timing$mtx$timing_err
)
## Restructuring for plotting, these cant be merged because the all have the same Period
## axis. So do them individually with the input, remove the input, rename the y-axis, and
## combine.
streamflow_axis_len = .5
wt_data = merge_data_plot(
wt_event$input_data,
wt_power,
streamflow_axis_len=streamflow_axis_len,
streamflow_breaks=c(.1,1,10,100,1000),
streamflow_trans=scales::log2_trans
)
xwt_data = merge_data_plot(
wt_event$input_data,
xwt_power,
streamflow_axis_len=streamflow_axis_len,
streamflow_trans=scales::log2_trans
)
xwt_phase_data = merge_data_plot(
wt_event$input_data,
xwt_phase,
streamflow_axis_len=streamflow_axis_len,
streamflow_trans=scales::log2_trans
)
timing_data = merge_data_plot(
wt_event$input_data,
xwt_timing,
streamflow_axis_len=streamflow_axis_len,
streamflow_trans=scales::log2_trans
)
the_attributes = attributes(wt_data)
wt_data = subset(wt_data, y_var == 'Streamflow (cms)')
xwt_data = subset(xwt_data, y_var == 'Period')
xwt_phase_data = subset(xwt_phase_data, y_var == 'Period')
timing_data = subset(timing_data, y_var == 'Period')
xwt_data$phase = xwt_phase_data$Power
## Subsample the xwt_phase_data for plotting
## This one is gridded, easy selection to even indices.
periods_rm = sort(unique(xwt_phase_data$y))[c(TRUE, TRUE, FALSE)]
## This one is not necessarily gridded. Convert to hours.
times = sort(unique(xwt_phase_data$x))/3600
mod_by = length(times) %/% n_phase_along_x
times_rm = times[(times %% mod_by) != 0]*3600
wh_rm_ends = which(xwt_data$x %in% times_rm | xwt_data$y %in% periods_rm)
xwt_data$phase[wh_rm_ends] = NA
## Add a new vertical facet for showing the "event cluster"
new_y_levels =
c('Streamflow (cms)',
## 'Period',
'XwtPer',
'TimePer',
'Time')
new_y_labels =
c('a. Timeseries',
'b. XWT',
'c. Sampled Timing Errors',
'')
the_labeller = function(string) {
labs = new_y_labels
names(labs) = new_y_levels
labs[string]
}
## Transform the factor levels on the original data.
wt_data$y_var = ordered(wt_data$y_var, levels=new_y_levels)
xwt_data$y_var = ordered(xwt_data$y_var, levels=new_y_levels)
## Rename the period axis on the other fields.
xwt_data$y_var = ordered('XwtPer', levels=new_y_levels)
timing_data$y_var = ordered("TimePer", levels=new_y_levels)
## JLM subjectiveness
timing_data$Power[which(timing_data$COI == FALSE)] = NA
timing_data$Power[which(timing_data$Significance == 0)] = NA
timing_data$XwtEvent =
as.logical(timing_data$Significance *
xwt_data$Significance *
xwt_data$COI)
##timing_data$Power[which(timing_data$COI == TRUE
## | timing_data$Significance == 0)] = NA
## Merge the new and old data. Wait for the phase...
wt_data$XwtEvent = NA
plot_data = rbind(wt_data, timing_data)
plot_data$phase = NA
xwt_data$XwtEvent = NA
plot_data = rbind(plot_data, xwt_data)
## Annotated the y-axes and set the limits (due to the annotation non-clip)
plot_data = as.data.table(plot_data)
y_labs = plot_data[
,
.(y_center=min(y)+.5*(max(y)-min(y)), x_loc=ylab_spacer*(max(x)-min(x))+max(x)),
by=y_var
]
relab = c("Streamflow (cms)", rep('Timescale (hours)',2)); names(relab) = y_labs$y_var
y_labs$lab = relab[y_labs$y_var]
x_breaks = as.numeric(the_attributes$x_breaks)
x_labels = the_attributes$x_labels
y_breaks = as.numeric(the_attributes$y_breaks)
y_labels = the_attributes$y_labels
xvals = unique(subset(wt_data, y_var == 'Streamflow (cms)')$x)
xlim = range(xvals) + c(-1,1) * diff(range(xvals))/length(xvals) / 2
## Could have used the standard plot, but it was a bit clearer to redo the whole thing.
## If the two start diverging in a bad way, then may consider using it again.
q_levels =
unique(subset(plot_data, y_var == "Streamflow (cms)")$Streamflow)
q_breaks = c('obs', c(sort(setdiff(q_levels, 'obs'))))
plot_data$Streamflow =
factor(plot_data$Streamflow, levels=rev(q_breaks))
gg2 =
ggplot() +
## This describes how the plot is arranged.
facet_grid(
y_var ~ x_var,
labeller = labeller(y_var=the_labeller, x_var=the_labeller),
scales='free',
space='free',
switch='y'
) +
## Input timeseries
geom_line(
data=subset(plot_data, y_var == "Streamflow (cms)"),
aes(x=x, y=y, color=Streamflow),
size=1.1
) +
## WT
## geom_raster(
## data=subset(plot_data, y_var == 'Period'),
## aes(x=x, y=y, fill=Power),
## interpolate=TRUE
## ) +
## geom_raster(
## data=subset(plot_data, y_var == "Period"),
## aes(x=x, y=y, alpha=COI),
## interpolate=TRUE,
## fill='white'
## ) +
## XWT
geom_raster(
data=subset(plot_data, y_var == 'XwtPer'),
aes(x=x, y=y, fill_xwt=Power),
interpolate=FALSE
) %>% rename_geom_aes(new_aes = c("fill" = "fill_xwt")) +
stat_contour(
data=subset(plot_data, y_var == "XwtPer"),
aes(x=x, y=y, z=Significance,
group=chunk, linetype='significant'),
bins=1,
color='grey40',
breaks=.5,
size=.5
) +
geom_text(
data=subset(plot_data, y_var == 'XwtPer' & !is.na(phase)),
aes(x=x, y=y, angle=(180/pi)*phase),
label='>',
size=2.5
) +
geom_raster(
data=subset(plot_data, y_var == "XwtPer"),
aes(x=x, y=y, alpha=COI),
interpolate=FALSE,
fill='white'
) +
## Timing
geom_raster(
data=subset(plot_data, y_var == 'TimePer'),
aes(x=x, y=y, fill_timing=Power),
interpolate=FALSE
#na.rm=FALSE
) %>% rename_geom_aes(new_aes = c("fill" = "fill_timing")) +
stat_contour(
data=subset(plot_data, y_var == "TimePer"),
aes(x=x, y=y, z=as.numeric(XwtEvent),
group=chunk, linetype='events'),
bins=1,
color='grey40',
breaks=.5,
size=.5
)
if(cluster_maxima) {
we_stats = we_hydro_stats(wt_event)
max_stats = we_stats[[1]]$xwt$event_timing$cluster_max
max_stats$x_var = factor('Time', levels=levels(plot_data$x_var))
max_stats$y_var = ordered('TimePer', levels=new_y_levels)
max_stats$x = min(plot_data$x, na.rm=TRUE) + 3600*(max_stats$time)
period_y_cols = c('y', 'period')
period_y_map = unique(plot_data[ y_var =='TimePer', ..period_y_cols ])
max_stats = merge(max_stats, period_y_map, by='period')
shape_color = 'grey80'
gg2 = gg2 +
geom_point(
data=max_stats,
aes(x=x, y=y, shape='Cluster'),
color=shape_color,
size=2) +
scale_shape_manual(
values=c('Time Avg\nEvent Power'=19, 'Cluster'=8),
name='Maxima')
}
gg2 = gg2 +
geom_text(
data=y_labs,
aes(x=x_loc, y=y_center, label=lab),
size=3.5,
angle=-90,
color='grey30'
) +
coord_cartesian(clip = 'off', xlim = xlim) +
labs(y = "") +
scale_y_continuous(
expand = c(0, 0),
position = "right",
breaks=y_breaks,
labels=y_labels
) +
scale_x_continuous(
expand = c(0, 0),
breaks=x_breaks,
labels=x_labels
) +
scale_color_brewer(
palette='Paired', #'Set2'
guide=guide_legend(order=100),
breaks=q_breaks,
#direction=-1
) +
scale_linetype_manual(
name='XWT',
values=c('significant'=1, 'events'=2),
breaks=c('significant', 'events'),
guide=guide_legend(order=75)
) +
scale_alpha_manual(values=c('TRUE'=0, 'FALSE'=.6), guide=FALSE) +
## scale_fill_distiller(
## aesthetics='fill',
## name="WT Power",
## guide=guide_colorbar(order=75),
## palette = "Spectral"
## ) +
scale_fill_distiller(
name="XWT Power",
aesthetics='fill_xwt',
guide=guide_colorbar(order=50, available_aes = 'fill_xwt'),
palette = "Spectral"
) +
scale_fill_distiller(
name = "Timing Error\n (hours)",
aesthetics='fill_timing',
guide=guide_colorbar(order=1, available_aes = 'fill_timing'),
palette = "Spectral",
na.value="transparent"
) +
theme_bw(base_size=base_size) +
theme(
legend.position="left",
legend.title=element_text(size=rel(0.8)),
## legend.key.height=unit(3, "line"),
axis.title.x = element_blank(),
## axis.title.y = element_blank(),
axis.title.y = element_text(color='grey40'),
panel.spacing = unit(.25, "lines"),
strip.background = element_rect(fill = 'grey90')
)
library(grid)
p = gg2
g = ggplot_gtable(ggplot_build(p))
## Deal with the unused bits.
# Check the layout...
# daGrob = ggplotGrob(gg2)
# gtable::gtable_show_layout(daGrob)
# daGrob
g = gtable::gtable_add_cols(g, grid::unit(.5,"line"), pos = -1)
## This just removes fill and line around the g$layout$name's axis-t-* to
## repurpose it as a figure title.
wh_strip = which(grepl('strip-t', g$layout$name))
fills = c("transparent")
kk = 1
for (ii in wh_strip) {
jj = which(grepl('rect', g$grobs[[ii]]$grobs[[1]]$childrenOrder))
g$grobs[[ii]]$grobs[[1]]$children[[jj]]$gp$fill = fills[kk]
g$grobs[[ii]]$grobs[[1]]$children[[jj]]$gp$lwd = 0
kk = kk+1
}
## Reorder the guides. This is a random mess.
wh_guide_box = which(g$layout$name == 'guide-box')
## Adjust the height of the individual guides using the panels on the main plot.
##gtable::gtable_show_layout(g)
##gtable::gtable_show_layout(g$grobs[[wh_guide_box]])
##g$grobs[[wh_guide_box]]$heights [3:11] = g$heights[8:16]
if(!cluster_maxima) {
g$grobs[[wh_guide_box]]$heights =
g$grobs[[wh_guide_box]]$heights[c(1,2,9,4,3,6,5,8,7,10,11)]
## 1,2,3,4,5,6,7,8,9,10,11
} else {
g$grobs[[wh_guide_box]]$heights =
g$grobs[[wh_guide_box]]$heights[c(1,2,9,4,3,6,5,8,7,10,11,12,13)]
## 1,2,3,4,5,6,7,8,9,10,11,12,13
}
wh_guides = which(grepl('guides', g$grobs[[wh_guide_box]]$layout$name))
guide_layout = g$grobs[[wh_guide_box]]$layout[wh_guides,]
## That order flummoxes me, but it works.
guide_layout = guide_layout[c(4,1,2,3),]
colnames(guide_layout) = 1:4
g$grobs[[wh_guide_box]]$layout[1:4,] = guide_layout
return(as.ggplot(g))
}
##' @export
event_cluster_timing_by_period = function(wt_event, n_periods=NULL, ncol=3) {
library(ggplot2)
## Currently this is only configured to handle a single modeled timeseries.
model_name = setdiff(names(wt_event), c("input_data", "obs"))
wh_max_periods = wt_event$obs$wt$event_timing$time_avg$local_max
max_periods = wt_event$obs$wt$event_timing$time_avg$period[wh_max_periods]
wh_period_rows = which(wt_event[[model_name]]$xwt$period %in% max_periods)
input_obs = subset(wt_event[['input_data']], Streamflow == 'obs')
input_obs$chunk_renum = input_obs$chunk - min(input_obs$chunk) +1
input_obs = input_obs[ chunk_renum %in% unique(wt_event$obs$wt$chunk) ]
timing_err_full = wt_event[[model_name]]$xwt$event_timing$mtx$timing_err[wh_period_rows,]
if(length(dim(timing_err_full)) > 1) {
dimnames(timing_err_full)[[1]] = wt_event[[model_name]]$xwt$period[wh_period_rows]
names(dimnames(timing_err_full))[1] = "period"
dimnames(timing_err_full)[[2]] = sort(unique(input_obs$input_index))
names(dimnames(timing_err_full))[2] = "time"
plot_data0 = data.table(reshape2::melt(timing_err_full, value.name='timing_err'))
} else{
plot_data0 = data.table(
timing_err=timing_err_full,
time=wt_event[[model_name]]$xwt$t,
period=max_periods
)
}
# Time here is input_index
event_timing_all = wt_event[[model_name]]$xwt$event_timing$all[period %in% max_periods]
event_timing_all$timing_err = NULL
## data table merge on the numeric causes a failure because of float noise...
event_timing_all$per_str = as.character(event_timing_all$period)
event_timing_all$period = NULL
plot_data0$per_str = as.character(plot_data0$period)
## Join in the obs signf and the wxt significance
## we_stats = we_hydro_stats(wt_event)
plot_data = merge(
plot_data0,
event_timing_all,
by=c('time', 'per_str'),
all.x=TRUE,
all.y=FALSE
)
label_clusters = function(values) {
inner_labeller = function(value) if(is.na(value)) 'None' else as.character(value)
plyr::laply(values, inner_labeller)
}
plot_data$period_clusters = factor(as.integer(label_clusters(plot_data$period_clusters)))
clust_numbers = sort(as.integer(setdiff(levels(plot_data$period_clusters), "None")))
fill_colors = c(NA, cluster_palette()(length(clust_numbers)))
names(fill_colors) = c('None', clust_numbers)
periods = unique(plot_data$period)
period_facet_labeller = paste0('Timescale = ', format(periods, digits=2, nsmall=1))
names(period_facet_labeller) = periods
max_period_stats = wt_event$obs$wt$event_timing$time_avg[local_max == TRUE,]
max_period_stats$per_str = as.character(max_period_stats$period)
setkey(max_period_stats, power_corr, physical=TRUE)
if(!is.null(n_periods)) {
n_period_use = min(n_periods, length(unique(plot_data$per_str)))
plot_data = plot_data[per_str %in% rev(max_period_stats$per_str)[1:n_period_use],]
}
plot_data$period_factor = factor(
plot_data$per_str,
levels = rev(max_period_stats$per_str)
)
we_hist_plot = function(data) {
result =
ggplot(data) +
geom_histogram(
aes(
x=timing_err,
fill=period_clusters,
alpha=xwt_signif
),
color='grey70',
size=.1#,
## binwidth=.2
) +
facet_wrap(
~period_factor,
scales='free_x',
labeller=as_labeller(period_facet_labeller),
ncol=ncol
) +
scale_alpha_manual(
name='Modeled Events',
values=c(`TRUE`=1, `FALSE`=.35),
labels=c('TRUE'='Hits', 'FALSE'='Misses'),
breaks=c(TRUE, FALSE),
na.translate=TRUE,
na.value=.2
) +
scale_fill_manual(
values=fill_colors,
name='Event Cluster Number',
na.translate=TRUE
) +
scale_x_continuous(name='Timing Error (hours)') +
theme_bw()
return(result)
}
#we_hist_plot(plot_data)
invisible(we_hist_plot(subset(plot_data, !is.na(phase))))
}
##' @export
event_cluster_timing_summary_by_period = function(
we_stats,
wt_event,
n_periods=NULL,
ncol=6,
distiller_pal='Accent',
distiller_direction=1,
timing_stat=c('cluster_max', 'cluster_mean', 'mean_max')[1],
signif_threshold=NULL,
show_points=FALSE,
show_outliers=TRUE,
mean_max=FALSE,
base_size=11,
box_fill = NA,
x_labeller=NULL
) {
library(ggplot2)
library(data.table)
plot_data = list()
we_stats['obs'] = NULL
for(mm in names(we_stats)) {
plot_data[[mm]] =
plyr::ldply(we_stats[[mm]]$xwt$event_timing[c("cluster_mean", "cluster_max")])
plot_data[[mm]]$version = mm
}
plot_data = data.table(plyr::ldply(plot_data))
if(timing_stat != 'mean_max') plot_data = plot_data[.id == timing_stat]
periods = unique(plot_data$period)
period_facet_labeller = format(periods, digits=2, nsmall=1)
names(period_facet_labeller) = periods
if(is.null(x_labeller)) {
stat_labeller = c(
cluster_mean='mean',
cluster_max='max',
`NWM v1.0`="V1.0",
`NWM v1.1`="V1.1",
`NWM v1.2`="V1.2",
`NWM v2.0`="V2.0" )
} else {
stat_labeller = x_labeller }
# The observed WT power by period can not be obtained from we_stats. Use wt_event.
obs_tavg = wt_event$obs$wt$event_timing$time_avg
obs_tavg = obs_tavg[ local_max == TRUE, ]
setkey(obs_tavg, power_corr, physical=TRUE)
plot_data$per_fact = factor(plot_data$period, levels=rev(obs_tavg$period))
if(!is.null(n_periods)) {
n_period_use = min(n_periods, length(unique(plot_data$period)))
plot_data = plot_data[period %in% rev(obs_tavg$period)[1:n_period_use],]
}
if(!is.null(signif_threshold)) {
plot_data = plot_data[xwt_signif >= signif_threshold,]
}
bps = function(data) {
## The_stats = values=boxplot.stats(data)$stats
## These are ggplot/Tukey style
lower = quantile(data, 0.25)
middle = median(data)
upper = quantile(data, 0.75)
iqr = upper - lower
max_lim = upper + (1.5*iqr)
min_lim = lower - (1.5*iqr)
mindata = data[data > min_lim]
ymin = if(length(mindata) & any(mindata < lower)) min(mindata) else min(data)
maxdata = data[data < max_lim]
ymax = if(length(maxdata) && any(maxdata > upper)) max(maxdata) else max(data)
if(ymax < upper) afafafaf
return(data.frame(ymin=ymin, lower=lower, middle=middle, upper=upper, ymax=ymax))
}
the_keys = c('version', '.id', 'period')
plot_stats =
plot_data[,
.(
ymin=bps(time_err)$ymin,
lower=bps(time_err)$lower,
mean=mean(time_err),
middle=bps(time_err)$middle,
upper=bps(time_err)$upper,
ymax=bps(time_err)$ymax,
mean_xwt_power=mean(xwt_power_corr),
mean_obs_power=mean(obs_power_corr),
count=.N,
avg_signif=mean(xwt_signif),
per_fact = per_fact[1]
),
by=the_keys]
if(show_outliers){
setkeyv(plot_data, c(the_keys, 'per_fact'))
setkeyv(plot_stats, c(the_keys, 'per_fact'))
outliers = merge(plot_data, plot_stats)[time_err < ymin | time_err > ymax] #, .() ,by=the_keys]
}
if(timing_stat == 'mean_max') {
the_plot =
ggplot() +
geom_boxplot(
data=plot_stats,
aes(x=.id,
color=avg_signif*100,
#fill=avg_signif,
ymin=ymin, lower=lower, middle=middle, upper=upper, ymax=ymax),
fill=box_fill,
stat='identity')
## scale_color_manual(
## name='Statistic',
## values=c(cluster_mean='grey70', cluster_max='black'),
## labels=c(cluster_mean='Cluster mean', cluster_max='Cluster max')
## )
if(show_outliers){
the_plot =
the_plot +
geom_point(data=outliers, aes(x=.id, y=time_err), show.legend=FALSE)
}
} else {
if(show_points) {
the_plot =
ggplot() +
geom_boxplot(
data=plot_stats,
aes(
x=version,
ymin=ymin, lower=lower, middle=middle, upper=upper, ymax=ymax
),
stat='identity'
)
} else {
the_plot =
ggplot() +
geom_boxplot(
data=plot_stats,
aes(
x=version,
ymin=ymin, lower=lower, middle=middle, upper=upper, ymax=ymax,
#fill=avg_signif,
color=avg_signif*100
),
fill=box_fill,
stat='identity'
)
}
if(show_outliers){
the_plot =
the_plot +
geom_point(data=outliers, aes(x=version, y=time_err), show.legend=FALSE)
}
}
if(show_points) {
if(timing_stat == 'mean_max') {
# THis plot is TMI, but that's just what it is.
the_plot =
the_plot +
geom_label(
data=plot_data,
aes(
x=.id,
y=time_err,
fill=xwt_signif,
label=as.character(period_clusters),
),
color='black', #.id
label.padding = unit(0.08, "lines"),
fontface="bold",
position='jitter',
size=2.5)
} else {
the_plot =
the_plot +
geom_label(
data=plot_data,
aes(
x=version,
y=time_err,
fill=xwt_signif,
label=as.character(period_clusters)
),
colour="black",
label.padding = unit(0.08, "lines"),
fontface="bold",
position='jitter',
size=2.5
)
}
}
the_plot =
the_plot +
facet_grid(
~ per_fact, # ~ version
##nrow=1,
labeller=as_labeller(period_facet_labeller)
)
if(timing_stat == 'mean_max') {
the_plot =
the_plot +
scale_x_discrete(name='Statistic',
labels=as_labeller(stat_labeller))
} else {
the_plot =
the_plot +
scale_x_discrete(name='Version',
labels=as_labeller(stat_labeller))
}
the_plot =
the_plot +
#scale_fill_distiller(name='Avg XWT\nSignif', palette=distiller_pal,
# direction=distiller_direction, limits=c(0,1)) +
scale_color_distiller(name='% Hits', palette=distiller_pal,
direction=distiller_direction, limits=c(0,100)) +
#guides(colour = "none") +
scale_y_continuous(name='Timing Error (hours)') +
theme_bw(base_size=base_size)
out_plot_stats = plot_stats
out_plot_stats$per_fact=NULL # remove redundant col
invisible(list(ggplot=the_plot, plot_stats=out_plot_stats))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.