Proj 3: 2D Reorderable Matrix

james_schaffer
Posts: 5
Joined: Sat Jan 10, 2015 11:34 am

Re: Proj 3: 2D Reorderable Matrix

Post by james_schaffer » Thu Feb 05, 2015 4:25 am

A Controversial Treemap

UPDATE!
final_rev_ss1.png
final_rev_ss2.png
Additional treemap configurations are now available. Clicking the 'Strip' button multiple times will actually result in different strip layouts each time. Additionally, this project has been accelerated with OpenGL, with the same text tweaks described in the final project post.
(END UPDATE)
screenshot.png
Screenshot of the system displaying controversial books in the 'Bible' topic.
For this project, I chose to implement a Treemap due to prior interest. Treemaps were traditionally conceived for visualizing space usage on a hard disk, so they are relatively suited to any visualization where we want to communicate a 'piece of the pie' and associated parameters via text and color.

I chose to partition the space by 'popularity' (that is, total checkouts). Topic is shown as text on each partition, with color indicating the controversy score which was previously described. I wanted to implement some degree of drill down in this iteration, so mousing over a topic shows the most controversial books.

As a side note, the majority of time spent on this project was spent getting more fine-grained data records into processing and setting up the data structures to handle automatic statistical aggregation. These summaries (buckets) were then passed to a Treemap library for layout, which were customized via subclassing. The treemap library can be found here: http://benfry.com/writing/treemap/ (and is part of the 'Visualizing Data' text).

Updated SQL script (dewey parameter was changed incrementally to fetch chunks of data and were later aggregated).

Code: Select all

SELECT 
    activity.bib,
    dewey.dewey as topic,
	extras.pages,
    popularity.popularity as pops,
    STD(UNIX_TIMESTAMP(activity.i) - UNIX_TIMESTAMP(activity.o)) AS checkoutVariance
FROM
    spl1.activity,
    spl1.popularity,
	spl1.dewey,
	spl1.extras
WHERE
    activity.bib = popularity.bib
		AND dewey.bib = activity.bib
        AND activity.i > '2005-01-01 00:00:00'
        AND dewey.dewey >= 100
        AND dewey.dewey < 200
        AND popularity.popularity > 10
		AND extras.bib = activity.bib
GROUP BY activity.bib;
The controversy score was also tinkered with using average rating and pages, but using either tended to result in flat values, possibly due to a bug. This will be investigated further.

Code is attached, data is too large to be attached. Full project can be found at: http://128.111.28.122/controversy_v2.zip
Attachments
controversy_v2.zip
Code.
(537.33 KiB) Downloaded 292 times
Last edited by james_schaffer on Mon Mar 16, 2015 11:42 pm, edited 1 time in total.

nedda.amini
Posts: 5
Joined: Tue Jan 14, 2014 11:55 am

Re: Proj 3: 2D Reorderable Matrix

Post by nedda.amini » Thu Feb 05, 2015 6:30 am

Due to time constraints, I found myself only able to implement the bare minimum for this assignment, and simply did a responsive reordering of the data matrix from my previous query and 2D color representation.
I did two simple reorders of my same query, one by column weight and one by row weight.
The most interesting reordering was by columns, which created an interesting revisualization that showed most books were checked out for a period of 60-70 months, then decrease. I found it odd that I capped around that number.

Query

Code: Select all

SELECT 
    FLOOR(deweyClass / 10) * 10,
    (TIMESTAMPDIFF(MONTH, cout, cin))
FROM
    spl2.inraw
WHERE
    (itemtype = 'acbk'
        AND (deweyClass > 700 AND deweyClass < 800)
        AND (TIMESTAMPDIFF(MONTH, cout, cin) > 12
        AND TIMESTAMPDIFF(MONTH, cout, cin) < 72)
        AND (YEAR(cout) > 2005 AND YEAR(cout) < 2014))
The processing code is attached
Attachments
MAT_259_V_2 copy.zip
(63.86 KiB) Downloaded 298 times
800 Rows.png
800 columns.png
700 Rows.png
700 columns.png

menzer
Posts: 5
Joined: Sat Jan 10, 2015 11:30 am

Re: Proj 3: 2D Reorderable Matrix

Post by menzer » Thu Feb 05, 2015 6:36 am

This re-ordering exercise is based on the previous visualization project that mapped the “awake” time of the library directly on diurnal and seasonal cycles (example shown in Fig. 1). Starting from the observation that highest activity seemed to occur more often during mid week and mid year, I decided to explore this relationship with time in more detail by re-ordering dimensions and exploring emerging patterns. The re-ordering exercise was done in three steps:

1.) Sort the values in the matrix by the awake time in minutes irrespective of weekday and week of year, starting at the upper left corner progressing through the matrix row by row. This is a magnitude based clustering approach in the form of a look-up table. Figure 2 is a simple visualization of the matrix re-ordered in that way, note that the size of the boxes still correspond to observed awake time period and so do the brightness and transparency of the boxes.
2006.png
Fig.1: Original Data Matrix showing awake time in minutes projected on day of week (vertical) and week of year (horizontal).
Fig.2-Re-ordered.png
Fig.2: Data Matrix re-ordered by the awake time in minutes starting in the upper left corner and progressing by row.
2.) To investigate temporal patterns in the data, we can now use the look-up table to visualize the corresponding information on day of week and week of year that are emerging from the re-ordered awake time. First, I visualized day of week with an RGB multi-hue color pattern from colorbrewer using the same color value for Saturday and Sunday, thus accounting for the circular nature of the weekday variable. This allows for discerning weekday-weekend effects while still showing smooth gradients between adjacent days (Fig. 3).
Re-ordered_weekdayClustering_Fig.3.png
Fig.3: Re-ordered matrix based on the sorting in Figure 2 showing weekday patterns in a circular color scheme.
3.) Finally, I am re-ordering each row obtained in 2.) centered on the maximum value similar to a Kernel density function. This can test for seasonal effects occurring across several weekdays within the 7 clustered awake classes.

In an updated version of this project, I will include mouse hover functions for each cell, so that exact information on the hour of the earliest and latest checkout become visible interactively. Also, Machine Learning techniques such as Artificial Neural Networks could be used to fit a plane to either the original temporal axes or the re-ordered axes. This response function plane could then be plotted in 3D space.

Code: Select all

int cellWidth = 22;
int cellHeight = 50;
int bgColor = 25;

float factHeight;
float morningOffset;

int rowMargin = 120;
int colMargin = 80;

int numWeekdays = 7;
int numWeeks = 51; //use 51 to correct for missing days and end up with rectangular shape
String[] weekdayNames = {
  "Sunday", 
  "Monday", 
  "Tuesday", 
  "Wednesday", 
  "Thursday", 
  "Friday", 
  "Saturday"
};

String[] weekdayNamesShort = {
  "Su", 
  "Mo", 
  "Tu", 
  "We", 
  "Th", 
  "Fr", 
  "Sa"
};

float [][] dataMatrix = null;
int [][] dataAwake = null;
//int [][] dataEarliestCout = null;
//int [][] dataLatestCout = null;

int [][] dataWeekByAwake = null;
int [][] dataWeekdayByAwake = null;
int [][] dataAwakeByAwake = null;
int [][] dataEarliestCout = null;
int [][] dataLatestCout = null;

int [][] dataWeekdayByAwakeCentered = null;

int maxAwake;
int numRows, numCols;

PFont myFont1 = createFont( "Helvetica", 24, true);
PFont myFont2 = createFont( "Helvetica", 16, true);

Table myTable;

color colorWeekday[]     = {
  color(252, 187, 161, 160), //Sun
  color(252, 146, 114, 160), //Mon
  color(251, 106, 74, 160), //Tue
  color(222, 45, 38, 160), 
  color(251, 106, 74, 160), 
  color(252, 146, 114, 160), 
  color(252, 187, 161, 160) //Sat
};

//['rgb(254,229,217)','rgb(252,187,161)','rgb(252,146,114)','rgb(251,106,74)','rgb(222,45,38)','rgb(165,15,21)']
//['rgb(254,240,217)','rgb(253,204,138)','rgb(252,141,89)','rgb(215,48,31)']

void setup()
{
  //setting up a screen size 1400*500
  size( 1360, 500);
  colorMode(RGB);
  // set background to white
  background(255);
  //activate smoothing anti-aliasing functions between pixels
  smooth();
  // set framerate to 10 per second. NOrmal video is 30 or 60
  frameRate( 10);

  //load the awake data set
  myTable = loadTable( "awake_Week_weekday_matrix_2006.csv", "header");
  //header for col names  as follows:
  //barcode  deweyClass  weekday_num  week_num  awake  earliest_cout_hour  latest_cout_hour

  // assign these variables to contain the number of rows and columns from myTable
  numRows = myTable.getRowCount();
  numCols = myTable.getColumnCount();

  // initialize the 2D array with number of rows and columns
  dataMatrix = new float[numRows][numCols];

  // copy everything from table into a 2D array

  maxAwake = (int)dataMatrix[0][4]; //find max awake value [minutes] for scaling of colorbar

  for ( int i = 0; i< numRows; i++)          // a for loop where i is set to 0  and increments all the way to numRows by 1
  {
    for ( int j = 0; j< numCols; j++)// a for loop where j is set to 0  and increments all the way to numColumns by 1
    {
      dataMatrix[i][j] = myTable.getInt(i, j);      // copying the table integer value at mytable (i,j) position into the dataMatrix
      print( dataMatrix[i][j ] + " ");            // print out the value of dataMatrix
    }                  
    if ( dataMatrix[i][4] > maxAwake)      // this is an if statement which checks for the condition in brackets                                                         // if true, it executes the statements in brackets 
    {
      maxAwake = (int)dataMatrix[i][4];
    }
    println();      // switch to next line in the prompt, improves legibility
  }

  //  //correct weekday numbering scheme to starting from Saturday instead of Sunday:
  //  for ( int i = 0; i< numRows; i++)          // a for loop where i is set to 0  and increments all the way to numRows by 1
  //  {
  //      dataMatrix[i][2] ++;
  //      if (dataMatrix[i][2] == 7) dataMatrix[i][2] = 0;
  //  }


  //get sorted week - weekday matrix from getWeekdayWeek function
  println("getting sorted matrices...");
  //dataAwake = getWeekWeekday(dataMatrix, 4); // 4 is colIndex for awake
  //println("interpolating missing data...");
  //dataAwake = interpMissing(dataAwake);

  // could be replaced by hashmap to make avoid multiple sortings of the same rules
  println("getting sorted weekday matrix...");
  dataWeekdayByAwake = getColByAwake(dataMatrix, 2); // 2 weekday
  println("getting sorted week matrix...");
  dataWeekByAwake = getColByAwake(dataMatrix, 3); // 3 is colIndex for week
  println("getting sorted awake matrix...");
  dataAwakeByAwake = getColByAwake(dataMatrix, 4); // 4 is colIndex for awake in minutes
  println("getting sorted Earliest matrix...");
  dataEarliestCout = getColByAwake(dataMatrix, 5); // 5 is colIndex for earliest cout hour
  println("getting sorted Latest matrix...");
  dataLatestCout = getColByAwake(dataMatrix, 6); // 6 is colIndex for latest cout hour

//  for ( int  i = 0; i<  numWeekdays; i++) 
//  {
//    int weekDaysToCenter[] = null;
//    for ( int  j = 0; j < numWeeks; j++)       
//    {     
//      print(weekDaysToCenter[j]);
//      print(dataWeekdayByAwake[i][j]);
//      weekDaysToCenter[j] = dataWeekdayByAwake[i][j];//take row and put into 1D array
//    }
//    //sort values on center
//    int[] weekDaysCentered = null;
//    weekDaysCentered = sortMaxOnCenterByRow(weekDaysToCenter);
//    for ( int  j = 0; j < numWeekdays; j++)       
//    { 
//      dataWeekdayByAwakeCentered[i][j] = weekDaysCentered[j];//re-transcribe into a matrix
//    }
//  }
}

// Mapping function to convert SQL output to a matrix that is ordered by AWAKE values, starting in the upper left corner
// values in original data set are already ordered by awake minutes so we can just go through them row by row and write out the weekday and week information
// This look up table could be generated much more efficiently, but given the size of the dataset it works OK.
int[][] getColByAwake(float[][]data, int colIndex) {
  int[][] dataByAwakeMatrix = new int[numWeeks+1][numWeekdays+1];
  //dataByAwakeMatrix[w-1][wd-1] = 0;//zero initializer
  for (int i=0; i<data.length; i++) {//go through values in data file and sort into week weekday matrix
    if ((i != 0) && ((i % numWeekdays) == 0)) {
      println();
    }
    //print(i + " ");
    //print(i / (numWeekdays));
    dataByAwakeMatrix[i%(numWeeks)][i / (numWeeks)] = (int)data[i][colIndex];
    print( dataByAwakeMatrix[i%(numWeeks)][i / (numWeeks)] + " ");
    //dataByAwakeMatrix[i/(numWeekdays)][i % (numWeekdays)] = (int)data[i][colIndex];
    //print( dataByAwakeMatrix[i/(numWeekdays)][i % (numWeekdays)] + " ");
  }
  println();
  return dataByAwakeMatrix;
}

// Interpolation function for missing values in data matrix
int[][] interpMissing(int[][]data) {
  for (int w=1; w<=numWeeks; w++) {
    for (int wd=1; wd<=numWeekdays; wd++) {   
      if (data[w-1][wd-1] == 0) {
        println("zero value detected, interpolate with data for the same day from rest of the year");
        int wdaySum = 0;
        for (int w1=1; w1<=numWeeks; w1++) {
          wdaySum += data[w1-1][wd-1];
        }
        data[w-1][wd-1] = wdaySum/numWeeks;
      }
      print( data[w-1][wd-1] + " ");
    }
    println();      // switch to next line in the prompt, improves legibility
  }
  return data;
}

int[] sortMaxOnCenterByRow(int[]data) {
  int[] n = null;
  for (int i = numWeeks-1; i >=numWeeks; i--) {
    n[i] = i;
  }
  int[] sorted = new int[n.length];

  final int center = (n.length / 2) - 1 + (n.length % 2);
  for (int i = 1, sgn = -1; i <= n.length; i++, sgn *= -1) {
    sorted[center + (sgn*i/2)] = n[i-1];
  }
  return sorted;
}

void draw()
{
  // refresh background every frame
  background(bgColor);
  fill(154); 
  textAlign(RIGHT, CENTER);
  textFont(myFont1);
  text("Weekday Clustering by Awake Times [2006]", 940, 40);
  //creating the cells sequentially
  // this where the actual drawing of data happens 
  // we run two nested loops, one for rows and the other for columns , we go through each cell to retrive its value 
  // and fill the color of the cell accordingly
  for ( int  i = 0; i<  numWeeks; i++) 
  {
    for ( int  j = 0; j < numWeekdays; j++)           // -1 as the last column is empty, our dataMatrix is smaller than the table by one column
    {                    
      colorMode(HSB);
//      stroke(1, 192, 224* dataWeekdayByAwake[i][j]/numWeekdays, 224* dataWeekdayByAwake[i][j]/numWeekdays );
      stroke(1, 192, 224* dataAwakeByAwake[i][j]/maxAwake);//, 224* dataAwakeByAwake[i][j]/maxAwake );
      strokeWeight(1);
      fill(bgColor); // fill boxes with same color as background
      //plot 24 hour rectangle with stroke around it
      rect(rowMargin + i * cellWidth, colMargin + j * cellHeight, cellWidth-2, cellHeight);//*;

//      fill(150+92* dataWeekByAwake[i][j]/numWeeks, 192, 192);
      colorMode(RGB);
//      fill(colorWeekday[floor(dataWeekByAwake[i][j])/(numWeekdays+1)]);
      fill(colorWeekday[dataWeekdayByAwake[i][j]-1]);
      //Fig.1
      //colorMode(HSB);
      //      fill(1, 192, 224* dataAwakeByAwake[i][j]/maxAwake, 224* dataAwakeByAwake[i][j]/maxAwake );
      //colorMode(RGB);
      factHeight = (float)(dataLatestCout[i][j]-dataEarliestCout[i][j])/24;//hours dependent scaling factor for height
      morningOffset = (float)dataEarliestCout[i][j]/24 * cellHeight;
      //plot rectangle that is mapped onto the area of the observed hours
      rect(rowMargin + i * cellWidth, colMargin + j * cellHeight + morningOffset, cellWidth-2, cellHeight*factHeight);//*;
    }
  }

  textAlign(RIGHT, CENTER);
  textFont(myFont2, 12);  
  fill(154);
int i = 0;  
  //for (int i=0; i<numWeekdays; i++) {
    //text(weekdayNames[i], rowMargin * 0.91, colMargin + cellHeight/2 + i*cellHeight);
    text("0 minutes ... ", rowMargin * 0.91, colMargin + cellHeight/2 + i*cellHeight);
    i = numWeekdays - 1;
    text("... 1390 minutes.", 1242 + rowMargin * 0.91, colMargin + cellHeight/2 + i*cellHeight);

  //}
  
  drawColorBar();

  if ( frameCount % 20 ==0)
  {
    println( "draw called " + frameCount );                    // here we are printing out the frameCount ( how many frames have been drawn so far)
  }
}

void drawColorBar() {
  colorMode(RGB);  
    for(int j = 0; j < 7; j++) {
          stroke(colorWeekday[j]);
          fill(colorWeekday[j]);
          rect(rowMargin+884+j*35, colMargin+375, 25, 20);
          
          fill(154);
          textFont(myFont2, 11);
          textAlign(LEFT, CENTER);
          text(weekdayNamesShort[j], rowMargin+884+j*35+6.25, colMargin+405);
      }   
}
Attachments
awakeReOrdered.zip
project sketch folder
(78.88 KiB) Downloaded 289 times
Last edited by menzer on Sun Feb 08, 2015 8:30 pm, edited 4 times in total.

brocknoah
Posts: 5
Joined: Sat Jan 10, 2015 11:36 am

Re: Proj 3: 2D Reorderable Matrix

Post by brocknoah » Thu Feb 05, 2015 9:40 am

My query is still the same as I search for the most popular week day to checkout books. The year was set to 2010 and is open to all types of books, juvenile, young adult, adult books, etc.

I count the number of checkouts per day, then sort an array of weekdays that belongs to a dewey grouping of 10, a dewey sub class. The sorted low to high array allows me to rank the most popular day by determining the index position of a certain week day. This value will determine the opacity for the weekday. Each dewey subclass grouping consists of the same colors, and the same increment of opac value. The darker colors represent more checkouts and lighter colors represent less checkouts.

The second column is a sorted array of all the dewey subclasses, done by a simple bubble sort checking the day with the lowest number of checkouts. The subclass with the lowest checkouts will appear at the top while the subclasses with more will appear at the bottom.

The first visual of most popular weekday to checkout books transforms into least popular to most popular dewey categories.

The left visual is linked with the right. Hovering in a range of dewey class (ig 0-99) will show all the subclasses on the right side at once. From the ordered array, you can get a feel how popular a dewey class is over all. If the right side has 4 of 10 stripes in the upper quadrant, you know it isn't that popular. Or it could have an outlier. One can also learn how popular a dewey subclass is within its own parent class.
Attachments
ex02.jpg
ex01.jpg
p3.zip
(8.71 KiB) Downloaded 294 times
Last edited by brocknoah on Thu Feb 05, 2015 6:37 pm, edited 2 times in total.

dimberman
Posts: 6
Joined: Sat Jan 10, 2015 11:28 am

Re: Proj 3: 2D Reorderable Matrix

Post by dimberman » Thu Feb 05, 2015 9:48 am

original:

Sorted chronologically:
Screenshot 2015-02-05 10.36.53.png
chrono sort
Sorted by average:
Screenshot 2015-02-05 10.36.59.png
average sort
Sorted by standard deviation:
Screenshot 2015-02-05 10.37.08.png
stDev sort

For this project, I decided to continue on the route that I have been looking into for my previous projects: how different genres react to different days of the week and times of days. I implemented functions that are able to sort the times for each individual genre by either a) how popular that time is or b) how strong of a deviation does that time have depending on the day.

I was actually able to modify my query so I could get data more easily, but at the moment I'm not sure how many genres I want to include, since I want to have individual time data for each genre.

Soon I was able to find a better color scheme that would look more similar to a heat mapping however I was having an issue in that it was hard to tell the relevance of any of the color. What's dense? what's sparse? everything seemed equally important and this simply was not the case.

Sorted chronologically:
Screenshot 2015-02-05 11.19.19.png
chrono 2
Sorted by average:
Screenshot 2015-02-05 11.19.29.png
av 2
Sorted by standard deviation:
Screenshot 2015-02-05 11.19.39.png
std 2

Finally, I realized that by making the background color the same color as my least important color I was able to achieve an effect where the least important pieces of data fade into the background, while the most important information appears to burn as a red hot spot.

Sorted chronologically:
Screenshot 2015-02-05 11.16.54.png
chrono 3
Sorted by average:
Screenshot 2015-02-05 11.17.05.png
av 3
Sorted by standard deviation:
Screenshot 2015-02-05 11.17.20.png
std 3
new query:

Code: Select all

SELECT hour(day1.cdate),
sum(case when deweyClass>=810 and deweyClass<820 and dayofweek(day1.cdate) = 1 then 1 else 0 end),
sum(case when deweyClass>=810 and deweyClass<820 and dayofweek(day1.cdate) = 2 then 1 else 0 end),
sum(case when deweyClass>=810 and deweyClass<820 and dayofweek(day1.cdate) = 3 then 1 else 0 end),
sum(case when deweyClass>=810 and deweyClass<820 and dayofweek(day1.cdate) = 4 then 1 else 0 end),
sum(case when deweyClass>=810 and deweyClass<820 and dayofweek(day1.cdate) = 5 then 1 else 0 end),
sum(case when deweyClass>=810 and deweyClass<820 and dayofweek(day1.cdate) = 6 then 1 else 0 end),
sum(case when deweyClass>=810 and deweyClass<820 and dayofweek(day1.cdate) = 7 then 1 else 0 end)

	from
	(SELECT  cout as cdate, deweyClass
		FROM (
			SELECT cout, deweyClass
			FROM spl2.inraw
			WHERE DATE(cout) >= '2013-03-01' AND DATE(cout) < '2013-04-01'
			) as outday1
		where hour(outday1.cout) >=10 and hour(outday1.cout)<= 20
    ) as day1
    group by hour(day1.cdate)
    order by hour(day1.cdate)
    
    
processing code:

Code: Select all

/*
class demo on Jan 15, 2015
By Mohit Hingorani
if you have any questons regarding the code please email me at mohit@mat.ucsb.edu


we will be going over on how to import any table into processing and arrays again in next class
in this demo we are importing a simple integer table 

This demo creates a two-dimensional grid where each cell has 3 values: a verticallocation, a horizontal location, 
and a cell colorvalue. All the values are stored in a csv file which has 11 columns of integers acquired through 
a MySQL quary in the SPL database. There are 31rows of data representing a query which has looked for data for 31 days

COMMENTS: any line that begins with // or is in-between /*    */
/* is commented out and the program does not see it, only humans. 
------------
Variables include
int = are integers such as, 5, 89, 594803
float = are decimal based numbers such as 5.45, 1489.3482
string = "life", "overthetop" strings are a sequence of characters and alwasy in double quotes
int []array = {34,65,2} is a 1 dimensional array, a list of data separated by commas
int[][]array = a 2 dimensional array as we use in this demo
*/

/* initializing a variable outside of a function makes it global. The variable is active and available throughtout the programe 
Variables initialized inside a function are called local variables and lose their values once the program exits the function 
*/





float colormap_hcl_1[][] =   {{ 0.1804, 0.0824, 0.0510 },
  { 0.2431, 0.1255, 0.0784 },
  { 0.3059, 0.1686, 0.1020 },
  { 0.3725, 0.2157, 0.1255 },
  { 0.4392, 0.2667, 0.1490 },
  { 0.5020, 0.3176, 0.1686 },
  { 0.5647, 0.3765, 0.1882 },
  { 0.6235, 0.4314, 0.2078 },
  { 0.6824, 0.4941, 0.2314 },
  { 0.7412, 0.5569, 0.2510 },
  { 0.7922, 0.6235, 0.2745 },
  { 0.8431, 0.6941, 0.2980 },
  { 0.8863, 0.7647, 0.3255 },
  { 0.9294, 0.8353, 0.3569 },
  { 0.9686, 0.9098, 0.3922 }};
  
  int colorInts[] = {
   #C71C2E,#C0192E,#B9152D,#B1122D,#AA0F2C,#A30C2C,#89216C,#941560,#9B0754,#A30039,#A30C2C,#89216C,#812B77,#753481,#673D8B,#554593,#3D4C99,#1B2A59,#213165,#273772,#2E3E7E,#36458C,#3D4C99}; 


import java.util.Collections;
import java.lang.Math;
int colorLength = colormap_hcl_1.length;
int radius =100;
int xPosition  = 20;


// we added these variables in class on tuesday

int cellWidth = 20;
int cellHeight = 50;
char AFLAG = 'C';
int rowMargin =180;
int columnMargin = 80;

/*Creating a two-dimensional array we are calling "Data Matrix", and initialize its values to null. 
A two-dimensional array is really nothing more than an array of arrays (a three-dimensional array 
is an array of arrays of arrays).
*/
float [][] standardDevMatrix = null;
float [][] averageMatrix = null;

// a variable to keep track of the MaxCount
float maxCount ;
float maxCount2;
//variables to represent the vertical and horizontal locations of the grid we will draw
int numRows, numColumns;

// crating a font of size 16 and helvetica 
PFont font = createFont( "Helvetica", 24, true);

// creating a table. Table objects store data with multiple rows and columns, much like in a traditional spreadsheet
Table myTable;
Table avTable;
float[][] averages;
int[][] avIndeces;
float[][] stDevs;
int[][] stDevIndeces;


String[] a= new String[7];
void setup()
    {
      //setting up a screen size 640*360
      size( 1280,800);
      //colorMode(HSB);
      // set background to white
      background(0,2,2);
      //activate smoothing anti-aliasing functions between pixels
      smooth();
      // set framerate to 10 per second. NOrmal video is 30 or 60
      frameRate( 10);
      //Print out the text in the command prompt once the program reaches here
      println( " setup done");
      

      a[0]="Su";
      a[1]="M";
      a[2]="T";
      a[3]="W";
      a[4]="Th";
      a[5]="F";
      a[6]="Sa";


      //in this step we copy the data from the csv file into our own table.
      //we use header flag to tell processing to ignore the first line of the csv file as it contains the names of the columns
      myTable = loadTable( "onemonthmindacbkjcbk.csv");
      avTable = loadTable("averageData.csv");
      
      // assign these variables to contain the number of rows and columns from myTable
      numRows = avTable.getRowCount();
      numColumns = avTable.getColumnCount();
      
      // initialize the 2D array with number of rows and columns
      standardDevMatrix = new float[numRows][numColumns];
      averageMatrix = new float[numRows][numColumns];
      averages = new float[4][numColumns];
      avIndeces = new int[4][numColumns];
      stDevs = new float[4][numColumns];
      stDevIndeces = new int[4][numColumns];

      // copy everything from table into a 2D array
      // use two for loops to iterate over both rows and columns
      // this step is not necessary, but helps in matrix manipulations which we will be doing later
      

      
      for ( int i = 0 ; i< numRows ; i++)          // a for loop where i is set to 0  and increments all the way to numRows by 1
          {
            for ( int j = 0 ; j< numColumns ; j++)// a for loop where j is set to 0  and increments all the way to numColumns by 1
                {
                  standardDevMatrix[i][j] = myTable.getFloat(i,j);      // copying the table integer value at mytable (i,j) position into the standardDevMatrix
                  stDevs[i/7][j] += standardDevMatrix[i][j]; 
                }
          }
     
     
     
     
                                println("original input data");

           for ( int i = 0 ; i< numRows ; i++)          // a for loop where i is set to 0  and increments all the way to numRows by 1
              {
            for ( int j = 0 ; j< numColumns ; j++)// a for loop where j is set to 0  and increments all the way to numColumns by 1
                {
                  averageMatrix[i][j] = avTable.getFloat(i,j);      // copying the table integer value at mytable (i,j) position into the standardDevMatrix
                  print(avTable.getFloat(i,j) + " ");

                  averages[i/7][j] += averageMatrix[i][j];
                }
                           println("");

          }

          println("\n\n");
          println("after input");


          for(int i = 0; i<numRows; i++){
           for ( int j = 0 ; j< numColumns ; j++)  {
               print(averageMatrix[i][j] + " ");
           }
           println("");
          }


          for(int i = 0; i<4; i++){
           for ( int j = 0 ; j< numColumns ; j++)  {
               print(averages[i][j] + " ");
           }
           println("");
          }

          for(int i = 0; i<4; i++){
           for ( int j = 0 ; j< numColumns ; j++)  {
              avIndeces[i][j] = j;
              stDevIndeces[i][j]= j;
           }
          }
          
      println("avIndeces");
         for(int i = 0; i<4; i++){
            for(int j = 0; j<numColumns; j++){
                print(avIndeces[i][j] +" ");
                
            }
            println();
         }

         for(int i = 0; i<4; i++){

            mySort(averages[i], avIndeces[i]);
            mySort(stDevs[i], stDevIndeces[i]);

         }
         println("avIndeces");
         for(int i = 0; i<4; i++){
            for(int j = 0; j<numColumns; j++){
                print(avIndeces[i][j] +" ");
                
            }
            println();
         }
//



    }
//The Draw() processing function repeats itselfs continuously at 60 frames per second unless the frameRate is changed
void draw()
      {
        // refresh background every frame
       background(200);
       
        int addedWeight = 0;
        //creating the cells sequentially
        // this where the actual drawing of data happens 
        // we run two nested loops, one for rows and the other for columns , we go through each cell to retrive its value 
        // and fill the color of the cell accordingly
        for(int k = 0; k < 4; k++){
        for ( int  i = 0 ; i<numRows/4 ; i++) 
            {
                 if(i%7==0 && i!=0){
//                               fill(200); 
//                               rect(rowMargin+ i * cellWidth ,columnMargin +j * cellHeight ,cellWidth, cellHeight );                // draw the rectange of size 15,25 at the appropriate position, the position of the cell depends on its value in the table position (i,j)
                              addedWeight+=3;
//                              println("calling addweight");
                 }

                for ( int  j = 0 ; j < numColumns ; j++)           // -1 as the last column is empty, our standardDevMatrix is smaller than the table by one column
                      {                    
                          stroke(128);                                      // turn color of borders to gray
                          strokeWeight(0.5);                        // make the borders thinner
                          colorMode(HSB);                                  // switch color mode to HSB space
                          if(AFLAG=='C'){
                                                      colorMode(RGB);                                  //switch colorspace back to RGB

                                 int r = (int)Math.floor(standardDevMatrix[i+k*7][j]*(colorLength-1));
                                 int g = (int)Math.floor(averageMatrix[i+k*7][j]*(colorLength-1));
                                 int b = (int)Math.floor(standardDevMatrix[i+k*7][j]*(colorLength-1));
//                                 println("hue brightness: "  + 255*colormap_hcl_1[b][2]);
                                 fill(colorInts[19 - (int)(averageMatrix[i+k*7][j]*19)], 100 +155*(2*colormap_hcl_1[b][2]) );  // 
                          
  
                          rect(rowMargin+ (i + addedWeight+k*10)*cellWidth ,columnMargin +j * cellHeight ,cellWidth, cellHeight );                // draw the rectange of size 15,25 at the appropriate position, the position of the cell depends on its value in the table position (i,j)
                          }
                          else if(AFLAG == 'A'){
                                 println("standard dev = " + standardDevMatrix[i][avIndeces[k][j]]);
                                 println("average = " + averageMatrix[i][j]);
                                 colorMode(RGB);                                  //switch colorspace back to RGB

                                 int r = (int)Math.floor(standardDevMatrix[i+k*7][avIndeces[k][j]]*(colorLength-1));
                                 int g = (int)Math.floor(averageMatrix[i+k*7][avIndeces[k][j]]*(colorLength-1));
                                 int b = (int)Math.floor(standardDevMatrix[i+k*7][avIndeces[k][j]]*(colorLength-1));
                                 
//                                 fill(255*colormap_hcl_1[r][0] , 255*colormap_hcl_1[g][1], 100 +155*(2*colormap_hcl_1[b][2]) );  
                                 fill(colorInts[19 - (int)(averageMatrix[i+k*7][avIndeces[k][j]]*19)], 100 +155*(2*colormap_hcl_1[b][2]) );  // 
 
                                                           colorMode(RGB);                                  //switch colorspace back to RGB

  
                          rect(rowMargin+ (i + addedWeight+k*10)*cellWidth ,columnMargin +j * cellHeight ,cellWidth, cellHeight );                // draw the rectange of size 15,25 at the appropriate position, the position of the cell depends on its value in the table position (i,j)
                          }
                          else{
                                 colorMode(RGB);                                  //switch colorspace back to RGB

                                 int r = (int)Math.floor(standardDevMatrix[i+k*7][stDevIndeces[k][j]]*(colorLength-1));
                                 int g = (int)Math.floor(averageMatrix[i+k*7][stDevIndeces[k][j]]*(colorLength-1));
                                 int b = (int)Math.floor(standardDevMatrix[i+k*7][stDevIndeces[k][j]]*(colorLength-1));
                                 
//                                 fill(255*colormap_hcl_1[r][0] , 255*colormap_hcl_1[g][1], 100 +155*(2*colormap_hcl_1[b][2]) );  // 
                                   fill(colorInts[19 - (int)(averageMatrix[i+k*7][stDevIndeces[k][j]]*19)], 100 +155*(2*colormap_hcl_1[b][2]) );  // 

                          rect(rowMargin+ (i + addedWeight+k*10)*cellWidth ,columnMargin +j * cellHeight ,cellWidth, cellHeight );                // draw the rectange of size 15,25 at the appropriate position, the position of the cell depends on its value in the table position (i,j)
                          }
                          
                          textAlign(CENTER ,CENTER );              // align text to CENTER
  
                          fill( 100);   
                          text(a[i%7], rowMargin+ (i + addedWeight)* cellWidth+cellWidth/2  , columnMargin*.9);  
    
                  }
              }
            }
            
         //the % is called modulo. It finds the remainder after division. So 21% 20 returns 1, 21%12 returns 7, 21%21 returns 0
        
        textAlign(CENTER ,CENTER );              // align text to CENTER
        fill( 0);                              // make color of text to light gray
        
//        for(int i = 0; i < numColumns; i++)
//            text(a[i%7], rowMargin+ (i + addedWeight)* cellWidth  , columnMargin*.9);  
  for(int j = 0; j<4; j++){
         for ( int i = 0 ; i<numColumns ;i++){
            if(AFLAG=='C'){           
                text( i+8 + ":00" , rowMargin-cellWidth +j*10*cellWidth , columnMargin+cellHeight/2+i*cellHeight);
            }
            else if(AFLAG == 'A'){
                text( avIndeces[j][i]+8 + ":00" ,  rowMargin-cellWidth +j*10*cellWidth , columnMargin+cellHeight/2+i*cellHeight);

            }
            else{
                text( stDevIndeces[j][i]+8 + ":00" , rowMargin-cellWidth +j*10*cellWidth , columnMargin+cellHeight/2+i*cellHeight);

            }
         }
  }
      
//        
//        text( "Arts" , rowMargin * 0.75, columnMargin + cellHeight/2 );
//        text( "Astronomy" , rowMargin * 0.75, columnMargin + cellHeight/2 +   cellHeight);
//        text( "Home+Family" , rowMargin * 0.75, columnMargin + cellHeight/2 +  2 * cellHeight);
//        text( "Literature" , rowMargin * 0.75, columnMargin + cellHeight/2 +  3 * cellHeight);

            text( "Arts"  , rowMargin + cellWidth*3.5  , columnMargin/2);
            text("Astronomy"  , rowMargin + cellWidth*3.5 +  cellWidth*10, columnMargin/2);
            text("Home+Family"  , rowMargin + cellWidth*3.5 +  cellWidth*20, columnMargin/2);
            text("Literature"  , rowMargin + cellWidth*3.5 +  cellWidth*30, columnMargin/2);


        // repeat the process for day numbers
//        for ( int i = 1 ; i<=13 ;i++)
//            text( i+7 + ":00" , rowMargin -  cellWidth/2 + i * cellWidth  , height- 1.25 * columnMargin);
//            
        if ( frameCount % 20 ==0)
           {
//             println( "draw called " + frameCount );                    // here we are printing out the frameCount ( how many frames have been drawn so far) 
           }
}


int[] mySort(float[] a, int[] indeces){
     int j;
     boolean flag = true;   // set flag to true to begin first pass
     int temp;   //holding variable

     while ( flag )
         {
            flag= false;    //set flag to false awaiting a possible swap
            for( j=0;  j < a.length -1;  j++ )
            {
                   if ( a[ j ] < a[j+1] )   // change to > for ascending sort
                   {
//                           temp = num[ j ];                //swap elements
//                           num[ j ] = num[ j+1 ];
//                           num[ j+1 ] = temp;
                           swap(a,indeces, j, j+1);
                          flag = true;              //shows a swap occurred  
                  } 
            } 
      } 
  return indeces;
}

void swap(float[] a, int[] ind, int b, int c){
  int indTmp;
  float tmp;
  tmp = a[b];
  indTmp = ind[b];
  a[b] = a[c];
  ind[b]=ind[c];
  a[c] = tmp;
  ind[c] = indTmp;
}
keypressed:

Code: Select all

void keyPressed() {
         if( key == 'a' ){
           AFLAG = 'A';
         }
         else if(key == 'c'){
          AFLAG = 'C'; 
         }
         else if(key == 's'){
          AFLAG = 'S'; 
         }

  
  
  
}
Attachments
sketch_2darrayv2.zip
project zipped
(10.45 KiB) Downloaded 252 times
Last edited by dimberman on Thu Feb 05, 2015 11:24 am, edited 2 times in total.

matzewagner
Posts: 5
Joined: Sat Jan 10, 2015 11:35 am

Re: Proj 3: 2D Reorderable Matrix

Post by matzewagner » Thu Feb 05, 2015 10:29 am

I used my project 2 code to reorder the 2 dimensional matrix by highest checkouts per row and highest checkouts per column via key commands. I implemented an interactive display of the cell data, when hovered over with the mouse, and added a few additional color schemes.
screenShot1680.jpg
unsorted
screenShot2076.jpg
sorted by row
screenShot3105.jpg
sorted by column sum
processing sketch

Code: Select all

// 2D reorderable matrix MAT259 Project 3, Winter 2015, Matthias Wagner
// initialize tables
int [][] dataMatrix = null; 
int [][] rowWeightedMatrix = null; 
int [][] columnWeightedMatrix = null; 
int [][] maxCellMatrix = null;
int [][] cellInRow = null;
int [][] cellInRowCopy = null;

Table myTable; 
int numRows; 
int numColumns;
int maxCount; 
// variables for row-weighted
int [] sumRows = null; 
int [] sumRowsCopy = null;
int [] rowIndexTracker = null;
int [] orderedRows = null; 
// variables for column-weighted
int [] sumColumns = null; 
int [] sumColumnsCopy = null;
int [] columnIndexTracker = null;
int [] orderedColumns = null; 
int [] maxInRow = null; 
int [][] maxColumnIndexTracker = null;
// display options
String [] orderedCategories = null; 
int colorPicker = 20; 
int cellWidth = 10; 
int cellHeight = 50; 
int xMargin, yMargin; 
int infoX, infoY;
int hoverX, hoverY; 
// labels
PFont font; 
String[] categories = { 
  "Adult VHS", "Adult DVD", "Youth VHS", "Youth DVD", "CD-ROM", 
  "Audio CD", "Audio Cassette", "Diskette", "Other"
};
String[] years = { 
  "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012"
};
// variables for hover
int currentValue; 
String currentCategory; 
int currentMonth;
int currentYear; 

boolean initialFlag = true; 
boolean rowFlag = false; 
boolean columnFlag = false; 
boolean maxCellFlag = false; 

void setup() {
  size(1280, 800); 
  smooth(); 

  font = createFont("Futura", 10);

  myTable = loadTable("GodB.csv", "header");
  numRows = myTable.getColumnCount(); 
  numColumns = myTable.getRowCount(); 

  dataMatrix = new int[numColumns][numRows];
  cellInRowCopy = new int[numRows][numColumns]; 
  rowWeightedMatrix = new int[numColumns][numRows];
  columnWeightedMatrix = new int[numColumns][numRows]; 

  maxCount = dataMatrix[0][0]; 
  sumRows = new int[numRows];
  sumRowsCopy = new int[numRows];
  rowIndexTracker = new int[numRows];
  orderedRows = new int[numRows];
  orderedCategories = new String[numRows];

  sumColumns = new int[numColumns];
  sumColumnsCopy = new int[numColumns];
  columnIndexTracker = new int[numColumns];
  orderedColumns = new int[numColumns];
  maxColumnIndexTracker = new int[numRows][numColumns];

  for ( int i=0; i<numColumns; i++) {
    for ( int j=0; j<numRows; j++) {
      dataMatrix[i][j] = myTable.getInt(i, j);

      if ( dataMatrix[i][j] > maxCount) {
        maxCount = dataMatrix[i][j];
      }
    }
  }
  println("  Rows: " + numRows + "\t\tColumns: " + numColumns + "\tMax Value: " + maxCount );

  // calculate rows
  for ( int i=0; i<numColumns; i++ ) {
    for ( int j=0; j<numRows; j++ ) {
      sumRows[j] += dataMatrix[i][j];
    }
  }
  for ( int i=0; i<numRows; i++ ) {
    sumRowsCopy[i] = sumRows[i];
    orderedCategories[i] = categories[i];
    rowIndexTracker[i] = i; 
    //println("row # " + i + " sum is: " + sumRows[i]);
  }

  for ( int i=0; i<numRows; i++) {
    for ( int j=i+1; j<numRows; j++) {
      if ( sumRowsCopy[i] < sumRowsCopy[j] ) {
        int tempSumRows = sumRowsCopy[i]; 
        sumRowsCopy[i] = sumRowsCopy[j]; 
        sumRowsCopy[j] = tempSumRows; 

        int tempRowIndex = rowIndexTracker[i]; 
        rowIndexTracker[i] = rowIndexTracker[j]; 
        rowIndexTracker[j] = tempRowIndex; 

        String tempCategory = orderedCategories[i]; 
        orderedCategories[i] = orderedCategories[j]; 
        orderedCategories[j] = tempCategory;
      }
    }
  }
  for ( int i=0; i<numColumns; i++) {
    for ( int j=0; j<numRows; j++) {
      int rowPointer = rowIndexTracker[j]; 
      rowWeightedMatrix[i][j] = dataMatrix[i][int(rowPointer)];
    }
  }

  // calculate columns
  for ( int i=0; i<numRows; i++ ) {
    for ( int j=0; j<numColumns; j++ ) {
      sumColumns[j] += dataMatrix[j][i];
      maxColumnIndexTracker[i][j] = (i+1)*(j+1);
    }
  }
  for ( int i=0; i<numColumns; i++ ) {
    sumColumnsCopy[i] = sumColumns[i];
    columnIndexTracker[i] = i; 
    //println("column # " + i + " sum is: " + sumColumns[i]);
  }
  for ( int i=0; i<numColumns; i++) {
    for ( int j=i+1; j<numColumns; j++) {
      if ( sumColumnsCopy[i] < sumColumnsCopy[j] ) {
        int tempSumColumns = sumColumnsCopy[i]; 
        sumColumnsCopy[i] = sumColumnsCopy[j]; 
        sumColumnsCopy[j] = tempSumColumns; 

        int tempColumnIndex = columnIndexTracker[i]; 
        columnIndexTracker[i] = columnIndexTracker[j]; 
        columnIndexTracker[j] = tempColumnIndex;
      }
    }
  }


  for ( int i=0; i<numColumns; i++) {
    for ( int j=0; j<numRows; j++) {
      int columnPointer = columnIndexTracker[i]; 
      int maxColumnPointer = maxColumnIndexTracker[j][i];
      columnWeightedMatrix[i][j] = dataMatrix[int(columnPointer)][j];
    }
  }
}


void draw() {
  colorMode(RGB);
  background(120, 120, 110);

  xMargin = int((width - (cellWidth * numColumns))/2);
  yMargin = int((height - (cellHeight * numRows))/2);
  strokeWeight(1);

  if ( initialFlag ) {
    for ( int i=0; i<numColumns-1; i++) { 
      for ( int j=0; j<numRows; j++) { 
        rectMode(CORNER);
        stroke(60);
        colorMode(HSB);
        fill(colorPicker, 128, pow((255*dataMatrix[i][j]/maxCount), 0.36) * 36);
        rect(xMargin + i*cellWidth +cellWidth/2, yMargin + j*cellHeight +cellHeight/2, cellWidth, cellHeight);
        if ( mouseX >= xMargin+(i-1)*cellWidth && mouseX >= xMargin+(i+1)*cellWidth 
          && mouseY >= yMargin + j*cellHeight && mouseY <= yMargin + (j+1)*cellHeight) {
          currentValue = dataMatrix[i][j];
          currentCategory = categories[j]; 
          currentMonth = (i%12)+1;
          currentYear = 2005 + i/12;
        }
      }
    }
    textAlign(CENTER, CENTER);
    textSize(13);
    colorMode(RGB);
    fill(255, 255, 220);
    for ( int i=0; i<numRows; i++) {
      text( categories[i], xMargin*0.6, yMargin + ((i+1)*cellHeight));
    }
  }


  if ( rowFlag ) {
    for ( int i=0; i<numColumns-1; i++) { 
      for ( int j=0; j<numRows; j++) { 
        rectMode(CORNER);
        stroke(60);
        colorMode(HSB);
        fill(colorPicker, 128, pow((255*rowWeightedMatrix[i][j]/maxCount), 0.36) * 36);
        rect(xMargin + i*cellWidth +cellWidth/2, yMargin + j*cellHeight +cellHeight/2, cellWidth, cellHeight);
        if ( mouseX >= xMargin+(i-1)*cellWidth && mouseX >= xMargin+(i+1)*cellWidth 
          && mouseY >= yMargin + j*cellHeight && mouseY <= yMargin + (j+1)*cellHeight) {
          currentValue = rowWeightedMatrix[i][j];
          currentCategory = orderedCategories[j]; 
          currentMonth = (i%12)+1;
          currentYear = 2005 + i/12;
        }
      }
    }
    textAlign(CENTER, CENTER);
    textSize(13);
    colorMode(RGB);
    fill(255, 255, 220);
    for ( int i=0; i<numRows; i++) {
      text( orderedCategories[i], xMargin*0.6, yMargin + ((i+1)*cellHeight));
    }
  }

  if ( columnFlag ) {
    for ( int i=0; i<numColumns-1; i++) { 
      for ( int j=0; j<numRows; j++) { 
        rectMode(CORNER);
        stroke(60);
        colorMode(HSB);
        fill(colorPicker, 128, pow((255*columnWeightedMatrix[i][j]/maxCount), 0.36) * 36);
        rect(xMargin + i*cellWidth +cellWidth/2, yMargin + j*cellHeight +cellHeight/2, cellWidth, cellHeight);
        if ( mouseX >= xMargin+(i-1)*cellWidth && mouseX >= xMargin+(i+1)*cellWidth 
          && mouseY >= yMargin + j*cellHeight && mouseY <= yMargin + (j+1)*cellHeight) {
          currentValue = columnWeightedMatrix[i][j];
          currentCategory = categories[j]; 
          currentMonth = 0;
          currentYear = 0;
        }
      }
    }
    textAlign(CENTER, CENTER);
    textSize(13);
    colorMode(RGB);
    fill(255, 255, 220);
    for ( int i=0; i<numRows; i++) {
      text( categories[i], xMargin*0.6, yMargin + ((i+1)*cellHeight));
    }
  }

  int colorBarxMargin = xMargin+cellWidth*48; 
  int colorBaryMargin = int(height - yMargin/2); 

  textFont(font, 13); 
  textAlign(CENTER, CENTER);
  for ( int i=0; i<cellWidth*48; i++) { 
    colorMode(HSB);
    stroke(colorPicker, 128, map(i, 0, 255, 0, cellWidth*18)); 
    if ( i%60==0 ) {
      stroke(60);
    }
    line(colorBarxMargin + i + cellWidth/2, colorBaryMargin, colorBarxMargin + i + cellWidth/2, colorBaryMargin+20);
    colorMode(RGB);
    fill(255, 255, 220);
    if ( i<=8 ) {
      text(i*200, colorBarxMargin+cellWidth/2 + i*colorBarxMargin/10.6, colorBaryMargin+30);
    }
  }


  textAlign(CENTER, CENTER);
  textSize(18);
  text("God's Preferred Electronic Medium", width/2, yMargin/1.7);

  textSize(13);
  if ( !columnFlag && !maxCellFlag ) {
    for ( int i=0; i<numColumns/12; i++ ) {
      text(years[i], xMargin + cellWidth*6.5 + i*12 * cellWidth, yMargin+((numRows+0.5)*cellHeight)+25);
    }
    for ( int i=1; i<=96; i+=12) {
      stroke(128, 128, 110);
      strokeWeight(1.5);
      line(xMargin + (i-1)*cellWidth + cellWidth/2, yMargin+cellHeight/2, xMargin+(i-1)*cellWidth + cellWidth/2, yMargin+cellHeight/2 + cellHeight*numRows);
    }
  }


  infoX = int(width/1.4);
  infoY = int(yMargin/1.75);

  textAlign(LEFT, CENTER); 
  textSize(14);
  text("number of check outs: " + "\ncategory: " + "\nmonth: " + "\nyear: ", infoX, infoY);
  if ( mouseX > xMargin+(cellWidth) && mouseX < xMargin+((numColumns-1)*cellWidth + cellWidth/2) 
    && mouseY > yMargin + cellHeight/2 && mouseY < yMargin + (numRows*cellHeight) + cellHeight/2) {
    colorMode(RGB);
    stroke(255, 255, 220);
    noFill();
    rectMode(CORNER);
    hoverX = mouseX - (mouseX%cellWidth); 
    hoverY = mouseY - (mouseY%cellHeight);
    rect(hoverX, hoverY, cellWidth, cellHeight);


    textAlign(RIGHT, CENTER); 
    text(currentValue + "\n" + currentCategory + "\n" + currentMonth + "\n" +  currentYear, infoX+200, infoY);
  }
  textAlign(LEFT, CENTER);
  text("'u' for unsorted table" + "\n" + "'r' for row-sorted table" + "\n" + "'c' for column-sorted table" + "\n" + "'x' to randomize color", xMargin, infoY); 
}

void keyPressed() {
  if ( key == 'r' ) {
    initialFlag = false;  
    columnFlag = false;
    maxCellFlag = false; 
    rowFlag = true;
  }
  if ( key == 'c' ) {
    initialFlag = false;  
    rowFlag = false;
    maxCellFlag = false; 
    columnFlag = true;
  }
  if ( key == 'u' ) {
    rowFlag = false; 
    columnFlag = false; 
    maxCellFlag = false;    
    initialFlag = true;
  }
  if ( key == 'x' ) 
    colorPicker = int(random(0, 255));

  if ( key == 'z' ) 
    colorPicker = 20;

//     if( key == ' ' )
//      saveFrame( "images/screenShot####.jpg" ); 
//      println(" screenshot taken ");
}

screenShot2285.jpg
alternative color scheme
screenShot3434.jpg
alternative color scheme
Attachments
matthias_project_3.zip
(61.05 KiB) Downloaded 198 times

chicobrando
Posts: 5
Joined: Sat Jan 10, 2015 11:25 am

Re: Proj 3: 2D Reorderable Matrix

Post by chicobrando » Thu Feb 05, 2015 10:41 am

The project intends to build a reorderable TreeMap of Gothic Books by month, to answer the question if Gothic books are more read during rainy months. It is still a work in progress.

Treemap 2.0

In the new version of the reorderable TreeMap of Gothic Books by month, the following improvements were made:
(1) now it is possible to visualize each one of the seven Gothic Books, and the sum of all the books, with the keyReleased function. As the TreeMap also have four different layouts (SquarifiedLayout, PivotBySplitSize, SliceLayout and OrderedTreemap), one can have up to 32 different visualizations of the data.
(2) I added the covers of each book to make the identification easier; for the visualization of "All Gothic Books", I created a fake cover, using one image of the movie "Dracula". As all the covers have the black color as a common element, I also changed the background to black. This gives an impression that the covers are merging with the background, making the visual more clean and avoiding excessive use of different colors.
(3) I also colored the treemap, with a variation of colors according to the width and height of each cell. As most of the books have shades of red and blue, I decided to use shades of green in the treemap. I think that was the best way to divide the areas of the treemap and the text box, avoiding confusion.
Attachments
Gothictreemap.zip
(1.19 MiB) Downloaded 177 times
Treemap8.png
Treemap7.png
Treemap6.png
Treemap5.png
Treemap4.png
Treemap3.png
Treemap2.png
Treemap1.png
treemap5.png
treemap4.png
treemap3.png
treemap2.png
treemap1.png
Reordenable Treemap.zip
(6.2 KiB) Downloaded 211 times
Last edited by chicobrando on Tue Mar 24, 2015 1:04 am, edited 1 time in total.

boyan
Posts: 5
Joined: Tue Jan 14, 2014 11:48 am

Re: Proj 3: 2D Reorderable Matrix

Post by boyan » Tue Feb 10, 2015 8:47 am

Based on the csv file, I used a python code to sort the data by row, that is I sort the value in each of the second level dewey categories, the dewey classes that do not exist or are no longer in use are color coded in dark gray. You can click on the "sort" button to switch between sorted visualization or unsorted visualization. Since the original text label does not apply to the sorted version, I changed the label to be shown on the left bottom corner on MouseOver.

The reorderable version does make the pattern more obvious. As we can see from the sorted visualization, there are many unused classes in computer science categories. In general, religion and literature categories have less variance in checkout duration, and literature on average have more categories that have been checkout for longer periods, very much related with our general idea of how people read books and their purpose of borrowing books.

Code: Select all


import controlP5.*;

ControlP5 cp5;
RadioButton r;

// cell size
int cellWidth = 10;
int cellHeight = 65;

//margin
int rowMargin = 145;
int colMargin = 75;

// matrix to store data
double[][] dataMatrix;
double[][] sortedDataMatrix;
double[][] sortedIndexMatrix;

// create a table to store matrix data
Table myTable;
Table myTableSorted;
Table myTableIndex;

int rowNum, colNum;
int rowNumSorted, colNumSorted;
int rowNumIndex, colNumIndex;

// create a font
PFont myFont;

int[][] colorbrewerG = {
    {237,248,233}, // light
    {199,233,192},
    {161,217,155},
    {116,196,118},
    {65,171,93},
    {35,139,69},
    {0,90,50}, // dark
    {80,80,80} // no data
};

int colorbrewerSelect(double value){
    int selector;
    if (value<0) {
        selector = 7;
    } 
    else if (value>=0 && value<40.77981) {
        selector = 6;
    } 
    else if (value>=40.77981 && value<46.17083) {
        selector = 5;
    }
    else if (value>=46.17083 && value<52.38916) {
        selector = 4;
    }
    else if (value>=52.38916 && value<59.87942) {
        selector = 3;
    }
    else if (value>=59.87942 && value<71.76164) {
        selector = 2;
    }
    else if (value>=71.76164 && value<113.69310) {
        selector = 1;
    } else {
        selector = 0;
    }
     
    return selector;
}

void setup() {
    //set the canvas size to 1280*800, use the PGraphicsRetina2D renderer
    size(1280, 800, "processing.core.PGraphicsRetina2D"); 
    colorMode(RGB); //set the default colormode to RGB
    //frame.setResizable(true); //make the window resizable

    //activate smoothing anti-aliasing functions between pixels
    smooth();
    cp5 = new ControlP5(this);
    r = cp5.addRadioButton("radioButton")
           .setPosition(width-rowMargin+2*cellWidth, 100)
           .setColorForeground(color(120))
           .setColorActive(color(255))
           .setColorLabel(color(255))
           .setSize(20,20)
           .setSpacingRow(10)
           .addItem("Sort",4)
           ;
    //r.activate("000-999");
 
    
    // set the font to size 16 and helvetica, smooth is true
    myFont = createFont("Helvetica", 16, true);
    
    textAlign(CENTER, CENTER);
    
    //read the csv data, ignore the first line (header)
    myTable = loadTable("outputAvg.csv", "header");
    rowNum = myTable.getRowCount();
    colNum = myTable.getColumnCount()-1; //The 1st col is not data
    
    myTableSorted = loadTable("sortedAvg.csv", "header");
    rowNumSorted = myTableSorted.getRowCount();
    colNumSorted = myTableSorted.getColumnCount();
    
    myTableIndex = loadTable("sortedIndex.csv");
    rowNumIndex = myTableIndex.getRowCount();
    colNumIndex = myTableIndex.getColumnCount();

    
    //initialize data matrix
    dataMatrix = new double[rowNum][colNum];
    sortedDataMatrix = new double[rowNumSorted][colNumSorted];
    sortedIndexMatrix = new double[rowNumIndex][colNumIndex];
    
    //copy the table to the datamatrix
    for (int i=0; i<rowNum; i++) {
        //start from the 2nd col, the 1st col is not the data
        for (int j=0; j<colNum; j++) {
            dataMatrix[i][j] = myTable.getFloat(i,j+1);
            //print(dataMatrix[i][j] + " ");
        }
        //println();
    }
    
    for (int i=0; i<rowNumSorted; i++) {
        for (int j=0; j<colNumSorted; j++) {
            sortedDataMatrix[i][j] = myTableSorted.getFloat(i,j);
            //print(dataMatrix[i][j] + " ");
        }
        //println();
    }
    
    for (int i=0; i<rowNumIndex; i++) {
        for (int j=0; j<colNumIndex; j++) {
            sortedIndexMatrix[i][j] = myTableIndex.getFloat(i,j);
            //print(dataMatrix[i][j] + " ");
        }
        //println();
    }
    
    
}


void draw() {
  
    background(0); //refresh background
    
    textFont(myFont);
    
    
    stroke(255);
    strokeWeight(0.5);
    
    if (!r.getState("Sorted")) {
        background(0);
        for (int i=0; i<rowNum; i++) {
            for (int j=0; j<colNum; j++) {
                int fillR = colorbrewerG[colorbrewerSelect(dataMatrix[i][j])][0];
                int fillG = colorbrewerG[colorbrewerSelect(dataMatrix[i][j])][1];
                int fillB = colorbrewerG[colorbrewerSelect(dataMatrix[i][j])][2];
                fill(fillR,fillG,fillB);
                rect(rowMargin-9*5+i*cellWidth+(i/10)*5,colMargin+j*cellHeight,cellWidth,cellHeight);
                
              fill(255);
              if (mouseX>rowMargin-9*5+i*cellWidth+(i/10)*5 && mouseX < rowMargin-9*5+(i+1)*cellWidth+((i)/10)*5 && mouseY>colMargin+j*cellHeight && mouseY<colMargin+(j+1)*cellHeight) {
                  if ((i*10+j)<10) {
                      text("Dewey Class: " + "00" + (i*10+j), rowMargin, height - colMargin/2);
                  } else if ((i*10+j)>=10 && (i*10+j)<100) {
                      text("Dewey Class: " + "0" + (i*10+j), rowMargin, height - colMargin/2);
                  } else {
                      text("Dewey Class: " + (i*10+j), rowMargin, height - colMargin/2);
                  }
                  
              }
       
            }
        }
    }
    //background(0);
    if (r.getState("Sort")) {
        background(0);
        for (int i=0; i<rowNumSorted; i++) {
            for (int j=0; j<colNumSorted; j++) {
                int fillR = colorbrewerG[colorbrewerSelect(sortedDataMatrix[i][j])][0];
                int fillG = colorbrewerG[colorbrewerSelect(sortedDataMatrix[i][j])][1];
                int fillB = colorbrewerG[colorbrewerSelect(sortedDataMatrix[i][j])][2];
                fill(fillR,fillG,fillB);
                rect(rowMargin-9*5+i*cellWidth+(i/10)*5,colMargin+j*cellHeight,cellWidth,cellHeight);
       
            }
        }
        for (int i=0; i<rowNumIndex; i++) {
            for (int j=0; j<colNumIndex; j++) {
                fill(255);
              if (mouseX>rowMargin-9*5+i*cellWidth+(i/10)*5 && mouseX < rowMargin-9*5+(i+1)*cellWidth+((i)/10)*5 && mouseY>colMargin+j*cellHeight && mouseY<colMargin+(j+1)*cellHeight) {
                  if ((i*10+sortedIndexMatrix[i][j])<10) {
                      text("Dewey Class: " + "00" + (int)(i*10+sortedIndexMatrix[i][j]), rowMargin, height - colMargin/2);
                  } else if ((i*10+sortedIndexMatrix[i][j])>=10 && (i*10+sortedIndexMatrix[i][j])<100) {
                      text("Dewey Class: " + "0" + (int)(i*10+sortedIndexMatrix[i][j]), rowMargin, height - colMargin/2);
                  } else {
                      text("Dewey Class: " + (int)(i*10+sortedIndexMatrix[i][j]), rowMargin, height - colMargin/2);
                  }
                  
              }
       
            }
        }
        
    }

    textFont(myFont, 7);
    
    for (int i=0; i<8; i++){
        fill(colorbrewerG[i][0],colorbrewerG[i][1],colorbrewerG[i][2]);
        rect(width-rowMargin+3*cellWidth, height-colMargin-5-7*(7-i), 30, 5);
    }
    
    fill(255);
    text(">=113", width-rowMargin+3*cellWidth+50, height-colMargin-4-7*7);
    text("71 - 113", width-rowMargin+3*cellWidth+50, height-colMargin-4-7*6);
    text("59 - 71", width-rowMargin+3*cellWidth+50, height-colMargin-4-7*5);
    text("52 - 59", width-rowMargin+3*cellWidth+50, height-colMargin-4-7*4);
    text("46 - 52", width-rowMargin+3*cellWidth+50, height-colMargin-4-7*3);
    text("40 - 46", width-rowMargin+3*cellWidth+50, height-colMargin-4-7*2);
    text("0 - 40", width-rowMargin+3*cellWidth+50, height-colMargin-4-7*1);
    text("No Data", width-rowMargin+3*cellWidth+50, height-colMargin-4-7*0);
    text("Legend", width-rowMargin+3*cellWidth+13, height-colMargin-3-60);
    
    textFont(myFont, 30);
    
    text("Average Checkout Duration of Dewey Classification", width/2, colMargin/2);


}

The project and data is attached
Attachments
Screen Shot 2015-02-10 at 8.48.31 AM.png
MAT259_PROJ3_BYAN.zip
(22.76 KiB) Downloaded 199 times

Post Reply