AI training data often feels detached from human stories. This project turns exoneration data into digital art using generative AI, coding, and symbolism. By visualizing wrongful convictions, it fosters empathy and deepens understanding of justice issues.
In the realm of modern technology, data serves as the cornerstone of progress, particularly in the rapidly advancing field of artificial intelligence (AI). The power of AI systems is intrinsically linked to the diversity and quality of data they consume, which enhances model performance, reduces bias, and ensures accurate predictions. However, there's an inherent paradox in this relationship: while data, especially structured data representing individuals and their experiences, is crucial for technological advancement, it often feels sterile and disconnected from the human stories it represents.
This disconnect poses a significant challenge, as it can diminish the sense of humanity in technology. But what if we could bridge this gap? What if we could transmute cold, impersonal data into something that speaks to our shared human experience? This is where the alchemy of data visualization comes into play, offering us a way to balance technological advancements with the human stories behind the numbers.
Our project embarks on a journey of transformation, exploring the confluence of data, generative artificial intelligence (GenAI), creative coding, data visualization, and artistic symbolism. Our goal is twofold: to bring awareness to the critical issue of false convictions in the United States and to showcase the positive use of AI and related technologies for visual communication. Through this alchemical process, we attempt to transmute impersonal exoneration data into visually compelling digital art, highlighting the significance of the data while evoking emotion and empathy from viewers.
Our development process leverages standard data science tools for data pre-processing, GenAI tools for code suggestions, and web programming tools for rendering. Using this approach, we transformed data from The National Registry of Exonerations into digital art inspired by Maori culture. The art features a motif based on the koru, the Maori symbol of new life and strength derived from a young fern fiddlehead unfurling. This symbol serves as a powerful metaphor for the process of exoneration itself - a rebirth and a new chance at life.
Through this alchemical project, we aim to bring awareness to false convictions and highlight the importance of AI for Good as society continues to identify and develop safe and trustworthy AI systems. More importantly, we demonstrate how the transformation of legal data into art can reveal patterns, spark new insights, and potentially drive meaningful change in our approach to justice.
The impact of data on the legal profession is profound and far-reaching. In a field anchored by two primary pillars - the law and facts - data serves as the vital link between abstract legal concepts and the tangible realities of human experience. This connection is perhaps most evident in the IRAC method (Issue, Rule, Application, Conclusion), a standard framework for legal analysis taught in law schools. Within this framework, data plays a crucial role in the application phase, where the law is applied to the facts of a case.
The journey of legal data collection and utilization has been long and transformative. From the launch of the FBI's National Crime Information Center database in the late 1960s1, to the establishment of the Public Access to Court Electronic Records (PACER) system in 19882, and the introduction of the FBI's Combined DNA Index System (CODIS) in 19983, we've seen a steady progression towards more comprehensive and accessible legal data systems.
A pivotal moment in the history of legal data came with the publication of the "Enron Corpus" in 20034. This dataset, comprising over 1.6 million emails from Enron employees, marked one of the first instances of unstructured data being used as evidence and made publicly available. The Enron dataset played a crucial role in the development of machine learning in the legal profession, leading to advancements in email classification, semantic index clustering, and relevancy predictions.
The legal profession's adoption of machine learning, particularly in civil litigation, was driven by necessity. The exponential growth of potential evidence sources necessitated more efficient methods of data analysis. This shift was formally recognized in 2012 when the United States saw its first federal judicial opinion on the acceptable use of machine learning for predictive relevancy coding in the discovery phase of litigation5.
The realm of exonerations represents a particularly poignant intersection of legal data and human experience. The advent of DNA forensic technology in the late 20th century marked a turning point, providing a scientific method to conclusively establish innocence or guilt. The first DNA-based exoneration in the United States occurred in 19896, setting the stage for a new era in criminal justice.
The establishment of the Innocence Project in 19927 further accelerated the use of data in pursuit of justice. Their work has not only freed innocent individuals but has also illuminated systemic issues such as racial bias, prosecutorial misconduct, and the unreliability of eyewitness testimony.
The National Registry of Exonerations, launched in 20128, serves as a crucial repository of this data. With nearly 3,500 documented cases representing more than 31,000 lost years due to miscarriages of justice9, the Registry provides a stark numerical representation of the human cost of wrongful convictions.
Our data-driven artwork was created through a workflow that served as our alchemical crucible, involving data organization, programming, and visual media design. This process was new to us and included discussion around which data elements would be appropriate for visualization, how the data could be represented in an engaging and visually interesting way, and how to achieve our desired results with existing knowledge and tools.
A key component of our alchemical process was the incorporation of GenAI tools to assist with an iterative creative coding process. These tools served as our philosopher's stone, catalyzing the transformation of raw data into visual art.
The primary element in our alchemical process was the dataset obtained from The National Registry of Exonerations. This dataset provides detailed information about every known exoneration in the United States since 1989 - cases where individuals were wrongly convicted and later cleared based on new evidence of innocence.
We focused on three key data points: State, Convicted, and Exonerated. These elements were manipulated using the R programming language, the RStudio IDE, and specialized libraries to summarize and append scaled latitude and longitude values to the raw data. The final form of our data contained a sum of the years between conviction and exoneration grouped by state, along with geographic coordinates representing the centroids of each state.
Our process was further enhanced by the use of GenAI tools, which acted as our alchemical assistants, producing code from text prompts. We tested multiple GenAI tools, including StarChat2 hosted by HuggingFace and the Perplexity Labs Playground by Perplexity. These tools leveraged large language models (LLMs) with knowledge of programming languages, essential for our creative coding process.
The programming language selected for this work was P5.js, a JavaScript library based on the Processing programming language. This choice was deliberate, as Processing was developed specifically for creative coding, prioritizing artistic expression over functionality.
Communication with LLMs involved submitting text prompts through an input field. These prompts ranged from simple requests to complex specifications, each producing a blend of expected and unexpected results. This element of unpredictability added an exciting dimension to our process, often resulting in surprising and beautiful outcomes.
The prompt that contributed most directly to our final rendering was: "write a p5.js class that draws a spiral. I want the spiral to be composed of individual circles that appear as a trail behind a leading point. The spiral class should be able to be called using x and y coordinates. The radius of the spiral should not grow forever but rather oscillate between a minimum and maximum size." This prompt resulted in an object-oriented programming solution that allowed individual spirals to be placed using coordinates derived from our data file.
The true alchemy of our project lay in the integration of symbolism with our data visualization. We chose to incorporate the koru, a symbol rooted in Maori culture representing new life, rebirth, and strength. This symbol, derived from the spiral-like fiddlehead structure of young ferns as they unfurl, served as a powerful metaphor for the process of exoneration.
In our final display, each animated koru represents a state, rendered over a two-color gradient. The color palette contains cool colors in blues, greens, and purples with complementary warmer tones for contrast. Each koru is rendered at the geometric center of its corresponding state and comprises individual ellipses representing each year from the total years of wrongful incarceration associated with the state.
We incorporated several visual effects to enhance the symbolic representation of our data:
Radius oscillation: The radius value of each koru oscillates, creating an effect of progression and regression. This symbolizes the Sisyphean efforts to achieve true freedom from a wrongful conviction.
Randomization: We introduced randomization of each individual point position to symbolize the anxiety and instability associated with an erroneous conviction.
Opacity and weight: The total years of wrongful incarceration are represented through the opacity and weight of the ellipse borders, creating a visual intensity that correlates with the magnitude of injustice in each state.
Through this process, we transformed cold, impersonal data into a living, breathing piece of art that not only represents the facts but also evokes the emotional weight of wrongful convictions.
Table 1. Visual representation of data
Data | Koru Effect |
---|---|
Latitude (scaled) | Location |
Longitude (scaled) | Location |
Year (single) | Ellipse |
Total years | Ellipse border opacity |
Total years | Ellipse border weight |
Total years | Ellipse opacity |
Total years | Ellipse radius |
Our process of transforming legal data into visual art revealed patterns and insights that might have remained hidden in raw numerical data. The most striking example is the visualization of Illinois, represented by the largest and most populated koru. This visual representation immediately draws attention to the state's disproportionate number of exonerations, primarily attributed to police misconduct by a small group of officers in Chicago.
This visualization makes the scale and concentration of wrongful convictions immediately apparent in a way that raw numbers cannot. It prompts questions about systemic issues within specific jurisdictions and highlights the need for focused reform efforts.
The use of AI in our visualization process allowed us to explore representations that might not have occurred to human designers alone. The spiral pattern of the koru, generated through AI-assisted coding, creates a visual metaphor for the cyclical nature of justice - the long, winding path from conviction to exoneration, and the potential for rebirth and new beginnings.
Moreover, the AI's ability to handle complex data relationships allowed us to incorporate multiple dimensions of our dataset into a single visual element. Each koru represents not just the number of exonerations, but also the geographic location, the total years of wrongful incarceration, and even the passage of time through its animation. This multidimensional representation offers a more holistic view of the exoneration landscape than traditional data visualization methods.
Perhaps the most valuable outcome of our alchemical process is its potential to foster empathy and understanding. By transforming years of wrongful incarceration into visually striking, animated forms, we create an emotional connection between the viewer and the data. Each pulsing, spiraling koru represents not just numbers, but lost years, shattered lives, and the resilience of those who fought for justice.
This emotional engagement is crucial for driving change. When people can see and feel the impact of wrongful convictions, they're more likely to support reform efforts and demand accountability from the justice system.
Our project, "States of Exoneration," stands as a testament to the transformative power of data visualization and AI in the realm of legal analysis and social justice. By transmuting raw exoneration data into visually compelling digital art, we've demonstrated how technology can bridge the gap between impersonal statistics and human experience, fostering a deeper understanding of critical social issues.
The implications of this work extend far beyond the realm of art or data visualization. We've shown how the alchemy of combining data science, legal analysis, and artistic expression can:
Enhance Public Understanding: By making complex legal data more accessible and emotionally resonant, we can increase public awareness and engagement with issues of wrongful conviction and criminal justice reform.
Drive Policy Changes: Visualizations that clearly illustrate the scale and patterns of wrongful convictions can serve as powerful tools for advocates pushing for policy changes and reforms in the criminal justice system.
Improve Legal Processes: The insights gained from these visualizations could inform efforts to improve legal processes, from investigation techniques to trial procedures, helping to prevent future wrongful convictions.
Foster Empathy and Support: By humanizing the data, we can generate more empathy and support for exonerees and their families, potentially leading to better reintegration programs and support systems.
Advance AI for Good: This project showcases how AI can be used as a force for good, assisting in the creation of impactful visualizations that can drive social change.
As we move forward, the potential applications of this approach to data visualization are vast. From environmental data to economic indicators, from public health statistics to educational outcomes, any dataset that has profound human implications could benefit from this type of “alchemy.”
Moreover, this project opens up new avenues for interdisciplinary collaboration. By bringing together legal experts, data scientists, AI specialists, and artists, we can create powerful new ways to communicate complex ideas and drive social change.
In conclusion, our journey from raw legal data to compelling digital art represents more than just an innovative approach to data visualization. It's a call to action - a demonstration of how technology, creativity, and human empathy can combine to shed new light on critical social issues. As we continue to explore and expand the capabilities of AI and creative coding, we have the opportunity to uncover new ways to visualize and address the complexities of our world, fostering a more informed, empathetic, and just society.
The true gold we've created through this alchemical process is not the art itself, but the potential for transformation - of data into insight, of statistics into stories, and ultimately, of awareness into action. As we continue to refine this process, we open up new possibilities for using technology to create not just smarter systems, but more humane and just societies.
Data Source:
The National Registry of Exonerations, https://www.law.umich.edu/special/exoneration/Pages/about.aspx
GenAI Tools:
StarChat2 Demo, https://huggingface.co/spaces/HuggingFaceH4/starchat2-playground
Perplexity Labs Playground, https://labs.perplexity.ai/
Programming:
P5.js, https://p5js.org/
P5.js editor, https://editor.p5js.org/
Processing, https://processing.org/
Visual Studio Code, https://code.visualstudio.com/
Live Server,
https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
Models:
StarChat2, https://huggingface.co/HuggingFaceH4/starchat2-15b-v0.1
DBRX-Instruct, https://huggingface.co/databricks/dbrx-instruct
LLM Creators:
BigCode, https://www.bigcode-project.org/
Databricks, https://www.databricks.com/
Source code available for download at: https://github.com/asantone/public/blob/0e5044985d2df56d9d5217a684c057912d05eeb7/santone_burns_2024_pt2.zip. For your convenience, the source code is included herein:
// adapted from gradient background by evebdn
// https://editor.p5js.org/evebdn/sketches/O9G35ueZv
class GradientBackground {
constructor(cMin,cMax) {
this.cMin = cMin;
this.cMax = cMax;
}
display() {
for(let y=0; y<height; y++){
let n = map(y,0,height,0,1);
let color_new = lerpColor(this.cMin,this.cMax,n);
stroke(color_new);
line(0,y,width,y);
}
}
}
/*
Author: Adam Santone, PhD
Collaborator: Kassi Burns, Esq.
Co-Author: Perplexity Labs AI
AI Model: dbrx-instruct
Date: 2024-04-20
*/
//create a koru-inspired spiral pattern
class Koru {
constructor(x, y, r, m, i,j,c) {
this.x = x;
this.y = y;
this.radius = r;
this.radiusGrowth = 0.01;
this.angle = 0;
this.angleIncrement = i;
this.minRadius = r;
this.maxRadius = 5;
this.history = [];
this.maxPoints = m;
this.jitter = j;
this.col = c;
}
update() {
//initialize jitter here for each ellipse individually
let j = random(-this.jitter,this.jitter);
//incremental updates
this.angle += this.angleIncrement;
this.radius += this.radiusGrowth;
//oscillation
if (this.radius > this.maxRadius || this.radius < this.minRadius) {
this.radiusGrowth *= -1;
}
//position around the pivot
this.x = this.x + cos(this.angle) * this.radius;
this.y = this.y + sin(this.angle) * this.radius;
//add jitter
this.x += j;
this.y += j;
//use history array to remove old points
this.history.push(createVector(this.x, this.y));
if (this.history.length > this.maxPoints) {
this.history.shift(); //remove points
}
}
//draw method for this class
display() {
//use history array for points
for (let i = 0; i < this.history.length; i++) {
let v = this.history[i];
//ellipse style
//extensive use of map() to connect style to position in the history array
//older data points fade out
stroke(100,0,100, map(i, 0, this.history.length, 0, 100)); //border color and opacity
strokeWeight(map(i, 0, this.history.length, 1, 3)); //border weight
fill(this.col, 180, 158,map(i, 0, this.history.length, 0, 100)); //main color and opacity
circle(v.x, v.y,map(i, 0, this.history.length, 1, this.col/10)); //point shape, position, and radius
}
}
}
/*
Author: Adam Santone, PhD
Collaborator: Kassi Burns, Esq.
Co-Author: Perplexity Labs AI
AI Model: dbrx-instruct
Date: 2024-04-20
*/
//global variable setup
//all koru
let k01,k02,k03,k04,k05,k06,k07,k08,k09,k10;
let k11,k12,k13,k14,k15,k16,k17,k18,k19,k20;
let k21,k22,k23,k24,k25,k26,k27,k28,k29,k30;
let k31,k32,k33,k34,k35,k36,k37,k38,k39,k40;
let k41,k42,k43,k44,k45,k46,k47,k48,k49,k50;
//color gradient min and max
let cMin,cMax;
let table; //used to hold initial data table
let data; //used to hold the data array
let abb = []; //state abbreviation (two-letter)
let lat = []; //latitude of state centroid
let lon = []; //longitude of state centroid
let tts = []; //total time served
let col = []; //colors based on tts
//let bgt = []; //background text
//set up background text
let bgt = Array(43).fill(" with liberty and justice for all");
//pre-load the data from a .csv file
function preload(){
//contains raw lat/lon values as well as rescaled values
table = loadTable('data/main_hd.csv', 'csv', 'header');
}
//setup function for initialization
function setup() {
//read the data
data = table.getArray();
//push data to arrays
//convert strings to int here
//used R to map raw lat/lon values to new range using the 'scales' library
for (i=0;i<data.length; i++){
abb.push(data[i].at(0)); //this one is strings
lon.push(int(data[i].at(6))); //longitude ('x')
lat.push(int(data[i].at(7))); //latitutde ('y')
tts.push(int(data[i].at(5))); //time
col.push(map(int(data[i].at(5)),0,9000,0,255));
}
//set the canvas dimensions
//1080p
//lat/lon data are scaled for 90% of 1080p in the .csv file
createCanvas(1920, 1080);
//background gradient colors
let colors = [color(228, 232, 216),
color(153, 173, 166)
];
//initialize background with colors
bg = new GradientBackground(colors[0],colors[1]);
//radius sizes
rVal = 0.2;
//angle increment values
aInc = random(0.15,0.25);
//point jitter value
j = 1;
//create individual koru instances
k01 = new Koru(lon[0],lat[0],rVal,tts[0],aInc,j,col[0]);
k02 = new Koru(lon[1],lat[1],rVal,tts[1],aInc,j,col[1]);
k03 = new Koru(lon[2],lat[2],rVal,tts[2],aInc,j,col[2]);
k04 = new Koru(lon[3],lat[3],rVal,tts[3],aInc,j,col[3]);
k05 = new Koru(lon[4],lat[4],rVal,tts[4],aInc,j,col[4]);
k06 = new Koru(lon[5],lat[5],rVal,tts[5],aInc,j,col[5]);
k07 = new Koru(lon[6],lat[6],rVal,tts[6],aInc,j,col[6]);
k08 = new Koru(lon[7],lat[7],rVal,tts[7],aInc,j,col[7]);
k09 = new Koru(lon[8],lat[8],rVal,tts[8],aInc,j,col[8]);
k10 = new Koru(lon[9],lat[9],rVal,tts[9],aInc,j,col[9]);
//
k11 = new Koru(lon[10],lat[10],rVal,tts[10],aInc,j,col[10]);
k12 = new Koru(lon[11],lat[11],rVal,tts[11],aInc,j,col[11]);
k13 = new Koru(lon[12],lat[12],rVal,tts[12],aInc,j,col[12]);
k14 = new Koru(lon[13],lat[13],rVal,tts[13],aInc,j,col[13]);
k15 = new Koru(lon[14],lat[14],rVal,tts[14],aInc,j,col[14]);
k16 = new Koru(lon[15],lat[15],rVal,tts[15],aInc,j,col[15]);
k17 = new Koru(lon[16],lat[16],rVal,tts[16],aInc,j,col[16]);
k18 = new Koru(lon[17],lat[17],rVal,tts[17],aInc,j,col[17]);
k19 = new Koru(lon[18],lat[18],rVal,tts[18],aInc,j,col[18]);
k20 = new Koru(lon[19],lat[19],rVal,tts[19],aInc,j,col[19]);
//
k21 = new Koru(lon[20],lat[20],rVal,tts[20],aInc,j,col[20]);
k22 = new Koru(lon[21],lat[21],rVal,tts[21],aInc,j,col[21]);
k23 = new Koru(lon[22],lat[22],rVal,tts[22],aInc,j,col[22]);
k24 = new Koru(lon[23],lat[23],rVal,tts[23],aInc,j,col[23]);
k25 = new Koru(lon[24],lat[24],rVal,tts[24],aInc,j,col[24]);
k26 = new Koru(lon[25],lat[25],rVal,tts[25],aInc,j,col[25]);
k27 = new Koru(lon[26],lat[26],rVal,tts[26],aInc,j,col[26]);
k28 = new Koru(lon[27],lat[27],rVal,tts[27],aInc,j,col[27]);
k29 = new Koru(lon[28],lat[28],rVal,tts[28],aInc,j,col[28]);
k30 = new Koru(lon[29],lat[29],rVal,tts[29],aInc,j,col[29]);
//
k31 = new Koru(lon[30],lat[30],rVal,tts[30],aInc,j,col[30]);
k32 = new Koru(lon[31],lat[31],rVal,tts[31],aInc,j,col[31]);
k33 = new Koru(lon[32],lat[32],rVal,tts[32],aInc,j,col[32]);
k34 = new Koru(lon[33],lat[33],rVal,tts[33],aInc,j,col[33]);
k35 = new Koru(lon[34],lat[34],rVal,tts[34],aInc,j,col[34]);
k36 = new Koru(lon[35],lat[35],rVal,tts[35],aInc,j,col[35]);
k37 = new Koru(lon[36],lat[36],rVal,tts[36],aInc,j,col[36]);
k38 = new Koru(lon[37],lat[37],rVal,tts[37],aInc,j,col[37]);
k39 = new Koru(lon[38],lat[38],rVal,tts[38],aInc,j,col[38]);
k40 = new Koru(lon[39],lat[39],rVal,tts[39],aInc,j,col[39]);
//
k41 = new Koru(lon[40],lat[40],rVal,tts[40],aInc,j,col[40]);
k42 = new Koru(lon[41],lat[41],rVal,tts[41],aInc,j,col[41]);
k43 = new Koru(lon[42],lat[42],rVal,tts[42],aInc,j,col[42]);
k44 = new Koru(lon[43],lat[43],rVal,tts[43],aInc,j,col[43]);
k45 = new Koru(lon[44],lat[44],rVal,tts[44],aInc,j,col[44]);
k46 = new Koru(lon[45],lat[45],rVal,tts[45],aInc,j,col[45]);
k47 = new Koru(lon[46],lat[46],rVal,tts[46],aInc,j,col[46]);
k48 = new Koru(lon[47],lat[47],rVal,tts[47],aInc,j,col[47]);
k49 = new Koru(lon[48],lat[48],rVal,tts[48],aInc,j,col[48]);
k50 = new Koru(lon[49],lat[49],rVal,tts[49],aInc,j,col[49]);
}
//draw function called each frame
function draw() {
//recording
//https://www.npmjs.com/package/p5.capture/v/1.2.0
/*
if (frameCount === 1) {
const capture = P5Capture.getInstance();
capture.start({
format: "mp4",
framerate:30,
width: 1920,
height: 1080,
duration: 1800, //60s * 30fps
disableUi: true
});
}
*/
//set the background color
background(220);
bg.display();
//shift everything to the middle
push(); //add to stack
translate(width/2,height/2);
scale(1, -1); //negative is 'reverse' axis
//update koru
k01.update(); k02.update(); k03.update(); k04.update(); k05.update(); k06.update(); k07.update(); k08.update(); k09.update(); k10.update();
k11.update(); k12.update(); k13.update(); k14.update(); k15.update(); k16.update(); k17.update(); k18.update(); k19.update(); k20.update();
k21.update(); k22.update(); k23.update(); k24.update(); k25.update(); k26.update(); k27.update(); k28.update(); k29.update(); k30.update();
k31.update(); k32.update(); k33.update(); k34.update(); k35.update(); k36.update(); k37.update(); k38.update(); k39.update(); k40.update();
k41.update(); k42.update(); k43.update(); k44.update(); k45.update(); k46.update(); k47.update(); k48.update(); k49.update(); k50.update();
//display koru
k01.display(); k02.display(); k03.display(); k04.display(); k05.display(); k06.display(); k07.display(); k08.display(); k09.display(); k10.display();
k11.display(); k12.display(); k13.display(); k14.display(); k15.display(); k16.display(); k17.display(); k18.display(); k19.display(); k20.display();
k21.display(); k22.display(); k23.display(); k24.display(); k25.display(); k26.display(); k27.display(); k28.display(); k29.display(); k30.display();
k31.display(); k32.display(); k33.display(); k34.display(); k35.display(); k36.display(); k37.display(); k38.display(); k39.display(); k40.display();
k41.display(); k42.display(); k43.display(); k44.display(); k45.display(); k46.display(); k47.display(); k48.display(); k49.display(); k50.display();
pop(); //remove from stack
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.1/p5.js"></script>
<!--https://www.npmjs.com/package/p5.capture/v/1.2.0-->
<!--<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/p5.capture.umd.min.js"></script>-->
<meta charset="utf-8" />
</head>
<body>
<main>
</main>
<script src="./js/sketch.js"> </script>
<script src="./js/koru.js"> </script>
<script src="./js/gradient.js"></script>
</body>
</html>