Useful Meetings and Code Tools

Overview

Under Construction

Learning Objectives

TBD

Preparation

TBD

A Framework for Group Process Design

The diamond model is not only a conceptual model of the common flow of participatory decisionmaking dynamics – it is also a tool you can use to design good group processes.

Have you ever been in a meeting that generated tons of ideas, but left you wondering whether any of it was going to go anywhere? That group process neglected to engage in convergent thinking. Or have you experienced a leader who hands down dictates with little discussion and expects everyone to just agree? They are missing out on the value of divergent and emergent thinking to generate creativity and buy-in.

A good group process will move through the diamond model and include all three types of thinking. Your process design, whether it’s for a single meeting, a multi-day workshop, or a longer collaborative process, should start by asking yourself, where are we now? What resources, people, and information do we have as our starting point? And where do we want to get to? What is our target end state – the deliverable or outcome we are trying to achieve?

Between those two points - your initial state and your target state - you can use one or multiple diamond shaped activities to productively move your group along. Each microstructure or game you use to engage the group can help to generate new ideas, explore them together, and converge on new insights or decisions. Those insights or decisions can then become the input for the next diamond, until you eventually reach your goal.

Those diamonds can vary in scale from mini-exercises that only take a few minutes to multi-day or longer processes. Once you start to recognize it, you’ll see the diamond model everywhere (or miss it when it’s lacking!).

NoteActivity: Small Group Exercise #1 - Where are we in the diamond?

Purpose: Identify where your group is in the diamond model right now and what stage you need to move through next.

Part 1 - Individual Reflection

  • Where would you say your group is right now in the diamond model?
  • Have you been leveraging the relevant thinking for the stage you are in (divergent, emergent, or convergent)?
  • Think about the next group work or decisionmaking task that lies ahead:
    • What stage(s) of the diamond will that work take you through and what kind of thinking will be needed?

Part 2 - Project Team Discussion

  • Identify a reporter, notetaker, and facilitator/timekeeper
  • Go around and share your answers to the prompt (1 min each)
  • Discuss and try to reach consensus about which stage(s) of the diamond model best match the next chunk of work you have ahead of you.

Part 3 - Report Out

Share with the whole group

Tools to Support the Thinking You Need

(D=divergent, E=emergent, C=convergent)

Microstructure Stage Purpose How It Works Tips & Traps
Brainwriting or brainstorming D Surface and elaborate ideas Brainstorm ideas in a google doc or virtual whiteboard (or on index cards or sticky notes in person); read and add to each other’s ideas; discuss Follow up with affinity mapping as you move into emergent thinking
Rotating Stations D Spread good ideas and make informal connections Set up stations with experts or innovators who can present information and engage discussion; group members circulate to learn, ask questions, or provide feedback Keep the overall session short so that it’s not too fatiguing for presenters who will have to repeat their spiel many times
User Experience Fishbowl (a riff on panel discussion) DE Draw out and contrast different perspectives from experts or interested parties Experts with direct experience of the challenge at hand are invited to engage each other in conversation at the center of a circle; the rest of the group are audience to their conversation; audience and facilitator can suggest things for them to discuss Avoid falling back on traditional formats where panelists talk to the audience rather than each other - the power of the fishbowl is the deep way in which the experts can engage each other
Horizon scanning / futures thinking DE Detect emerging trends, issues, or research opportunities Define your scope; consult outside sources of data and expertise or brainstorm within the group to identify emerging trends, events, and weak signals of future change that may affect the question / topic you have defined Set a timeframe that’s far enough out to encompass important uncertainties but not so far that forecasting becomes overly speculative
Affinity Map (clustering) E Surface ideas, detect patterns, and analyze Brainstorm ideas using sticky notes on a wall or virtual whiteboard; cluster into categories Follow up with prioritization of ideas within clusters as you move into convergent thinking
Conceptual models E Build a shared representation of the system Co-develop a figure or diagram that encapsulates your collective understanding of the focal problem or system Consider mind maps, flow charts, system diagrams; Consider having several small groups attempt this in parallel and compare results
World Cafe conversations E Engage everyone in making sense of profound challenges Ask for a volunteer to host each table; use a talking object; Go-around 1: share what you are thinking, feeling, or doing about the theme or topic; Go-around 2: share your thoughts and feelings after having listened to others; Open conversation; Go-around 4: “takeaways” Start with a clear question or prompt for discussion; Share the agreements and ask hosts to gently facilitate adherence
What, So What, Now What EC Make sense of past progress or experiences and decide on future actions What - As a group, compile the facts and observations relevant to the context; So What - Reflect on the facts and their implications, identify patterns, generate hypotheses; Now What - Draw conclusions - What actions make sense? Be firm in calling out opinions being passed off as facts in the What stage. Stick to what is observable.
Polling EC Rank alternatives Decide how many votes per person; In person - use sticky dots; Virtually - use +1s in a google doc or a digital polling tool (e.g., Zoom, Mural, slido) Before you start - clarify how you will use the results - are you gathering information or taking a vote to make a decision?
Feasibility x impact matrix C Compare alternatives Discuss and agree on definitions for two criteria for evaluating ideas: feasibility of implementation and impact potential; Rate each idea against these two axes and map onto 2x2 grid How you define the axes must be clear and agreed upon by everyone before you start
Fist to Five / Gradient of Agreement C Assess degree of consensus; seek closure Use when ready to close a discussion or make a decision; Invite participants to rate their level of agreement with a proposal on a scale of 0-5; Five fingers means “absolute, total agreement or support” and a fist means “complete opposition” If you have some 1s and 2s, more discussion is needed - ask them to explain their concerns or questions
Open discussion DEC Group inquiry, sensemaking, and/or decision-making Clearly define the scope; set agreements for inclusive discussion; invite discussion about the topic at hand; capture ideas and questions; listen for when the group is ready to converge Keep track of side topics (e.g. in a “bike rack”) and make time to come back to them, but don’t let them derail
Breakout groups DEC Engage everyone deeply; avoid groupthink Define the scope and intended outcomes; set a time limit; assign roles (facilitator, notetaker, reporter); model what you want in the report out Consider whether all groups should work with the same prompts or different aspects of the problem
Chart writing or whiteboarding DEC Reflect participant’s viewpoints back to the group On a virtual or physical chart or whiteboard, capture key points in the discussion so everyone can see them Use speakers’ own words; if the comment is long or complex, ask the speaker to give you a headline you can capture
1,2,4,all DEC Engage everyone in generating questions, ideas, and suggestions Individual reflection; Pair share; Two pairs combine and share as a group of 4; Small groups share highlights with whole group Emphasize novel ideas and distinctions for divergence; common themes and emerging insights for emergence and convergence
Round robin / go around DEC Hear from everyone; get starting positions on the table Everyone answers the same prompt. Alternatives to going in order: each speaker calls on someone else after they have shared; popcorn-style - people share in the order that they feel moved to speak Do not allow discussion until everyone has responded to the initial prompt
NoteActivity: Small Group Exercise #2 - Emergent thinking practice

Part 1 - Team Discussion & Co-Production

  • Assign a facilitator, notetaker and reporter
  • Read through the list of options and begin with the step that seems most useful for your team’s current needs. Work your way through as many of the steps as you can during the allotted time.
  • Create or refine a conceptual figure that captures how you are thinking about the system you are investigating
  • Once you are satisfied with your conceptual figure:
    • Outline your key questions
    • Map your planned analyses to them
    • How are you going to answer each question with data?
    • If you were working with the tools we suggested last time to start outlining your analysis, this should build from there
  • What are the ~3 key figures that would best illustrate your results?

Part 2 - Report Out

  • Share what you developed with the whole group!
  • After all groups have shared, offer suggestions to other groups and/or ask questions about the module.

Conditionals

Rather than finding and replacing content, you may want to create a new column based on the contents of a different column. In plain language you might phrase this as ‘if column X has [some values] then column Y should have [other values]’. These operations are called conditionals and are an important part of data wrangling.

If you only want your conditional to support two outcomes (as in an either/or statement) there are useful functions that support this. Let’s return to our Plum Island Ecosystems crab dataset for an example.

# Load tidyverse
library(tidyverse)

# Make a new colum with an either/or conditional
pie_crab_v2 <- pie_crab %>% 
  dplyr::mutate(size_category = ifelse(test = (size >= 15),
                                       yes = "big",
                                       no = "small"),
                .after = size) 

# Count the number of crabs in each category
pie_crab_v2 %>% 
  dplyr::group_by(size_category) %>% 
  dplyr::summarize(crab_ct = dplyr::n())
1
mutate makes a new column, ifelse is actually doing the conditional
# A tibble: 2 × 2
  size_category crab_ct
  <chr>           <int>
1 big               179
2 small             213

If you have multiple different conditions you can just stack these either/or conditionals together but this gets cumbersome quickly. It is preferable to instead use a function that supports as many alternates as you want!

# Make a new column with several conditionals
pie_crab_v2 <- pie_crab %>% 
  dplyr::mutate(size_category = dplyr::case_when( 
    size <= 10 ~ "tiny",
    size > 10 & size <= 15 ~ "small",
    size > 15 & size <= 20 ~ "big",
    size > 20 ~ "huge",
    TRUE ~ "uncategorized"),
                .after = size)

# Count the number of crabs in each category
pie_crab_v2 %>% 
  dplyr::group_by(size_category) %>% 
  dplyr::summarize(crab_ct = dplyr::n())
1
Syntax is ‘test ~ what to do when true’
2
This line is a catch-all for any rows that don’t meet previous conditions
# A tibble: 4 × 2
  size_category crab_ct
  <chr>           <int>
1 big               150
2 huge               28
3 small             178
4 tiny               36

Note that you can use functions like this one when you do have an either/or conditional if you prefer this format.

NoteActivity: Conditionals

In a script, attempt the following with the PIE crab data:

  • Create a column indicating when air temperature is above or below 13° Fahrenheit
  • Create a column indicating whether water temperature is lower than the first quartile, between the first quartile and the median water temp, between the median and the third quartile or greater than the third quartile
Hint Consult the summary function output!

Uniting or Separating Columns

Sometimes one column has multiple pieces of information that you’d like to consider separately. A date column is a common example of this because particular months are always in a given season regardless of the specific day or year. So, it can be useful to break a complete date (i.e., year/month/day) into its component bits to be better able to access those pieces of information.

# Split date into each piece of temporal info
pie_crab_v3 <- pie_crab_v2 %>% 
  tidyr::separate_wider_delim(cols = date, 
                              delim = "-",
                              names = c("year", "month", "day"),
                              cols_remove = TRUE)

# Check that out
str(pie_crab_v3)
1
‘delim’ is short for “delimiter” which we covered in the Reproducibility module
2
This argument specifies whether to remove the original column when making the new columns

While breaking apart a column’s contents can be useful, it can also be helpful to combine the contents of several columns!

# Re-combine data information back into date
pie_crab_v4 <- pie_crab_v3 %>% 
  tidyr::unite(col = "date",
               sep = "/",
               year:day, 
               remove = FALSE)

# Structure check
str(pie_crab_v4)
1
This is equivalent to the ‘delim’ argument in the previous function
2
Comparable to the ‘cols_remove’ argument in the previous function

Note in this output how despite re-combining data information the column is listed as a character column! Simply combining or separating data is not always enough so you need to really lean into frequent data structure checks to be sure that your data are structured in the way that you want.

Joining Data

Often the early steps of a synthesis project involve combining the data tables horizontally. You might imagine that you have two groups’ data on sea star abundance and–once you’ve synonymized the column names–you can simply ‘stack’ the tables on top of one another. Slightly trickier but no less common is combining tables by the contents of a shared column (or columns). Cases like this include wanting to combine your sea star table with ocean temperature data from the region of each group’s research. You can’t simply attach the columns because that assumes that the row order is identical between the two data tables (and indeed, that there are the same number of rows in both to begin with!). In this case, if both data tables shared some columns (perhaps “site” and coordinate columns) you can use joins to let your computer match these key columns and make sure that only appropriate rows are combined.

Because joins are completely dependent upon the value in both columns being an exact match, it is a good idea to carefully check the contents of those columns before attempting a join to make sure that the join will be successful.

# Create a fish taxonomy dataframe that corresponds with the earlier fish dataframe
fish_tax <- data.frame("species" = c("salmon", "bass", "halibut", "eel"),
                       "family" = c("Salmonidae", "Serranidae", "Pleuronectidae", "Muraenidae"))

# Check to make sure that the 'species' column matches between both tables
supportR::diff_check(old = fish_ct$species, new = fish_tax$species) 
# Use text replacement methods to fix that mistake in one table
fish_tax_v2 <- fish_tax %>% 
  dplyr::mutate(species = gsub(pattern = "^eel$",
                               replacement = "moray eel", 
                               x = species))

# Re-check to make sure that fixed it
supportR::diff_check(old = fish_ct$species, new = fish_tax_v2$species)
1
The symbols around “eel” mean that we’re only finding/replacing exact matches. It doesn’t matter in this context but often replacing a partial match would result in more problems. For example, replacing “eel” with “moray eel” could make “electric eel” into “electric moray eel”.

Now that the shared column matches between the two two dataframes we can use a join to combine them! There are four types of join:

  1. left/right join
  2. full join (a.k.a. outer join)
  3. inner join
  4. anti join

You can learn more about the types of join here or here but the quick explanation is that the name of the join indicates whether the rows of the “left” and/or the “right” table are retained in the combined table. In synthesis work a left join or full join is most common (where you have your primary data in the left position and some ancillary/supplementary dataset in the right position).

# Let's combine the fish count and fish taxonomy information
fish_df <- fish_ct %>% 
  # Actual join step
  dplyr::left_join(y = fish_tax_v2, by = "species") %>%
  # Move 'family' column to the left of all other columns
  dplyr::relocate(family, .before = dplyr::everything())

# Look at the result of that
fish_df
1
The ‘by’ argument accepts a vector of column names found in both data tables
NoteActivity: Joining Data

In a script, attempt the following with the PIE crab data:

  1. Create a data frame where you bin months into seasons (i.e., winter, spring, summer, fall)
    • Use your judgement on which month(s) should fall into each given PIE’s latitude/location
  2. Join your season table to the PIE crab data based on month
  3. Calculate the average size of crabs in each season in order to identify which season correlates with the largest crabs
Hint You may need to modify the PIE dataset to ensure both data tables share at least one column upon which they can be joined

Leveraging Data Shape

You may already be familiar with data shape but fewer people recognize how playing with the shape of data can make certain operations dramatically more efficient. If you haven’t encountered it before, any data table can be said to have one of two ‘shapes’: either long or wide. Wide data have all measured variables from a single observation in one row (typically resulting in more columns than rows or “wider” data tables). Long data usually have one observation split into many rows (typically resulting in more rows than columns or “longer” data tables).

Data shape is often important for statistical analysis or visualization but it has an under-appreciated role to play in quality control efforts as well. If many columns have the shared criteria for what constitutes “tidy”, you can reshape the data to get all of those values into a single column (i.e., reshape longer), perform any needed wrangling, then–when you’re finished–reshape back into the original data shape (i.e., reshape wider). As opposed to applying the same operations repeatedly to each column individually.

Let’s consider an example to help clarify this. We’ll simulate a butterfly dataset where both the number of different species and their sex were recorded in the same column. This makes the column not technically numeric and therefore unusable in analysis or visualization.

# Generate a butterfly dataframe
bfly_v1 <- data.frame("pasture" = c("PNW", "PNW", "RCS", "RCS"),
                      "monarch" = c("14m", "10f", "7m", "16f"),
                      "melissa_blue" = c("32m", "2f", "6m", "0f"),
                      "swallowtail" = c("1m", "3f", "0m", "5f"))

# First we'll reshape this into long format
bfly_v2 <- bfly_v1 %>% 
  tidyr::pivot_longer(cols = -pasture, 
                      names_to = "butterfly_sp", 
                      values_to = "count_sex")

# Check what that leaves us with
head(bfly_v2, n = 4)
# A tibble: 4 × 3
  pasture butterfly_sp count_sex
  <chr>   <chr>        <chr>    
1 PNW     monarch      14m      
2 PNW     melissa_blue 32m      
3 PNW     swallowtail  1m       
4 PNW     monarch      10f      
# Let's separate count from sex to be more usable later
bfly_v3 <- bfly_v2 %>% 
  tidyr::separate_wider_regex(cols = count_sex, 
                              c(count = "[[:digit:]]+", sex = "[[:alpha:]]")) %>% 
  # Make the 'count' column a real number now
  dplyr::mutate(count = as.numeric(count))

# Re-check output
head(bfly_v3, n = 4)
# A tibble: 4 × 4
  pasture butterfly_sp count sex  
  <chr>   <chr>        <dbl> <chr>
1 PNW     monarch         14 m    
2 PNW     melissa_blue    32 m    
3 PNW     swallowtail      1 m    
4 PNW     monarch         10 f    
# Reshape back into wide-ish format
bfly_v4 <- bfly_v3 %>% 
  tidyr::pivot_wider(names_from = "butterfly_sp", values_from = count)

# Re-re-check output
head(bfly_v4)
# A tibble: 4 × 5
  pasture sex   monarch melissa_blue swallowtail
  <chr>   <chr>   <dbl>        <dbl>       <dbl>
1 PNW     m          14           32           1
2 PNW     f          10            2           3
3 RCS     m           7            6           0
4 RCS     f          16            0           5

While we absolutely could have used the same function to break apart count and butterfly sex data it would have involved copy/pasting the same information repeatedly. By pivoting to long format first, we can greatly streamline our code. This can also be advantageous for unit conversions, applying data transformations, or checking text column contents among many other possible applications.

Loops

Another way of simplifying repetitive operations is to use a “for loop” (often called simply “loops”). Loops allow you to iterate across a piece of code for a set number of times. Loops require you to define an “index” object that will change itself at the end of each iteration of the loop before beginning the next iteration. This index object’s identity will be determined by whatever set of values you define at the top of the loop.

Here’s a very bare bones example to demonstrate the fundamentals.

# Loop across each number between 2 and 4
for(k in 2:4){
  
  # Square the number
  result <- k^2
  
  # Message that outside of the loop
  message(k, " squared is ", result)
}
1
‘k’ is our index object in this loop
2
Note that the operations to iterate across are wrapped in curly braces ({...})
2 squared is 4
3 squared is 9
4 squared is 16

Once you get the hang of loops, they can be a nice way of simplifying your code in a relatively human-readable way! Let’s return to our Plum Island Ecosystems crab dataset for a more nuanced example.

# Create an empty list
crab_list <- list()

# Let's loop across size categories of crab
for(focal_size in unique(pie_crab_v4$size_category)){
  
  # Subset the data to just this size category
  focal_df <- pie_crab_v4 %>% 
    dplyr::filter(size_category == focal_size)
  
  # Calculate average and standard deviation of size within this category
  size_avg <- mean(focal_df$size, na.rm = T) 
  size_dev <- sd(focal_df$size, na.rm = T) 
  
  # Assemble this into a data table and add to our list
  crab_list[[focal_size]] <- data.frame("size_category" = focal_size,
                                        "size_mean" = size_avg,
                                        "size_sd" = size_dev)
} # Close loop

# Unlist the outputs into a dataframe
crab_df <- purrr::list_rbind(x = crab_list)

# Check out the resulting data table
crab_df
1
Note that this is not the most efficient way of doing group-wise summarization but is–hopefully–a nice demonstration of loops!
2
When all elements of your list have the same column names, list_rbind efficiently stacks those elements into one longer data table.