var table; var x_x1; // x-axis x1 var x_x2; var x_y1; var x_y2; var y_x1; // y-axis x1 var y_x2; var y_y1; var y_y2; var x_len; // length of the x-axis var y_len; var desired_x; var desired_y; var desired_c; var desired_options; // additional information one would want to include var numTicks; // number of tick marks per axis var coords; // array of [x, y] data entries var c_dict; // a dictionary that maps some categorical variable c -> randomly generated color var max_x; var max_y; var scale_x; var scale_y; function preload() { table = loadTable("classics.csv", "csv", "header"); } function setup() { // VARIABLE INFORMATION...................................................................... // Canvas information var canvas_x = 1250; var canvas_y = 800; // DESIRED x, y, c, options desired_x = 'downloads'; desired_y = 'words'; desired_c = 'month name'; // categorical variable desired_options = ['title', 'name']; // if you want no options, set desired_options to null. // Axis information x_x1 = 200; x_x2 = 700; x_y1 = 650; x_y2 = 650; y_x1 = 200; y_x2 = 200; y_y1 = 150; y_y2 = 650; numTicks = 10; // number of tick marks per axis // DERIVED VALUES............................................................................ createCanvas(canvas_x, canvas_y); x_len = abs(x_x1 - x_x2); y_len = abs(y_y1 - y_y2); // DATA POPULATION........................................................................... coords = []; // array of [x,y] observations c_dict = {}; // a dictionary that maps some categorical variable c -> randomly generated color max_x = 0; max_y = 0; // populate the coordinates array for(var i = 0; i < table.getRowCount(); i++) { var x = int(table.getString(i, desired_x)); var y = int(table.getString(i, desired_y)); var c = table.getString(i, desired_c); // 'month' found in column 19 // Find maximum values if (x > max_x) { max_x = x; } if (y > max_y) { max_y = y; } // add c to the color dictionary if (!(x in c_dict)) { var colors = []; colors[0] = Math.round(random(256)); colors[1] = Math.round(random(256)); colors[2] = Math.round(random(256)); c_dict[c] = colors; } // Add [x,y] to array of observations var a = []; a[0] = x; a[1] = y; a[2] = c; // Add optional information to if (desired_options != null) { // if the array is not empty for (var j = 0; j < desired_options.length; j++) { var o = table.getString(i, desired_options[j]); a[j+3] = o; // start at index 3 to account for x, y, c } } coords[i] = a; } // SCALING.................................................................................................. // Scale so the highest value reaches the tips of the axes scale_x = (1/max_x) * x_len; // find the scaling factor for x-values scale_y = (1/max_y) * y_len; // find the scaling factor for y-values // Scaling for (var i = 0; i < coords.length; i++) { coords[i][0] = coords[i][0] * scale_x; // Scale x-value coords[i][1] = coords[i][1] * scale_y; // Scale y-value } } function draw() { // background info background(255, 248, 220); // TITLE CREATION.......................................................................... // Plot type title textSize(50); fill(255, 145, 146); text("Tri-Variate Scatter", 20, 50); fill(255, 248, 220); text("Tri-Variate Scatter", 22, 52); fill(255, 145, 146); text("Tri-Variate Scatter", 24, 54); fill(49, 54, 57); // Sub title textSize(30); fill(49, 54, 57); // rect info text(desired_x + " vs. " + desired_y, 25, 90); // AXIS CREATION ................................................................................................ // axis info stroke(49, 54, 57); strokeWeight(3); // Tick info tick_dist_x = x_len / numTicks; // distance between tick marks on x-axis tick_dist_y = y_len / numTicks; // distance between tick marks on y-axis // Plot x-axis line(x_x1, x_y1, x_x2, x_y2); // Plot y-axis line(y_x1, y_y1, y_x2, y_y2); // tick-text info fill(49, 54, 57); textSize(10); // Y-axis ticks & tick-text var temp_y = max_y; for (var i = y_y1; i < y_y2; i += tick_dist_x) { strokeWeight(3); // tick mark info line(y_x1 - 5, i, y_x1 + 5, i); // tick mark strokeWeight(0); // tick value info text(Math.round(temp_y), y_x1 - 50, i + 5); // print tick value (+5 to center number on tick) temp_y = temp_y - (max_y / numTicks); // update value of temp } // X-axis ticks & tick-text var temp_x = max_x; for (var i = x_x2; i > x_x1; i -= tick_dist_y) { strokeWeight(3); // tick mark info line(i, x_y1 - 5, i, x_y1 + 5); // tick mark strokeWeight(0); // tick value info text(Math.round(temp_x), i - 10, x_y1 + 25); // print tick value (+5 to center number on tick) temp_x = temp_x - (max_x / numTicks); // update value of temp } // Axis titles // Axis title info textSize(20); fill(49, 54, 57); // y-axis var y_title_x = 35; var y_title_y = y_y1 + Math.round(y_len / 2); text(desired_y, y_title_x, y_title_y); // x-axis var x_title_x = x_x1 + Math.round((x_len / 3)); var x_title_y = y_y1 + y_len + 70; text(desired_x, x_title_x, x_title_y); // Legend info var key_x1 = y_x1 + x_len + 10 ; var key_y1 = y_y1; // legend title textSize(20); text(desired_c, key_x1 - 10, key_y1 + 4) key_y1 += 25; // Plot each legend element textSize(12); for (col in c_dict) { fill(c_dict[col][0], c_dict[col][1], c_dict[col][2]); ellipse(key_x1, key_y1, 10); fill(49, 54, 57); text(col, key_x1 + 15, key_y1 + 4) key_y1 += 15; } // PLOT............................................................................................................ // plot x & y var ellipse_width = 5; for (var i = 0; i < coords.length; i++) { var cat = coords[i][2]; colors = c_dict[cat]; var r = colors[0]; var g = colors[1]; var b = colors[2]; fill(r, g, b); ellipse(x_x1 + coords[i][0], x_y1 - coords[i][1], ellipse_width); } // INTERACTION................................................................................... for (var i = 0; i < coords.length; i++) { var round_x = Math.round(coords[i][0]); var round_y = Math.round(coords[i][1]); var real_x = Math.round(coords[i][0]/scale_x); var real_y = Math.round(coords[i][1]/scale_y); if (dist(round_x+x_x1, x_y1 - round_y, mouseX, mouseY) < 5) { fill(255, 145, 146); // rect info rect(mouseX, mouseY, 250, -150); // rect creation textSize(10); // text info fill(255, 248, 220); // text info var string_x = desired_x + " " + real_x; var string_y = desired_y + " " + real_y; var string_c = desired_c + " " + coords[i][2]; var x_val_loc = -10; // the start x location away from mouseX to print text var y_val_loc = 120; // the start y location away from mouseY to print text var y_val_inc = 20; // the amount to increment y (how far apart the lines of text are) // Title for informative box textStyle(BOLD); textSize(15); text("info", mouseX + 10, mouseY - y_val_loc); y_val_loc -= (y_val_inc + 5); textStyle(NORMAL); // normal text info textSize(10); // normal text info // printing optional values for (j = 0; j < desired_options.length; j++) { var o = desired_options[j] + " " + coords[i][j+3]; text(o, mouseX - x_val_loc, mouseY - y_val_loc); y_val_loc -= y_val_inc; } // Printing X, Y, C var temp_colors = c_dict[coords[i][2]]; fill(temp_colors[0], temp_colors[1], temp_colors[2]); text(string_c, mouseX - x_val_loc, mouseY - y_val_loc); // print c y_val_loc -= y_val_inc; fill(255, 248, 220); // text info text(string_x, mouseX - x_val_loc, mouseY - y_val_loc); // print exact x y_val_loc -= y_val_inc; text(string_y, mouseX - x_val_loc, mouseY - y_val_loc); // print exact y } } }