#' Flower plots for OHI scores
#' By Casey O'Hara, Julia Lowndes, Melanie Frazier github.com/ohi-science
#' Assumes the following is present:
#'
#' * A csv file of scores (typically, scores.csv) generated by the calculate_score.R script.
#' * An updated conf/goals.csv file. This file provides a list of goals/subgoals and the
#' goal/subgoal names used for plotting
#' * Optional: A data layer called layers/fp_wildcaught_weight.csv that is used to weight
#' the contribution of the fisheries and mariculture subgoals to the food provision goal; this
#' information determines the relative width of these two subgoals in the flowerplot;
#' if not available, these subgoals will have equal widths.
#'
#' @param region_plot region_id/s to plot (i.e., region_plot = c(1,4,8)), defaults to plotting all regions plus the
#' weighted average of all regions
#' @param year_plot scenario year to plot if there are multiple scenario years in
#' scores.csv; if not provided, defaults to most recent year
#' @param assessment_name this is the name that will be given to the weighted
#' average of all regions (i.e., region_id=0, usually something like: "Global Average")
#' @param scenario_folder name of the scenario folder within the repository
#' (this is the folder with scores.csv, conf and layers folders, etc.)
#' @param scores_file name of the file with the score data used to create the flower plots,
#' typically: "scores.csv"
#' @param dir_fig_save file path to the location the figures (and related csv file) will be
#' saved
#' @param save whether to save csv and png files (otherwise figures are only displayed)
#'
#' @return png file/s of flowerplots will be saved in the dir_fig_save location; an
#' additional regions_figs.csv file will be saved that describes region_id, region_name,
#' and file paths to flower_.png files.
#' @export
#'
#'
#'
PlotFlower <- function(region_plot = NA,
year_plot = NA,
assessment_name = "Average",
scenario_folder = "eez",
scores_file = "scores.csv",
dir_fig_save = file.path(scenario_folder, "reports/figures"),
legend_include = TRUE,
save = TRUE) {
# dir_fig_save = 'global2018/figures/flowerplots'
## scores data ----
scores <- read.csv(here::here(scenario_folder, scores_file), stringsAsFactors = FALSE)
## if there is no year variable in the data, the current year is assigned
if(sum(names(scores) == "year") == 0){
scores$year <- substring(date(), 21, 24)
}
## if there are multiple years in the dataset and no year_plot argument,
## the most recent year of data is selected
if(is.na(year_plot)){
scores <- scores %>%
dplyr::filter(year == max(year))
} else {
scores <- scores %>%
dplyr::filter(year == year_plot)
}
## filters the region of interest, otherwise all regions are printed
if ( !any(is.na(region_plot)) ){
scores <- scores %>%
dplyr::filter(region_id %in% region_plot)
}
## filter only score dimension
scores <- scores %>%
dplyr::filter(dimension == 'score')
## labeling:: Index score for center labeling before join with conf
score_index <- scores %>%
dplyr::filter(goal == "Index") %>%
dplyr::select(region_id, score) %>%
dplyr::mutate(score = round(score))
## unique regions to plot
region_plots <- unique(scores$region_id)
## goals.csv configuration info----
## read in conf/goals.csv, start dealing with supra goals
conf <- read.csv(here::here(scenario_folder, 'conf/goals.csv'), stringsAsFactors = FALSE)
goals_supra <- na.omit(unique(conf$parent))
supra_lookup <- conf %>%
dplyr::filter(goal %in% goals_supra) %>%
dplyr::select(parent = goal, name_supra = name)
## extract conf info for labeling
conf <- conf %>%
dplyr::left_join(supra_lookup, by = 'parent') %>%
dplyr::filter(!(goal %in% goals_supra)) %>%
dplyr::select(goal, order_color, order_hierarchy,
weight, name_supra, name_flower) %>%
dplyr::mutate(name_flower = gsub("\\n", "\n", name_flower, fixed = TRUE)) %>%
dplyr::arrange(order_hierarchy)
## join scores and conf ----
score_df <- scores %>%
dplyr::inner_join(conf, by="goal") %>%
dplyr::arrange(order_color)
## set up positions for the bar centers:
## cumulative sum of weights (incl current) minus half the current weight
score_df <- score_df %>%
dplyr::group_by(region_id) %>%
dplyr::mutate(pos = sum(weight) - (cumsum(weight) - 0.5 * weight)) %>%
dplyr::mutate(pos_end = sum(weight)) %>%
dplyr::ungroup() %>%
dplyr::group_by(name_supra) %>%
## calculate position of supra goals before any unequal weighting (ie for FP)
dplyr::mutate(pos_supra = ifelse(!is.na(name_supra), mean(pos), NA)) %>%
dplyr::ungroup() %>%
dplyr::filter(weight != 0) %>%
## set up for displaying NAs
dplyr::mutate(plot_NA = ifelse(is.na(score), 100, NA))
## read if file for weights for FIS vs. MAR ----
w_fn <- list.files(here::here(scenario_folder, "layers"), pattern = "fp_wildcaught_weight.csv",
full.names = TRUE)
# deal with weights
if ( length(w_fn)<1) {
message('Cannot find `layers/fp_wildcaught_weight*.csv`...plotting FIS and MAR with equal weighting\n')
w_fn = NULL
} else{
## read in weights
w <- read.csv(w_fn, stringsAsFactors = FALSE)
if(is.na(year_plot)){
w <- w %>%
dplyr::filter(year == max(year)) %>%
dplyr::select(rgn_id, w_fis)
} else {
w <- w %>%
dplyr::filter(year == year_plot) %>%
dplyr::select(rgn_id, w_fis)
}
w <- rbind(w, data.frame(rgn_id = 0, w_fis = mean(w$w_fis))) %>%
dplyr::arrange(rgn_id)
## make sure weight regions match regions_plot regions
if ( any(!(region_plots %in% w$rgn_id)) ) {
message('`layers/fp_wildcaught_weight.csv` missing some regions...plotting FIS and MAR with equal weighting\n')
missing <- data.frame(rgn_id = setdiff(region_plots, w$rgn_id), w_fis=0.5)
w <- rbind(w, missing) %>%
dplyr::arrange(rgn_id)
}
} # end of dealing with weights
## create supra goal dataframe for position and labeling ----
supra <- score_df %>%
dplyr::mutate(name_supra = ifelse(is.na(name_supra), name_flower, name_supra)) %>%
dplyr::mutate(name_supra = paste0(name_supra, "\n"),
name_supra = gsub("Coastal", "", name_supra, fixed = TRUE)) %>%
dplyr::select(name_supra, pos_supra) %>%
unique() %>%
as.data.frame()
## calculate arc: stackoverflow.com/questions/38207390/making-curved-text-on-coord-polar ----
supra_df <- supra %>%
dplyr::mutate(myAng = seq(-70, 250, length.out = dim(supra)[1])) %>%
dplyr::filter(!is.na(pos_supra))
## more labeling and parameters ----
goal_labels <- score_df %>%
dplyr::select(goal, name_flower)
p_limits <- c(0, score_df$pos_end[1])
blank_circle_rad <- 42
light_line <- 'grey90'
white_fill <- 'white'
light_fill <- 'grey80'
med_line <- 'grey50'
med_fill <- 'grey52'
dark_line <- 'grey20'
dark_fill <- 'grey22'
## Mel's color palette ----
reds <- grDevices::colorRampPalette(
c("#A50026", "#D73027", "#F46D43", "#FDAE61", "#FEE090"),
space="Lab")(65)
blues <- grDevices::colorRampPalette(
c("#E0F3F8", "#ABD9E9", "#74ADD1", "#4575B4", "#313695"))(35)
myPalette <- c(reds, blues)
## filenaming for labeling and saving ----
region_names_all <- dplyr::bind_rows(
data_frame( ## order regions to start with whole study_area
region_id = 0,
region_name = assessment_name),
read.csv(paste(scenario_folder, 'spatial/regions_list.csv', sep="/"), stringsAsFactors = FALSE) %>%
dplyr::select(region_id = rgn_id,
region_name = rgn_name)) %>%
dplyr::mutate(flower_png = sprintf('%s/flower_%s.png',
here::here(dir_fig_save),
stringr::str_replace_all(region_name, ' ', '')))
## write out filenames
if(save){
write.csv(region_names_all, here::here(dir_fig_save, 'regions_figs.csv'))
}
## move into for loop only with region_names to plot
region_names <- region_names_all %>%
dplyr::filter(region_id %in% region_plots) %>% ## filter only regions to plot
dplyr::distinct() ## in case region_id 0 was included in regions_list.csv
## loop through to save flower plot for each region ----
for (region in region_plots) { # region =82
## filter region info, setup to plot ----
plot_df <- score_df %>%
dplyr::filter(region_id == region)
plot_score_index <- score_index %>%
dplyr::filter(region_id == region)
## fig_name to save
fig_save <- region_names$flower_png[region_names$region_id == region]
## labeling:: region name for title
region_name <- region_names %>%
dplyr::filter(region_id == region) %>%
dplyr::select(region_name)
## inject weights for FIS vs. MAR ----
if ( length(w_fn) > 0 ) {
## inject FIS/MAR weights
plot_df$weight[plot_df$goal == "FIS"] <- w$w_fis[w$rgn_id == region]
plot_df$weight[plot_df$goal == "MAR"] <- 1 - w$w_fis[w$rgn_id == region]
## recalculate pos with injected weights arrange by pos for proper ordering
plot_df <- plot_df %>%
dplyr::mutate(pos = sum(weight) - (cumsum(weight) - 0.5 * weight)) %>%
dplyr::arrange(pos)
}
## set up basic plot parameters ----
plot_obj <- ggplot2::ggplot(data = plot_df,
ggplot2::aes(x = pos, y = score, fill = score, width = weight))
## sets up the background/borders to the external boundary (100%) of plot
plot_obj <- plot_obj +
ggplot2::geom_bar(ggplot2::aes(y = 100),
stat = 'identity', color = light_line, fill = white_fill, size = .2) +
ggplot2::geom_errorbar(ggplot2::aes(x = pos, ymin = 100, ymax = 100, width = weight),
size = 0.5, color = light_line, show.legend = NA)
## lays any NA bars on top of background, with darker grey:
if(any(!is.na(plot_df$plot_NA))) {
plot_obj <- plot_obj +
ggplot2::geom_bar(ggplot2::aes(x = pos, y = plot_NA),
stat = 'identity', color = light_line, fill = light_fill, size = .2)
}
## establish the basics of the flower plot
plot_obj <- plot_obj +
## plot the actual scores on top of background/borders:
ggplot2::geom_bar(stat = 'identity', color = dark_line, size = .2) +
## emphasize edge of petal
ggplot2::geom_errorbar(ggplot2::aes(x = pos, ymin = score, ymax = score),
size = 0.5, color = dark_line, show.legend = NA) +
## plot zero as a baseline:
ggplot2::geom_errorbar(ggplot2::aes(x = pos, ymin = 0, ymax = 0),
size = 0.5, color = dark_line, show.legend = NA) +
## turn linear bar chart into polar coordinates start at 90 degrees (pi*.5)
ggplot2::coord_polar(start = pi * 0.5) +
## set petal colors to the red-yellow-blue color scale:
ggplot2::scale_fill_gradientn(colours=myPalette, na.value="black",
limits = c(0, 100)) +
## use weights to assign widths to petals:
ggplot2::scale_x_continuous(labels = plot_df$goal, breaks = plot_df$pos, limits = p_limits) +
ggplot2::scale_y_continuous(limits = c(-blank_circle_rad,
ifelse(first(goal_labels == TRUE) |
is.data.frame(goal_labels),
150, 100)))
## add center number and title
plot_obj <- plot_obj +
ggplot2::geom_text(data = score_index,
inherit.aes = FALSE,
ggplot2::aes(label = plot_score_index$score),
x = 0, y = -blank_circle_rad,
hjust = .5, vjust = .5,
size = 12,
color = dark_line) +
ggplot2::labs(title = stringr::str_replace_all(region_name, '-', ' - '))
### clean up the theme
plot_obj <- plot_obj +
ggtheme_plot() +
ggplot2::theme(panel.grid.major = ggplot2::element_blank(),
axis.line = ggplot2::element_blank(),
axis.text = ggplot2::element_blank(),
axis.title = ggplot2::element_blank())
## add goal names
plot_obj <- plot_obj +
ggplot2::geom_text(ggplot2::aes(label = name_flower, x = pos, y = 120),
hjust = .5, vjust = .5,
size = 3,
color = dark_line)
## position supra arc and names. x is angle, y is distance from center
supra_rad <- 145 ## supra goal radius from center
plot_obj <- plot_obj +
## add supragoal arcs
ggplot2::geom_errorbar(data = supra_df, inherit.aes = FALSE,
ggplot2::aes(x = pos_supra, ymin = supra_rad, ymax = supra_rad),
size = 0.25, show.legend = NA) +
ggplot2::geom_text(data = supra_df, inherit.aes = FALSE,
ggplot2::aes(label = name_supra, x = pos_supra, y = supra_rad, angle = myAng),
hjust = .5, vjust = .5,
size = 3,
color = dark_line)
# exclude legend if argument is legend=FALSE
if(!legend_include){
plot_obj <- plot_obj +
ggplot2::theme(legend.position="none")
}
### display/save options: print to graphics, save to file
suppressWarnings(print(plot_obj))
## save plot
if(save){
suppressWarnings(
ggplot2::ggsave(filename = fig_save,
plot = plot_obj,
device = "png",
height = 6, width = 8, units = 'in', dpi = 300)
)
}
### ...then return the plot object for further use
# return(invisible(plot_obj)) ## can't return with this for loop
}
}
## ggtheme_plot ----
ggtheme_plot <- function(base_size = 9) {
ggplot2::theme(axis.ticks = ggplot2::element_blank(),
text = ggplot2::element_text(family = 'Helvetica', color = 'gray30', size = base_size),
plot.title = ggplot2::element_text(size = ggplot2::rel(1.25), hjust = 0, face = 'bold'),
panel.background = ggplot2::element_blank(),
legend.position = 'right',
panel.border = ggplot2::element_blank(),
panel.grid.minor = ggplot2::element_blank(),
panel.grid.major = ggplot2::element_line(colour = 'grey90', size = .25),
# panel.grid.major = element_blank(),
legend.key = ggplot2::element_rect(colour = NA, fill = NA),
axis.line = ggplot2::element_blank()) # element_line(colour = "grey30", size = .5))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.