Published

February 20, 2025

Modified

February 19, 2025

About

This page extracts information about illustrations of Gestalt principles that students found as part of their work on 2025-02-13. Data are pulled from the shared Google Sheet.

Data

Direct link: https://docs.google.com/spreadsheets/d/1G8U_IPMP0x17Sfl-FQfF37DN19bDQFm0GO_UmQQzv7Q/edit?usp=sharing

Preparation

First, we load the external packages (groups of R commands) that we will be using.

Important

The code uses the quietly() function from the purrr package to suppress most of the feedback.

Code
library('ggplot2')
library('dplyr')

# r_functions <- list.files(file.path(here::here(), "src", "R"), "\\.R$", full.names = TRUE)
# 
# purrr::map(r_functions, source) |>
#   purrr::quietly()

Gathering

Next, we download the data from the Google Sheet where it is collected. Dr. Gilmore has stored his Google account credentials in a special environment file that can be accessed by the R command Sys.getenv("GMAIL_SURVEY").

Tip

It’s vital to be very careful when creating and sharing code like this that involves sensitive information like login credentials.

Gilmore likes to put credentials in an .Renviron file that lives in his home directory. This is a recommended practice. On Mac OS and Linux, that’s ~/.Renviron. You can use the usethis::edit_r_profile() command at the R console (not the Terminal) to open your own .Renviron file. In Gilmore’s case, he has added the following line to that file:

GMAIL_SURVEY="<my-google-account>"

Here, he has substituted his Google account with credentials/access to the required files for <my-google-account>. Then, when the R code below calls Sys.getenv("GMAIL_SURVEY"), the value of those credentials is returned as a text string.

Make sure to close and save the .Renviron file and restart your R session before testing this yourself.

Code
if (!dir.exists('csv')) {
  message("Creating missing `csv/`.")
  dir.create("csv")
}

if (params$update_data) {
  options(gargle_oauth_email = Sys.getenv("GMAIL_SURVEY"))
  googledrive::drive_auth()

  googledrive::drive_download(
    params$google_sheet_name,
    path = file.path("csv", params$fn),
    type = "csv",
    overwrite = TRUE
  )
  message("Data updated.")
} else {
  message("Using stored data.")
}

The data file has been saved as a comma-separated value (CSV) format data file in a special directory called csv/.

Cleaning

Next we load the saved data file, and then proceed to clean it.

Code
gestalt <-
  readr::read_csv(file.path("csv", params$fn), show_col_types = FALSE)

There are 22 responses.

These are the column/variable names.

Code
# Google Forms puts the full question in the top row of the data file.
# We use the names() function to extract and print the original questions.
gestalt_qs <- names(gestalt)
gestalt_qs
[1] "identifier"        "gestalt_principle" "url_src"          
[4] "url_to_img"       

For simplicity, we visualize below only those with non-empty URLs to the specific figure.

Summary data

Code
figs_w_urls <- gestalt |>
  filter(!is.na(url_to_img)) |>
  filter(stringr::str_detect(url_to_img, "[png|jpg|webp]$"))

There were n=14 unique respondents.

Of the 22 responses from these individuals or teams, n=13 had URLs we could link to directly with non-data-visualization figures.

Make helper functions

Code
make_img_markdown_from_url <- function(img_url = "https://www.psychologicalscience.org/redesign/wp-content/uploads/2015/12/TCD_fig_1.jpg",
                                       lightbox = "{.lightbox}") {
  assertthat::is.string(img_url)
  
  component_1 <- paste0("![](")
  component_2 <- paste0(img_url, ")", lightbox)
  paste0(component_1, component_2)
}


return_img_chunk <- function(i, df) {
  assertthat::is.number(i)
  assertthat::assert_that(i > 0)
  assertthat::assert_that(is.data.frame(df))
  
  df_i <- df[i,]
  chunk_hdr_txt <- paste0("### Figure ", i, "\n\n")
  chunk_hdr <- knitr::knit_expand(text = chunk_hdr_txt)
  
  if (!is.na(df_i$url_to_img)) {
    img_markdown <- make_img_markdown_from_url(df_i$url_to_img)
  } else {
    img_markdown = "**No direct link to figure**"
  }
  body_txt <- paste0("\n\n| Analyst | Principle | \n|---|---|\n", 
  "| ", df_i$identifier, " | ", df_i$gestalt_principle, "|")
  knitr::knit_child(
    text = c(chunk_hdr, img_markdown, body_txt),
    envir = environment(),
    quiet = TRUE
  )  
}

Figures found

Code
res <- invisible(lapply(1:dim(figs_w_urls)[1], return_img_chunk, df = figs_w_urls))
cat(unlist(res), sep = "\n")

Figure 1

Analyst Principle
HRQ Closure

Figure 2

Analyst Principle
HRQ Closure

Figure 3

Analyst Principle
TJD Continuity

Figure 4

Analyst Principle
TJD Continuity

Figure 5

Analyst Principle
SS Closure

Figure 6

Analyst Principle
JVM Proximity

Figure 7

Analyst Principle
ABC Continuity

Figure 8

Analyst Principle
ABC Continuity

Figure 9

Analyst Principle
KVV Closure

Figure 10

Analyst Principle
KVV Closure

Figure 11

Analyst Principle
ac Continuity

Figure 12

Analyst Principle
NA NA

Figure 13

Analyst Principle
pp Reification

Sites found

Code
gestalt |>
  filter(!is.na(url_src)) |>
  filter(stringr::str_detect(url_src, "^https://")) |>
  dplyr::select(url_src) |>
#  dplyr::mutate(url_src = paste0("<", url_src, ">")) |>
  knitr::kable(format = 'html')
url_src
https://www.wikiart.org/en/salvador-dali/face-of-mae-west-which-may-be-used-as-an-apartment
https://www.olympics.com/ioc/olympic-rings
https://www.census.gov/library/visualizations/interactive/state-private-nonres-construction-spending.html
https://www.behance.net/gallery/18122387/Gestalt-Principles
https://nastengraph.medium.com/gestalt-principles-in-data-visualization-a4e56e6074b5
https://www.uxdesigninstitute.com/blog/gestalt-principles-ux-ui-design/
https://towardsdatascience.com/the-psychology-behind-data-visualization-techniques-68ef12865720/
https://pmc.ncbi.nlm.nih.gov/articles/PMC3728284/
https://wbispace.usc.edu/gestalt.html
https://www.pinterest.com/pin/355854808061515950/sent/?invite_code=838115ec6814476584ca76ff24e9d590&sfo=1