PROJ 2: 3D INTERACTION & CHANGE OVER TIME

glegrady
Posts: 203
Joined: Wed Sep 22, 2010 12:26 pm

PROJ 2: 3D INTERACTION & CHANGE OVER TIME

Post by glegrady » Sat Dec 26, 2015 6:20 pm

PROJ 2: 3D INTERACTION & CHANGE OVER TIME

In this assignment, we are moving into interactive 3D volumetric visualization.

Query
Your query will need to have minimum 4 columns for x,y,z location and then to color or scale the pixel/voxel. Your MySQL query should be more complex then previous ones. Stay away from the larger tables (_rawXmlDataCheckIns, _rawXmlDataCheckOuts) and instead explore the various "x_..." tables prepared by Karl Yerkes, or else use the JOIN function to search in multiple tables. As usual, you are expected to come up with an interesting question that will give interesting results! Your query should use MySQL syntax that has NOT been presented in the demos, and the query should go for detail.

--------------
3D Volumetric, Spacial Visualization
3D volumetric representation is an ideal method to express data that is time-based, for instance check-out/check-in, or “change over time”, or mapping different media, searching data based on titles and subject, showing fluctuations. The important thing is that the x,y,z location of how the data is placed should have meaning.

--------------
Technical Introduction
3D spatial navigation and interactivity is introduced using the PeasyCam library: http://mrfeinberg.com/peasycam/

ControlP5 is a GUI and controller library that includes functions like Sliders, Buttons, Toggles, Knobs, Textfields, RadioButtons, etc. http://www.sojamo.de/libraries/controlP5/

OpenGL (Open Graphics Library), a cross-platform graphics interface is used in this demo. Translate, pushmatrix, popmatrix functions are introduced. Information about push, pop and translation can be found at:
https://www.processing.org/tutorials/transform2d/
http://processing.org/tutorials/p3d

--------------
Assignment Criteria
Use the full capabilities of 3D where each x,y,z location represents data. You may map data directly into 3D space based on the 4 datasets, or explore clustering algorithms as a means of organizing the data in 3D space.

This assignments requires
granular definition
in 3D space (increased data to achieve visual detail), so mapping main Dewey categories will not be sufficient, nor fulfill the expectation of an interesting query.
George Legrady
legrady@mat.ucsb.edu

qiu0717
Posts: 9
Joined: Wed Jan 06, 2016 1:44 pm

Re: PROJ 2: 3D INTERACTION & CHANGE OVER TIME

Post by qiu0717 » Mon Feb 08, 2016 10:57 pm

What's the 7 prevalently checked out items
about the 7 deadly sins?

Weihao Qiu

This time, I mainly made updates to enhance the interaction. All interaction methods are now can be completed by mouse click.
000362_2.jpg
New Interactions
Interaction:
1. To add or minus the selected year you want to look, which range from 1990 to 2014.
2. To choose to see or not to see data of other year than the selected year.
3. To control the type of items to show.
4. The four buttons are used to :
(1).Control the mode of viewing
(2).Whether rotate automatically
(3).Whether show as black background or white background
(4).Whether to show the grahpic user interface.
5. To control the sin you want to see. Single click for choose single one sin. Double click for seeing all seven sins.

Additionally, to suit different taste, I made a black version of this visualization. These two version can be switched through a button on the bottom of the visualization.
000362.jpg
Black mode & White mode

The new processing code:

1.DataVis_3dVisualization_version2.pde:

Code: Select all

import controlP5.*;
import peasy.*;
import processing.opengl.*;

PeasyCam cam;
ControlP5 cp5;
ListBox l;

// Data parameters
Table dataTable;
int rowNums, colNums;
int[] MaxCheckoutCount, MinCheckoutCount;
String[] sevenDeadlySins; 

// Drawing setting
float overallRadius, panelDistance;
PVector[] Points; 
int presentYear;
float interpolatorYear;
Integrator[] interpolator;
float rotateX, rotateY, rotateZ;

// Color & fonts
color[] colors;
PFont[] fonts;

// Control parameters
int viewMode;
boolean showOtherYear, showBook, showVideo, showAudio, rotateFree, autoRotate, showGUI, onlyStillFrame, blackOrWhite;
boolean[] titleSelected;
boolean mouseOnBook, mouseOnVideo, mouseOnAudio, interactWithSin, interactWithButtons;
boolean[] mouseOnSins, showTheSin;
boolean mouseOnUpTriangle, mouseOnDownTriangle, mouseOnPresentYear;

RectButton[] rectButtons;

void setup() {
  fullScreen(P3D);
  //size(800, 800, P3D);
  cam = new PeasyCam(this, 250);
  cam.setWheelScale(0.3);
  cam.setDistance(2000);


  //Initialization for data
  //
  dataTable = loadTable("query_result.csv", "header");  
  rowNums = dataTable.getRowCount();
  colNums = dataTable.getColumnCount();

  MaxCheckoutCount = new int[7];
  MinCheckoutCount = new int[7];
  for (int i = 0; i< 7; i++) {
    MaxCheckoutCount[i] = 0;
    MinCheckoutCount[i] = 100000;
  }
  for (int i = 0; i<rowNums; i++) {
    TableRow row = dataTable.getRow(i);
    int index = whichDeadlySin(row.getString(2)); 
    int checkoutCount = row.getInt(4);
    if (checkoutCount > MaxCheckoutCount[index]) MaxCheckoutCount[index] = checkoutCount;
    if (checkoutCount < MinCheckoutCount[index]) MinCheckoutCount[index] = checkoutCount;
  }

  sevenDeadlySins = new String[7];
  sevenDeadlySins[0] = "Lust";
  sevenDeadlySins[1] = "Gluttony";
  sevenDeadlySins[2] = "Greed";
  sevenDeadlySins[3] = "Wrath";
  sevenDeadlySins[4] = "Sloth";
  sevenDeadlySins[5] = "Envy";
  sevenDeadlySins[6] = "Pride";


  // Initializaiton for drawing 
  //
  rotateX = 0;
  rotateY = 0;
  rotateZ = 0;

  viewMode = 1;
  showOtherYear = true;
  showBook = true;
  showVideo = true;
  showAudio = true;
  rotateFree = true;
  showGUI = true;
  autoRotate = false;
  onlyStillFrame = false;
  mouseOnBook = false;
  mouseOnVideo = false; 
  mouseOnAudio = false; 
  interactWithSin = false;
  blackOrWhite = true;

  titleSelected = new boolean[rowNums];
  for (int i = 0; i<rowNums; i++) {
    titleSelected[i] = false;
  }

  mouseOnSins = new boolean[7];
  showTheSin = new boolean[7];  
  for (int i= 0; i<7; i++) {
    mouseOnSins[i] = false;
    showTheSin[i] = true;
  }

  overallRadius = 400;
  panelDistance = 70;
  presentYear = 1990;
  interpolator = new Integrator[4];  
  interpolator[0] = new Integrator(presentYear, 0.4, 0.08);
  interpolator[1] = new Integrator(rotateX, 0.4, 0.16);
  interpolator[2] = new Integrator(rotateY, 0.4, 0.16);
  interpolator[3] = new Integrator(rotateZ, 0.4, 0.16);

  Points = new PVector[7];
  for (int i = 0; i<7; i++) {
    float x, y;
    x = overallRadius*cos(i*2*PI/7);
    y = overallRadius*sin(i*2*PI/7);
    Points[i] = new PVector(x, y, 0);
  }


  // Initialize colors & fonts
  //
  colors = new color[10];
  colors[0] = #0A86D0;
  colors[1] = #134ED5;
  colors[2] = #6D5CAF;
  colors[3] = #D2000D;
  colors[4] = #EB6002;
  colors[5] = #FFBC00;
  colors[6] = #019C69;
  colors[7] = #D42020;
  if (blackOrWhite) {
    colors[9] = #FFFFFF;
    colors[8] = #101010;
  } else {
    colors[8] = #FFFFFF;
    colors[9] = #000000;
  }

  fonts = new PFont[3];
  fonts[0] = loadFont("OratorStd-48.vlw");
  fonts[1] = loadFont("OratorStd-12.vlw");

  controllerSetup();


  noLights();
  smooth();
}

void draw() {
  background(colors[8]);

  for (int i = 0; i < interpolator.length; i++) {
    interpolator[i].update();
  }
  interpolatorYear = interpolator[0].value;

  // When rotation during the viewmode changing is completed, rotation is restored to be free.
  if (!rotateFree) {
    if (abs(interpolator[1].value - interpolator[1].target)<0.0001 
      && abs(interpolator[2].value - interpolator[2].target)<0.0001 
      && abs(interpolator[3].value - interpolator[3].target)<0.0001) rotateFree = true;
    else cam.setRotations(interpolator[1].value, interpolator[2].value, interpolator[3].value);
  } else
    setRotationInterpolator(cam.getRotations()[0], cam.getRotations()[1], cam.getRotations()[2]);

  for (int i = 0; i<rowNums; i++) {
    if ((l.getItem(i).get("state").toString().equals("true"))) {  
      titleSelected[i] = true;
    } else
      titleSelected[i] = false;
  }

  drawStillFrame();
  if (!onlyStillFrame) {
    for (int i= 0; i<rowNums; i++) {    
      drawTableRow(i);
    }
  }

  if (autoRotate) {
    if (viewMode == 1)cam.rotateZ(0.002);
    if (viewMode == 2)cam.rotateX(0.002);
    if (viewMode == 3)cam.rotateY(0.002);
  }

  mouseInteraction();
  hint(DISABLE_DEPTH_TEST);
  cam.beginHUD();
  if (showGUI) gui();
  drawButtons();
  cam.endHUD();
  hint(ENABLE_DEPTH_TEST);
}


void drawTableRow(int i) {
  TableRow row = dataTable.getRow(i);
  String type = row.getString(1);
  String theSin = row.getString(2);
  int year = row.getInt(3);
  if (year<1990) year = 1990;
  int index = whichDeadlySin(theSin);

  // Judgement about itemType
  // If selected, then show.
  //
  boolean shouldShow = false;
  if (type.equals("Book") && showBook) shouldShow = true;
  if (type.equals("Video") && showVideo) shouldShow = true;
  if (type.equals("Audio") && showAudio) shouldShow = true;

  if (shouldShow) {
    float percent = sqrt(sqrt(map(row.getFloat(4), MinCheckoutCount[index], MaxCheckoutCount[index], 0, 1)));
    float percent1 = map(percent, 0, 1, 0.1, 0.9);
    PVector p = PVector.lerp(Points[index], Points[(index+1)%7], percent1);
    float z = (year - interpolatorYear) * panelDistance;

    beginShape(LINES);
    colorMode(HSB, 255);
    color theColor = color(hue(colors[index]), saturation(colors[index])*0.9, brightness(colors[index]));

    // Judgement for each row's diplay mode
    //
    int mode = 0;
    if (showTheSin[index])
      mode = 2;
    else 
    mode = 4;
    if (titleSelected[i]==true) mode = 3;
    else {
      if ( mode != 4) {
        if (presentYear == year) mode = 1;
        else {
          if (showOtherYear ) mode = 2;
          else mode =4;
        }
      }
    }

    // Display according to its diplay mode
    //
    switch (mode) {

    case 1:
      // #1 YearSelected
      stroke(theColor, 100);
      strokeWeight(1.5);
      vertex(p.x, p.y, p.z);
      stroke(theColor, 250);
      strokeWeight(max(10*percent, 1.5));
      vertex(0, 0, z);
      break;

    case 2:
      // #2 Visible
      stroke(theColor, 40);
      strokeWeight(1);
      vertex(p.x, p.y, p.z);
      stroke(theColor, 110);
      strokeWeight(max(10*percent, 1));
      vertex(0, 0, z);
      break;

    case 3:
      // #3 TitleSelected
      stroke(colors[9], 100);
      strokeWeight(3);
      vertex(p.x, p.y, p.z);
      stroke(colors[9], 200);
      strokeWeight(max(10*percent, 3));
      vertex(0, 0, z);
      break;

    case 4 :
      // #4 Invisible
      stroke(hue(colors[index]), saturation(colors[index])*0.1, brightness(colors[index])*0.1, 50);
      strokeWeight(0.5);
      vertex(p.x, p.y, p.z);
      strokeWeight(0.5);
      vertex(0, 0, z);
    }
    endShape();


    // Show titles of items published at selected year
    //
    if ((year == presentYear && mode != 4 )|| titleSelected[i]) { 
      pushMatrix();
      translate(p.x, p.y, p.z);
      rotateY(PI/2);
      rotateX(((7-index)+0.5)*2*PI/7 - PI/4);
      rotateZ(PI);
      fill(colors[9], 200);
      textFont(fonts[0], 8);
      textAlign(LEFT);
      String title = row.getString(0);
      text(str(row.getInt(4))+"  "+title, 0, 0, 0);
      popMatrix();
    }
  }
}

// A mapping between index and sins
//
int whichDeadlySin(String theSin) {
  int index=0;
  if (theSin.equals("Lust"))     index = 0;
  if (theSin.equals("Gluttony")) index = 1;
  if (theSin.equals("Greed"))    index = 2;
  if (theSin.equals("Wrath"))    index = 3; 
  if (theSin.equals("Sloth"))    index = 4;
  if (theSin.equals("Envy"))     index = 5;
  if (theSin.equals("Pride"))    index = 6;
  return index;
}
2.Integrator.pde

Code: Select all

  /*

Original Author: Ben Fry
From book Visualizing Data

*/

class Integrator {

  final float DAMPING = 0.5f;
  final float ATTRACTION = 0.2f;

  float value;
  float vel;
  float accel;
  float force;
  float mass = 1;

  float damping = DAMPING;
  float attraction = ATTRACTION;
  boolean targeting;
  float target;


  Integrator() { }


  Integrator(float value) {
    this.value = value;
  }


  Integrator(float value, float damping, float attraction) {
    this.value = value;
    this.damping = damping;
    this.attraction = attraction;
  }


  void set(float v) {
    value = v;
  }


  void update() {
    if (targeting) {
      force += attraction * (target - value);      
    }

    accel = force / mass;
    vel = (vel + accel) * damping;
    value += vel;

    force = 0;
  }


  void target(float t) {
    targeting = true;
    target = t;
  }


  void noTarget() {
    targeting = false;
  }
}
3.Button.pde

Code: Select all

class RectButton {
  float x;
  float y;
  float w;
  float h;
  Boolean status;
  color pressedColor;
  color hoverColor;
  color onColor;
  color offColor;

  RectButton(float _x, 
    float _y, 
    float _w, 
    float _h, 
    Boolean _status, 
    color _pressedColor, 
    color _hoverColor, 
    color _onColor, 
    color _offColor) 
  {
    x = _x;
    y = _y;
    w = _w;
    h = _h;
    status = _status;
    pressedColor = _pressedColor;
    hoverColor = _hoverColor;
    onColor = _onColor;
    offColor = _offColor;
  }

  void draw() {
    noStroke();
    if (this.mouseOnButton()) {
      if (mousePressed) fill(pressedColor);
      else fill(hoverColor);
    } else {
      if (status) fill (onColor);
      else fill(offColor);
    }
    rectMode(CENTER);
    rect(x, y, w, h);
  }

  boolean mouseOnButton() {
    return (between(mouseX, x-w/2, x+w/2) && between(mouseY, y-h/2, y+h/2));
  }

  void setStatus(boolean _status) {
    status = _status;
  }
  void changeStatus() {
    status = !status;
  }
}

boolean between(float a, float b, float c ) {
  return ((a>=b)&&(a<=c)) || ((a>=c)&&(a<=b));
}
4.Interaction.pde

Code: Select all

void mouseInteraction() {

  // Judgement for which sin the mouse is hovering on
  //
  PVector center = new PVector(width*7/8, height*13/16);
  PVector mouse = new PVector(mouseX, mouseY);
  PVector mouseToCenterDistance = mouse.sub(center);
  float angle = PVector.angleBetween(mouseToCenterDistance, new PVector(1.f, 0.f));
  for (int i= 0; i<7; i++) {
    mouseOnSins[i] = false;
  }
  if (mouseToCenterDistance.mag() < overallRadius/3) {
    interactWithSin = true;
    if (angle < 2*PI/7) {
      if (mouseY > center.y) mouseOnSins[0] = true;
      else mouseOnSins[6] = true;
    } else if (angle < 4*PI/7) {
      if (mouseY > center.y) mouseOnSins[1] = true;
      else mouseOnSins[5] = true;
    } else if (angle < 6*PI/7) {
      if (mouseY > center.y) mouseOnSins[2] = true;
      else mouseOnSins[4] = true;
    } else mouseOnSins[3] = true;
    //println(degrees(angle));
  } else if (interactWithSin) {
    interactWithSin = false;
  }

  // Judgement for wheter user is interacting with the 4 buttons
  //
  interactWithButtons = false;
  for (int i = 0; i< 4; i++) {
    if (rectButtons[i].mouseOnButton()) {
      interactWithButtons = true;
    }
  }
}

void mousePressed() {
  // ItemType interaction
  //
  if (mouseOnBook) showBook = !showBook;
  if (mouseOnAudio) showAudio = !showAudio;
  if (mouseOnVideo) showVideo = !showVideo;

  // Show other years' items or just the present years'
  //
  if (mouseOnPresentYear) showOtherYear = !showOtherYear;

  // Uptriangle and downtriangle interaction
  //
  if (mouseOnUpTriangle) {
    presentYear ++;
    interpolator[0].target(presentYear);
  }
  if (mouseOnDownTriangle) {
    presentYear --;
    interpolator[0].target(presentYear);
  }

  // seven short lines interaction for choosing the sin user want to see
  //
  for (int i= 0; i<7; i++) {
    if (mouseOnSins[i]) {
      if (showTheSin[i] == true && showTheSin[(i+1)%7]== false) {
        for (int j= 0; j<7; j++) {
          showTheSin[j] = true;
        }
      } else {
        for (int j= 0; j<7; j++) {
          if (j != i) showTheSin[j] = false;
          else showTheSin[j] = true;
        }
      }
    }
  }

  // Buttons' interaction
  //
  for (int i = 0; i <4; i++) {
    if (rectButtons[i].mouseOnButton()) {
      switch (i) {
      case 0 : 
        viewMode++; 
        viewMode = viewMode % 3+1;
        switch (viewMode) {
        case 1: 
          cam.setDistance(2000);
          setRotationInterpolator(0, 0, 0);
          break;
        case 2: 
          setRotationInterpolator(0, -PI/2, 0);
          rotateFree = false;
          break;
        case 3: 
          viewMode = 3;
          setRotationInterpolator(-PI/2, -PI/2, 0);
          rotateFree = false;
        }
        break;
      case 1 : 
        autoRotate = !autoRotate; 
        break;
      case 2 :
        blackOrWhite = !blackOrWhite;
        if (blackOrWhite) {
          colors[9] = #FFFFFF;
          colors[8] = #101010;
        } else {
          colors[8] = #FFFFFF;
          colors[9] = #000000;
        }
        controllerSetup();
        break;
      case 3 : 
        showGUI = !showGUI; 
        break;
      }
    }
  }
}

void keyPressed() {
  if (key == 'S' || key == 's') {
    saveFrame("######.jpg");
  }
  if (key == '=' || key =='+') {
    presentYear++;
    interpolator[0].target(presentYear);
  }
  if (key == '-' || key =='_') {
    presentYear--;
    interpolator[0].target(presentYear);
  }
  if (key == 'F' || key =='f') {
    rotateFree = !rotateFree;
  }
  if (key == 'T' || key == 't') {
    autoRotate = !autoRotate;
  }
  if (key == 'B' || key =='b') {
    showBook = !showBook;
  }
  if (key == 'V' || key =='v') {
    showVideo = !showVideo;
  }
  if (key == 'A' || key =='a') {
    showAudio = !showAudio;
  }
  if (key == 'Y' || key =='y') {
    showOtherYear = !showOtherYear;
  }
  if (key == 'H' || key == 'h') {
    showGUI = !showGUI;
  }
  if (key == 'C' || key == 'c') {
    for (int i =0; i<rowNums; i++) {
      l.getItem(i).put("state", false);
    }
  }
  if (key == 'P' || key == 'p') {
    onlyStillFrame = !onlyStillFrame;
  }
  if (key == '1') {
    viewMode = 1;
    cam.setDistance(1600);
    setRotationInterpolator(0, 0, 0);
  }
  if (key == '2') {
    viewMode = 2;
    setRotationInterpolator(0, -PI/2, 0);
    rotateFree = false;
  }
  if (key == '3') {
    viewMode = 3;
    setRotationInterpolator(-PI/2, -PI/2, 0);
    rotateFree = false;
  }
}

void setRotationInterpolator(float rx, float ry, float rz) {
  interpolator[1].set(cam.getRotations()[0]);
  interpolator[2].set(cam.getRotations()[1]);
  interpolator[3].set(cam.getRotations()[2]);
  interpolator[1].target(rx);
  interpolator[2].target(ry);
  interpolator[3].target(rz);
}
5.StillFrame.pde

Code: Select all

void drawStillFrame() {
  for (int i = 0; i< 7; i++) {
    // bar
    PVector p1 = PVector.lerp(Points[i], Points[(i+1)%7], 0.1);
    PVector p2 = PVector.lerp(Points[i], Points[(i+1)%7], 0.9);
    //println(p1);
    beginShape(LINES);
    strokeWeight(3);
    stroke(colors[i], 20);
    vertex(p1.x, p1.y, p1.z);
    strokeWeight(3);
    if (showTheSin[i]) {
      stroke(colors[i], 200);
    } else {
      stroke(colors[i], 20);
    }
    vertex(p2.x, p2.y, p2.z);
    endShape();

    fill(colors[9]);
    // count label
    pushMatrix();
    translate(p2.x, p2.y, p2.z);
    rotateZ((2*i+1)*PI/7+PI);
    textAlign(RIGHT, TOP);
    textFont(fonts[0], 20);
    text(str(MaxCheckoutCount[i]), -10, 0, 0);
    popMatrix();

    pushMatrix();
    translate(p1.x, p1.y, p1.z);
    rotateZ((2*i+1)*PI/7+PI);
    textAlign(RIGHT, BOTTOM);
    text(str(MinCheckoutCount[i]), -5, 0, 0);
    popMatrix();
  }

  beginShape(LINES);
  for (int i = 0; i< 7; i++) {
   PVector p1 = PVector.lerp(Points[i], Points[(i+1)%7], 0.1);
   PVector p2 = PVector.lerp(Points[i], Points[(i+1)%7], 0.9);
   //println(p1);
   strokeWeight(3);
   if (showTheSin[i]) {
     stroke(colors[i], 255);
   } else {
     stroke(colors[i], 20);
   }
   vertex(p1.x*2, p1.y*2, p1.z);
   vertex(p2.x*2, p2.y*2, p2.z);
  }
  endShape();

  for (int i = 0; i< 7; i++) {
    PVector p3 = PVector.lerp(Points[i], Points[(i+1)%7], 0.5);
    pushMatrix();
    translate(p3.x*1.5, p3.y*1.5, p3.z);
    rotate((i+0.5)*2*PI/7+PI/2);
    fill(colors[9], 200);
    textAlign(CENTER, BOTTOM);
    textFont(fonts[0], 48);
    text(sevenDeadlySins[i], 0, 0, 0);
    popMatrix();
  }

  drawYearLabel();
}


void drawYearLabel() {
  for (int year = 1989; year<2015; year++) {
    float z = (year - interpolatorYear) * panelDistance;
    pushMatrix();
    translate(0, 0, z+2);
    rotateY(-PI/2);
    fill(colors[9], 200);
    textFont(fonts[0], 10);
    textAlign(LEFT);
    if (year== 1990)
      text("<"+str(year+1), 0, 0, 0);
    else if (year == 1989) {
      textFont(fonts[0], 20);
      text("Publish Year", -textWidth("Publish Year"), 0, 0);
      textFont(fonts[0], 10);
    } else
      text(str(year), 0, 0, 0);
    popMatrix();
  }
}
6.controller.pde

Code: Select all

void controllerSetup() {
  cp5 = new ControlP5(this);

  ControlFont labelFont = new ControlFont(fonts[0], 16);
  ControlFont valueFont = new ControlFont(fonts[1], 12);

  l = cp5.addListBox("myList")
    .setPosition(width/16, height/2 + 150)
    .setSize(width/4-width/16, 3*height/8 - 150)
    .setItemHeight(15)
    .setBarHeight(15)
    .setColorBackground(colors[8])
    .setColorActive(colors[9])
    .setColorForeground(0xFFEB6002)
    ;
  l.getCaptionLabel().toUpperCase(true);
  l.getCaptionLabel().set("Item Title");
  l.getCaptionLabel().setColor(colors[9]);
  l.getCaptionLabel().setFont(labelFont);
  l.getCaptionLabel().getStyle().marginTop= 5;
  l.getCaptionLabel().getStyle().marginLeft= -5;
  l.getValueLabel().setColor(colors[9]);
  l.getValueLabel().setFont(valueFont);
  l.getValueLabel().getStyle().marginTop= 5;
  l.getValueLabel().getStyle().marginLeft= -5;
  for (int i=0; i<rowNums; i++) {
    String title = nf(i, 3)+" "+ dataTable.getRow(i).getString(0);
    int maxLength = int((width/4-width/16)/7);
    if (title.length()>maxLength) title= title.substring(0, maxLength);
    l.addItem(title, i);
    CColor c = new CColor();
    //c.setBackground(0x14141400);
    c.setBackground(colors[8]);
    //println(c);
    l.getItem(title).put("color", c);
    //println(l.getItem(title));
  }
  cp5.setAutoDraw(false);
  
  
    
  // Initialize four buttons
  //
  float buttonSpacing = width/16;
  float buttonwidth = width/16*7/8;
  float buttonHeight = 5;
  float pressedColor = 90;
  float hoverColor = 128;
  float onColor = 180;
  float offColor = 40;

  rectButtons = new RectButton[4];
  rectButtons[0] = new RectButton(width/2-1.5*buttonSpacing, height*15/16-buttonHeight, buttonwidth, buttonHeight, true, color(pressedColor), color(hoverColor), color(onColor), color(offColor));
  rectButtons[1] = new RectButton(width/2-0.5*buttonSpacing, height*15/16-buttonHeight, buttonwidth, buttonHeight, autoRotate, color(pressedColor), color(hoverColor), color(onColor), color(offColor));
  rectButtons[2] = new RectButton(width/2+0.5*buttonSpacing, height*15/16-buttonHeight, buttonwidth, buttonHeight, blackOrWhite, color(pressedColor), color(hoverColor), color(onColor), color(offColor));
  rectButtons[3] = new RectButton(width/2+1.5*buttonSpacing, height*15/16-buttonHeight, buttonwidth, buttonHeight, showGUI, color(pressedColor), color(hoverColor), color(onColor), color(offColor));
}



void gui() {

  cp5.draw();

  float horizonalLocation = width/16;
  float verticalLocation = height/2;
  float dist = 25;

  fill(128, 30);
  noStroke();
  rectMode(CORNER);
  //rect(width/32, height/16, width/4, height/8);
  rect(width/32, height/2-height/16, width/4, height/2);

  boolean isMouseInX = (mouseX > width/32) && (mouseX<(width/4+width/32));
  boolean isMouseInY = (mouseY > (height/2-height/16)) && (mouseY <(height-height/16));
  boolean isMouseIn = isMouseInX && isMouseInY;

  if (isMouseIn||interactWithSin||interactWithButtons) cam.setActive(false);
  else cam.setActive(true);

  // -------------------------------------------------------------- //
  // Big Title
  //
  fill(colors[9], 200);
  textFont(fonts[1], 16);
  textAlign(LEFT, BOTTOM);
  text("The 7 prevalently checked out items of", horizonalLocation, height/8-20);
  textFont(fonts[0], 48);
  textAlign(LEFT, TOP);
  text("7 DEADLY SINS", horizonalLocation, height/8);

  // -------------------------------------------------------------- //
  // Present year label
  // (1). judgement
  //
  mouseOnPresentYear = between(mouseY, verticalLocation, verticalLocation+40) && 
    between(mouseX, horizonalLocation, horizonalLocation + textWidth(str(presentYear)));

  // (2). draw text
  //
  textAlign(LEFT, TOP);
  if (mouseOnPresentYear) {
    if (presentYear == 1990) {
      if (mousePressed) fill(colors[9], 200);
      else fill(colors[9], 120);
      textFont(fonts[0], 24);
      text("BEFORE ", horizonalLocation, verticalLocation-40);
      textFont(fonts[0], 48);
      text(str(presentYear+1), horizonalLocation, verticalLocation);
    } else if (presentYear > 1990 && presentYear < 2015) {
      if (mousePressed) fill(colors[9], 200);
      else fill(colors[9], 120);
      textFont(fonts[0], 48);
      text(str(presentYear), horizonalLocation, verticalLocation);
    } else {
      if (mousePressed) fill(colors[9], 200);
      else fill(colors[9], 120);
      textFont(fonts[0], 48);
      text(str(presentYear), horizonalLocation, verticalLocation);
    }
  } else {
    if (presentYear == 1990) {
      fill(colors[9], 200);
      textFont(fonts[0], 24);
      text("BEFORE ", horizonalLocation, verticalLocation-40);
      textFont(fonts[0], 48);
      text(str(presentYear+1), horizonalLocation, verticalLocation);
    } else if (presentYear > 1990 && presentYear < 2015) {
      fill(colors[9], 200);
      textFont(fonts[0], 48);
      text(str(presentYear), horizonalLocation, verticalLocation);
    } else {
      fill(colors[9], 40);
      textFont(fonts[0], 48);
      text(str(presentYear), horizonalLocation, verticalLocation);
    }
  }

  // -------------------------------------------------------------- //
  // Up and down Triangles for adjusting present year
  // (1). intitialization
  //
  PVector[] upTrianglePoints = new PVector[3];
  PVector[] downTrianglePoints = new PVector[3];
  upTrianglePoints[0] = new PVector(horizonalLocation + textWidth(str(presentYear)) + 10, verticalLocation-6);
  upTrianglePoints[1] = new PVector(horizonalLocation + textWidth(str(presentYear)) + 5, verticalLocation+10);
  upTrianglePoints[2] = new PVector(horizonalLocation + textWidth(str(presentYear)) + 15, verticalLocation+10); 
  downTrianglePoints[0] = new PVector(horizonalLocation + textWidth(str(presentYear)) + 10, verticalLocation+24+6);
  downTrianglePoints[1] = new PVector(horizonalLocation + textWidth(str(presentYear)) + 5, verticalLocation+24-10);
  downTrianglePoints[2] = new PVector(horizonalLocation + textWidth(str(presentYear)) + 15, verticalLocation+24-10);

  // (2). judgement
  //
  mouseOnUpTriangle = false;
  if (between(mouseY, upTrianglePoints[0].y, upTrianglePoints[1].y)) {
    float heightRatio = (mouseY - upTrianglePoints[0].y) / (upTrianglePoints[1].y-upTrianglePoints[0].y);
    PVector p1 = PVector.lerp(upTrianglePoints[0], upTrianglePoints[1], heightRatio);
    PVector p2 = PVector.lerp(upTrianglePoints[0], upTrianglePoints[2], heightRatio);
    if (between(mouseX, p1.x, p2.x)) {
      mouseOnUpTriangle = true;
    }
  }
  mouseOnDownTriangle = false;
  if (between(mouseY, downTrianglePoints[0].y, downTrianglePoints[1].y)) {
    float heightRatio = (mouseY - downTrianglePoints[0].y) / (downTrianglePoints[1].y-downTrianglePoints[0].y);
    PVector p1 = PVector.lerp(downTrianglePoints[0], downTrianglePoints[1], heightRatio);
    PVector p2 = PVector.lerp(downTrianglePoints[0], downTrianglePoints[2], heightRatio);
    if (between(mouseX, p1.x, p2.x)) {
      mouseOnDownTriangle = true;
    }
  }

  // (3). draw triagnles
  //
  if (mouseOnUpTriangle) {
    if (mousePressed) fill(colors[9], 200);
    else fill(colors[9], 120);
  } else fill(colors[9], 200);
  triangle(upTrianglePoints[0].x, upTrianglePoints[0].y, upTrianglePoints[1].x, upTrianglePoints[1].y, upTrianglePoints[2].x, upTrianglePoints[2].y);
  if (mouseOnDownTriangle) {
    if (mousePressed) fill(colors[9], 200);
    else fill(colors[9], 120);
  } else fill(colors[9], 200);
  triangle(downTrianglePoints[0].x, downTrianglePoints[0].y, downTrianglePoints[1].x, downTrianglePoints[1].y, downTrianglePoints[2].x, downTrianglePoints[2].y);



  // -------------------------------------------------------------- //
  // The three item types
  // 1. judgement
  //
  mouseOnBook = false;
  mouseOnAudio = false;
  mouseOnVideo = false;
  if (between(mouseX, horizonalLocation, (horizonalLocation+textWidth("Video"))) && between(mouseY, (verticalLocation + 50), (verticalLocation + dist*3 + 50))) {
    if (between (mouseY, (verticalLocation + 50), (verticalLocation + 50+dist)))              mouseOnBook = true;
    if (between (mouseY, (verticalLocation + dist + 50), (verticalLocation + dist*2 + 50)))   mouseOnVideo = true;
    if (between (mouseY, (verticalLocation + dist*2 + 50), (verticalLocation + dist*3 + 50))) mouseOnAudio = true;
  }

  // 2. draw text
  //
  textFont(fonts[0], 24);
  if (mouseOnBook) {
    if (mousePressed) fill(colors[9], 200);
    else fill(colors[9], 120);
  } else {
    if (showBook) fill(colors[9], 200);
    else fill(colors[9], 40);
  }
  text("Book", horizonalLocation, verticalLocation + 50);
  if (mouseOnVideo) {
    if (mousePressed) fill(colors[9], 200);
    else fill(colors[9], 120);
  } else {
    if (showVideo) fill(colors[9], 200);
    else fill(colors[9], 40);
  }
  text("Video", horizonalLocation, verticalLocation + dist + 50);
  if (mouseOnAudio) {
    if (mousePressed) fill(colors[9], 200);
    else fill(colors[9], 120);
  } else {
    if (showAudio) fill(colors[9], 200);
    else fill(colors[9], 40);
  }
  text("Audio", horizonalLocation, verticalLocation + dist*2 + 50);


  // -------------------------------------------------------------- //
  // Sevent lines representing seven deadly sins
  // (Mouse location judgement is moved into Interaction.pde)
  // (1). seven lines
  //
  pushMatrix();
  translate(width*7/8, height*13/16);
  beginShape(LINES);
  for (int i = 0; i< 7; i++) {
    PVector p1 = PVector.lerp(Points[i], Points[(i+1)%7], 0.1);
    PVector p2 = PVector.lerp(Points[i], Points[(i+1)%7], 0.9);
    //println(p1);
    strokeWeight(3);
    if (mouseOnSins[i]) {
      if (mousePressed) stroke(colors[i], 255);
      else stroke(colors[i], 100);
    } else {
      if (showTheSin[i]) stroke(colors[i], 255);
      else stroke(colors[i], 20);
    }
    vertex(p1.x/5, p1.y/5, 0);
    vertex(p2.x/5, p2.y/5, 0);
  }
  endShape();

  // (2). seven text labels
  //
  for (int i = 0; i< 7; i++) {
    PVector p3 = PVector.lerp(Points[i], Points[(i+1)%7], 0.5);
    pushMatrix();
    translate(p3.x/5*1.1, p3.y/5*1.1);
    rotate((i+0.5)*2*PI/7+PI/2);
    fill(colors[9], 200);
    textAlign(CENTER, BOTTOM);
    textFont(fonts[0], 12);
    text(sevenDeadlySins[i], 0, 0);
    popMatrix();
  }
  popMatrix();
}


void drawButtons() {
  rectButtons[1].setStatus(autoRotate);
  rectButtons[2].setStatus(blackOrWhite);
  rectButtons[3].setStatus(showGUI);

  rectButtons[0].draw();
  rectButtons[1].draw();
  rectButtons[2].draw();
  rectButtons[3].draw();

  textAlign(CENTER, BOTTOM);
  textFont(fonts[1], 12);
  fill(rectButtons[0].hoverColor);
  text("viewmode", rectButtons[0].x, rectButtons[0].y-10);
  text("auto rotate", rectButtons[1].x, rectButtons[1].y-10);
  text("black/white", rectButtons[2].x, rectButtons[2].y-10);
  text("interface", rectButtons[3].x, rectButtons[3].y-10);
}
Zip:
DataVis_3dVisualization_version2.zip
New source file
(1.94 MiB) Downloaded 241 times
----------- EDITED ------------

I was thinking that the modern culture get teenagers exposed too much unhealthy stuff, such as violence and pornography. It reminded me of the seven deadly sins. I was worried that getting those children exposed to the words of seven deadly sins may have a negative effects. So I tried to find out answers to these questions.

1. Which word of sin appears in most items?
2. Which item is checked out for most times among all the items related to one sin?
3. What is the relationship between the publish year and the publications' checkout counts?

Code: Select all

select distinct
title.title,
(CASE 
WHEN substring(itemType.itemType,3,3) = "bk" THEN "Book"
WHEN substring(itemType.itemType,3,3) = "cas" THEN "Audio"
WHEN substring(itemType.itemType,3,3) = "cd" THEN "Audio"
WHEN substring(itemType.itemType,3,3) = "vhs" THEN "Video"
WHEN substring(itemType.itemType,3,3) = "dvd" THEN "Video"
ELSE "OTHERS"
END) as MyType,
(CASE 
WHEN keyword.keyword ='Lust' THEN "Lust"
WHEN keyword.keyword ='Gluttony' THEN "Gluttony"
WHEN keyword.keyword ='Greed' THEN "Greed"
WHEN keyword.keyword ='Sloth' THEN "Sloth"
WHEN keyword.keyword ='Wrath' THEN "Wrath"
WHEN keyword.keyword ='Envy' THEN "Envy"
WHEN keyword.keyword ='Pride' THEN "Pride"
ELSE "OTHERS"
END) as MykeyWord,
substring(callNumber,-4) as PubYear,
COUNT(_transactionsExploded.bibNumber) as Counts
from
itemToBib, itemType, keyword, callNumber, title, _transactionsExploded
where
itemToBib.itemNumber = itemType.itemNumber
AND itemToBib.itemNumber = callNumber.itemNumber
AND itemToBib.bibNumber = keyword.bibNumber
AND itemToBib.bibNumber = title.bibNumber
AND itemToBib.bibNumber = _transactionsExploded.bibNumber
AND itemType.itemNumber = itemToBib.itemNumber
AND (keyword.keyword = "Lust" 
or keyword.keyword = "Gluttony"
or keyword.keyword = "Greed"
or keyword.keyword = "Sloth"
or keyword.keyword = "Wrath"
or keyword.keyword = "Envy"
or keyword.keyword = "Pride")
AND Cast(substring(callNumber,-4) as UNSIGNED) >  1900
AND Cast(substring(callNumber,-4) as UNSIGNED) <  2015 
Group by itemToBib.bibNumber
Through he query code above, I got the query result as below:
1.png
The query result
This table includes each item's publish year, type, the keyword of deadly sin it contains and the total checkout counts. This is a 480+ rows table, which means we have 480+ items to present.

To present it clearly, I adapted my model from a 2D model named "Time Wheel" (described as below and here: http://survey.timeviz.net).
timewheel.png
time wheel
time wheel 2.png
time wheel details
Each arrow in this image represents a value of each category. The lowest value is at the end of the arrow, and the highest value is at the head of the arrow. The horizontal arrow in the center represent the axis of time, which grows from the left to the right. By connecting the time and the values with lines, the visualization was made.

I adapted it to a 3-dimentional one. I transformed the time axis from left-to-right to inside-to-outside.
2.pic_hd.jpg
Sketches
Similarly, I use lines to represent items. So the value in each arrow is representing the total checkout times of the item, the time axis representing each item's publish year.

Therefore, the main frame of my visualization consists of 2 parts, the time axis and the 7 lines of the sins.
The time axis represents the publish years, ranging from 1990 to 2015.
Each line of a sin ranges from the maximum and minimum of the cumulative checkout counts of all items related to this sin. That why you can see the two number labels on the two sides of each line.
001085.jpg
Still Frame
When putting all the data into this frame, it looks like this:
001555.jpg
Overview
001835.jpg
Overview 2
Let me explain it step by step:

1. A single item can be represent by a line, which connected the time axis and one specific point on a sin's line.
The position of connecting point on the sin's line is determined by how big the checkout count of this item is, relative to the maximum checkout count of this sin.
Additionally, the lines for representing items differs from each other by their stroke weight, color transparency and saturation, which are also determined by how big the checkout count of this item is relative to the maximum checkout count of this sin.
004699.jpg
When single item is chosen
005043.jpg
When single item is chosen 2
2.When put all items published at a selected year into this frame. It looks like this.
This actually shows the distribution of items published at a specific year, which can be set by the user. The title and checkout counts of those items can be known from this perspective.
006618.jpg
All items published at selected year
007159.jpg
All items published at selected year 2
This is actually one of my display mode, in which data of years other than selected year are nearly invisible, in order to emphasize the selected year's data. Using +/- can change the year you want to look into.

3.When put all items that are related to a specific sin into this frame. It looks like this.
This shows the distribution of items related to a specific sin, which can be set by the user, too. We can know how popular each year's publications related to this sin are.
009073.jpg
All items related to the selected sin
010962.jpg
All items related to the selected sin
This is actually the other one display mode, in which data of sins other than the selected sin are nearly invisible, in order to emphasize the selected sin's data. Using 4 or 5 can change the sin you want to look into.

4.When put all together, the complete project is displayed as below.
011396.jpg
Put all together
004154.jpg
Put all together 2
Main interactions:
1. "+" and "-" to change the selected year to be displayed.
2. "4" and "5" to change the sin to be displayed.

Other interactions:
1. "B","A" and "V" are used to switch on and off the display of book items, audio items and video items separately.
2. "1","2" and "3" are three viewing perspectives.
3. "F" is to switch on and off the freedom of rotation. (After changing the viewing perspective, the freedom of rotation is automatically switched off)
4. "T" is to switch on and off the slowly self-rotation.
5. "H" is to hide or unhide the interface.
6. "C" is to clear the selected title.
7. "S" is to save screen shot.
8. "P" is to hide or unhide the data, which lets you see the still frame.

Future work:

1. I need to find a way eliminate the ambiguous items. Currently, the judgement of whether a item is related to a sin is merely based on keyword. It's ambiguous sometime. For example, sloth is a sin, but a kind of animal at the same time. Thus, the book like "Upside Down Sloth" that is about the animal should be eliminated, which is still in my data.
2. Some enhancements about interaction. The "4" or "5" to change the selected sin is not straightforward. I think clicking on the edges of the left-below 7-edge pentagon is better.


The processing code:

1.DataVis_3dVisualization.pde

Code: Select all

import controlP5.*;
import peasy.*;
import processing.opengl.*;

PeasyCam cam;
ControlP5 cp5;
ListBox l;

// Data parameters
Table dataTable;
int rowNums, colNums;
int[] MaxCheckoutCount, MinCheckoutCount;
String[] sevenDeadlySins; 

// Drawing setting
float overallRadius, panelDistance;
PVector[] Points; 
int presentYear;
float interpolatorYear;
Integrator[] interpolator;
float rotateX, rotateY, rotateZ;

// Color & fonts
color[] colors;
PFont[] fonts;

// Control parameters
int viewMode, whichSinToSee;
boolean showOtherYear, showBook, showVideo, showAudio, rotateFree, autoRotate, showGUI, onlyStillFrame;
boolean[] titleSelected;




void setup() {
  fullScreen(P3D);
  //size(800, 800, P3D);
  cam = new PeasyCam(this, 250);
  cam.setWheelScale(0.1);
  cam.setDistance(1600);


  //Initialization for data
  //
  dataTable = loadTable("query_result.csv", "header");  
  rowNums = dataTable.getRowCount();
  colNums = dataTable.getColumnCount();

  MaxCheckoutCount = new int[7];
  MinCheckoutCount = new int[7];
  for (int i = 0; i< 7; i++) {
    MaxCheckoutCount[i] = 0;
    MinCheckoutCount[i] = 100000;
  }
  for (int i = 0; i<rowNums; i++) {
    TableRow row = dataTable.getRow(i);
    int index = whichDeadlySin(row.getString(2)); 
    int checkoutCount = row.getInt(4);
    if (checkoutCount > MaxCheckoutCount[index]) MaxCheckoutCount[index] = checkoutCount;
    if (checkoutCount < MinCheckoutCount[index]) MinCheckoutCount[index] = checkoutCount;
  }

  sevenDeadlySins = new String[7];
  sevenDeadlySins[0] = "Lust";
  sevenDeadlySins[1] = "Gluttony";
  sevenDeadlySins[2] = "Greed";
  sevenDeadlySins[3] = "Wrath";
  sevenDeadlySins[4] = "Sloth";
  sevenDeadlySins[5] = "Envy";
  sevenDeadlySins[6] = "Pride";


  // Initializaiton for drawing 
  //
  rotateX = 0;
  rotateY = 0;
  rotateZ = 0;

  viewMode = 0;
  showOtherYear = true;
  showBook = true;
  showVideo = true;
  showAudio = true;
  rotateFree = true;
  showGUI = true;
  autoRotate = false;
  onlyStillFrame = false;

  titleSelected = new boolean[rowNums];
  for (int i = 0; i<rowNums; i++) {
    titleSelected[i] = false;
  }

  overallRadius = 400;
  panelDistance = 60;
  presentYear = 1990;
  interpolator = new Integrator[4];
  interpolator[0] = new Integrator(presentYear, 0.4, 0.08);
  interpolator[1] = new Integrator(rotateX, 0.4, 0.16);
  interpolator[2] = new Integrator(rotateY, 0.4, 0.16);
  interpolator[3] = new Integrator(rotateZ, 0.4, 0.16);

  Points = new PVector[7];
  for (int i = 0; i<7; i++) {
    float x, y;
    x = overallRadius*cos(i*2*PI/7);
    y = overallRadius*sin(i*2*PI/7);
    Points[i] = new PVector(x, y, 0);
  }

  whichSinToSee = 0;

  // Initialize colors & fonts
  //
  colors = new color[10];
  colors[0] = #0A86D0;
  colors[1] = #134ED5;
  colors[2] = #6D5CAF;
  colors[3] = #F2000D;
  colors[4] = #EB6002;
  colors[5] = #FFBC00;
  colors[6] = #019C69;
  colors[7] = #D42020;
  colors[8] = #FFFFFF;
  colors[9] = #000000;

  fonts = new PFont[3];
  fonts[0] = loadFont("OratorStd-48.vlw");
  fonts[1] = loadFont("OratorStd-12.vlw");

  controllerSetup();

  noLights();
  smooth();
}

void draw() {

  background(255);

  for (int i = 0; i < interpolator.length; i++) {
    interpolator[i].update();
  }
  interpolatorYear = interpolator[0].value;

  if (!rotateFree)
    cam.setRotations(interpolator[1].value, interpolator[2].value, interpolator[3].value);
  else
    setRotationInterpolator(cam.getRotations()[0], cam.getRotations()[1], cam.getRotations()[2]);

  for (int i = 0; i<rowNums; i++) {
    if ((l.getItem(i).get("state").toString().equals("true"))) {  
      titleSelected[i] = true;
    } else
      titleSelected[i] = false;
  }

  drawStillFrame();
  if (!onlyStillFrame) {
    for (int i= 0; i<rowNums; i++) {    
      drawTableRow(i);
    }
  }

  if (autoRotate) {
    if (viewMode == 2)cam.rotateX(0.002);
    if (viewMode == 3)cam.rotateY(0.002);
  }
  if (showGUI) gui();
}


void drawTableRow(int i) {
  TableRow row = dataTable.getRow(i);
  String type = row.getString(1);
  String theSin = row.getString(2);
  int year = row.getInt(3);
  if (year<1990) year = 1990;
  int index = whichDeadlySin(theSin);

  // Judgement about itemType
  // If selected, then show.
  //
  boolean shouldShow = false;
  if (type.equals("Book") && showBook) shouldShow = true;
  if (type.equals("Video") && showVideo) shouldShow = true;
  if (type.equals("Audio") && showAudio) shouldShow = true;

  if (shouldShow) {
    float percent = sqrt(sqrt(map(row.getFloat(4), MinCheckoutCount[index], MaxCheckoutCount[index], 0, 1)));
    float percent1 = map(percent, 0, 1, 0.1, 0.9);
    PVector p = PVector.lerp(Points[index], Points[(index+1)%7], percent1);
    float z = (year - interpolatorYear) * panelDistance;

    beginShape(LINES);
    colorMode(HSB, 255);
    color theColor = color(hue(colors[index]), saturation(colors[index])*(percent*0.3+0.7), brightness(colors[index]));

    // Judgement for each row's diplay mode
    //
    int mode = 0;
    if (whichSinToSee == (index+1) || whichSinToSee == 0) 
      mode = 2;
    else 
    mode = 4;
    if (titleSelected[i]==true) mode = 3;
    else {
      if ( mode != 4) {
        if (presentYear == year) mode = 1;
        else {
          if (showOtherYear ) mode = 2;
          else mode =4;
        }
      }
    }

    // Display according to its diplay mode
    //
    switch (mode) {

    case 1:
      // #1 YearSelected
      stroke(theColor, 100);
      strokeWeight(1);
      vertex(p.x, p.y, p.z);
      stroke(theColor, 250);
      strokeWeight(max(10*percent, 1));
      vertex(0, 0, z);
      break;

    case 2:
      // #2 Visible
      stroke(theColor, 100*(percent*0.7+0.3));
      strokeWeight(1);
      vertex(p.x, p.y, p.z);
      stroke(theColor, 250*(percent*0.7+0.3));
      strokeWeight(max(10*percent, 1));
      vertex(0, 0, z);
      break;

    case 3:
      // #3 TitleSelected
      stroke(colors[9], 100);
      strokeWeight(3);
      vertex(p.x, p.y, p.z);
      stroke(colors[9], 250);
      strokeWeight(max(10*percent, 3));
      vertex(0, 0, z);
      break;

    case 4 :
      // #4 Invisible
      stroke(hue(colors[index]), saturation(colors[index])*0.1, brightness(colors[index])*0.1, 15);
      strokeWeight(0.5);
      vertex(p.x, p.y, p.z);
      strokeWeight(0.5);
      vertex(0, 0, z);
    }
    endShape();


    // Show titles of items published at selected year
    //
    if ((year == presentYear && mode != 4 )|| titleSelected[i]) { 
      pushMatrix();
      translate(p.x, p.y, p.z);
      rotateY(PI/2);
      rotateX(((7-index)+0.5)*2*PI/7 - PI/4);
      rotateZ(PI);
      fill(colors[9], 200);
      textFont(fonts[0], 8);
      textAlign(LEFT);
      String title = row.getString(0);
      text(str(row.getInt(4))+"  "+title, 0, 0, 0);
      popMatrix();
    }
  }
}

// A mapping between index and sins
//
int whichDeadlySin(String theSin) {
  int index=0;
  if (theSin.equals("Lust"))     index = 0;
  if (theSin.equals("Gluttony")) index = 1;
  if (theSin.equals("Greed"))    index = 2;
  if (theSin.equals("Wrath"))    index = 3; 
  if (theSin.equals("Sloth"))    index = 4;
  if (theSin.equals("Envy"))     index = 5;
  if (theSin.equals("Pride"))    index = 6;
  return index;
}
2.Integrator.pde

Code: Select all

/*

Original Author: Ben Fry
From book Visualizing Data

*/
class Integrator {

  final float DAMPING = 0.5f;
  final float ATTRACTION = 0.2f;

  float value;
  float vel;
  float accel;
  float force;
  float mass = 1;

  float damping = DAMPING;
  float attraction = ATTRACTION;
  boolean targeting;
  float target;


  Integrator() { }


  Integrator(float value) {
    this.value = value;
  }


  Integrator(float value, float damping, float attraction) {
    this.value = value;
    this.damping = damping;
    this.attraction = attraction;
  }


  void set(float v) {
    value = v;
  }


  void update() {
    if (targeting) {
      force += attraction * (target - value);      
    }

    accel = force / mass;
    vel = (vel + accel) * damping;
    value += vel;

    force = 0;
  }


  void target(float t) {
    targeting = true;
    target = t;
  }


  void noTarget() {
    targeting = false;
  }
}
3.controller.pde

Code: Select all

void controllerSetup() {
  cp5 = new ControlP5(this);

  ControlFont labelFont = new ControlFont(fonts[0], 16);
  ControlFont valueFont = new ControlFont(fonts[1], 12);

  l = cp5.addListBox("myList")
    .setPosition(width/16, height/2 + 150)
    .setSize(width/4-width/16, 3*height/8 - 150)
    .setItemHeight(15)
    .setBarHeight(15)
    .setColorBackground(0xFFFFFFFF)
    .setColorActive(color(0))
    .setColorForeground(0xFFEB6002)
    ;
  l.getCaptionLabel().toUpperCase(true);
  l.getCaptionLabel().set("Item Title");
  l.getCaptionLabel().setColor(colors[9]);
  l.getCaptionLabel().setFont(labelFont);
  l.getCaptionLabel().getStyle().marginTop= 5;
  l.getCaptionLabel().getStyle().marginLeft= -5;
  l.getValueLabel().setColor(colors[9]);
  l.getValueLabel().setFont(valueFont);
  l.getValueLabel().getStyle().marginTop= 5;
  l.getValueLabel().getStyle().marginLeft= -5;
  for (int i=0; i<rowNums; i++) {
    String title = nf(i, 3)+" "+ dataTable.getRow(i).getString(0);
    int maxLength = int((width/4-width/16)/7);
    if (title.length()>maxLength) title= title.substring(0, maxLength);
    l.addItem(title, i);
    CColor c = new CColor();
    //c.setBackground(0x14141400);
    c.setBackground(0xFFFFFFFF);
    //println(c);
    l.getItem(title).put("color", c);
    println(l.getItem(title));
  }
  cp5.setAutoDraw(false);
}

void controlEvent(ControlEvent theEvent) {

  //println(theEvent.getController().getId());
}




void gui() {
  hint(DISABLE_DEPTH_TEST);
  cam.beginHUD();
  cp5.draw();

  float horizonalLocation = width/16;
  float verticalLocation = height/2;
  float dist = 25;

  fill(0, 15);
  noStroke();
  //rect(width/32, height/16, width/4, height/8);
  rect(width/32, height/2-height/16, width/4, height/2);

  boolean isMouseInX = (mouseX > width/32) && (mouseX<(width/4+width/32));
  boolean isMouseInY = (mouseY > (height/2-height/16)) && (mouseY <(height-height/16));
  boolean isMouseIn = isMouseInX && isMouseInY;

  if (isMouseIn)cam.setActive(false);
  else cam.setActive(true);

  fill(colors[9], 200);
  textFont(fonts[1], 16);
  textAlign(LEFT, BOTTOM);
  text("The 7 prevalently checked out items of", horizonalLocation, height/8-20);
  textFont(fonts[0], 48);
  textAlign(LEFT, TOP);
  text("7 DEADLY SINS", horizonalLocation, height/8);

  textAlign(LEFT, TOP);
  if (presentYear == 1990) {
    fill(colors[9], 200);
    textFont(fonts[0], 24);
    text("BEFORE ", horizonalLocation, verticalLocation-40);
    textFont(fonts[0], 48);
    text(str(presentYear+1), horizonalLocation, verticalLocation);
  } else if (presentYear > 1990 && presentYear < 2015) {
    fill(colors[9], 200);
    textFont(fonts[0], 48);
    text(str(presentYear), horizonalLocation, verticalLocation);
  } else {
    fill(50, 200);
    textFont(fonts[0], 48);
    text(str(presentYear), horizonalLocation, verticalLocation);
  }


  textFont(fonts[0], 24);
  if (showBook) fill(colors[9], 200);
  else fill(100, 200);
  text("Book", horizonalLocation, verticalLocation + 50);
  if (showVideo) fill(colors[9], 200);
  else fill(100, 200);
  text("Video", horizonalLocation, verticalLocation + dist + 50);
  if (showAudio) fill(colors[9], 200);
  else fill(100, 200);
  text("Audio", horizonalLocation, verticalLocation + dist*2 + 50);

  pushMatrix();
  translate(width*7/8,height*13/16);
  beginShape(LINES);
  for (int i = 0; i< 7; i++) {
    PVector p1 = PVector.lerp(Points[i], Points[(i+1)%7], 0.1);
    PVector p2 = PVector.lerp(Points[i], Points[(i+1)%7], 0.9);
    //println(p1);
    strokeWeight(3);
    if (i==whichSinToSee-1 || whichSinToSee ==0) {
      stroke(colors[i], 255);
    } else {
      stroke(colors[i], 20);
    }
    vertex(p1.x/5, p1.y/5, 0);
    vertex(p2.x/5, p2.y/5, 0);
  }
  endShape();
  
  for (int i = 0; i< 7; i++) {
   PVector p3 = PVector.lerp(Points[i], Points[(i+1)%7], 0.5);
   pushMatrix();
   translate(p3.x/5*1.1, p3.y/5*1.1);
   rotate((i+0.5)*2*PI/7+PI/2);
   fill(colors[9], 200);
   textAlign(CENTER, BOTTOM);
   textFont(fonts[0], 12);
   text(sevenDeadlySins[i], 0, 0);
   popMatrix();
  }
  popMatrix();

  cam.endHUD();
  hint(ENABLE_DEPTH_TEST);
}
4.Interaction.pde

Code: Select all

void keyPressed() {
  if (key == 'S' || key == 's') {
    saveFrame("######.jpg");
  }
  if (key == '=' || key =='+') {
    presentYear++;
    interpolator[0].target(presentYear);
  }
  if (key == '-' || key =='_') {
    presentYear--;
    interpolator[0].target(presentYear);
  }
  if (key == 'F' || key =='f') {
    rotateFree = !rotateFree;
  }
  if (key == 'T' || key == 't') {
    autoRotate = !autoRotate;
  }

  if (key == '1') {
    viewMode = 1;
    cam.setDistance(1600);
    setRotationInterpolator(0, 0, 0);
  }
  if (key == '2') {
    viewMode = 2;
    setRotationInterpolator(0, -PI/2, 0);
    rotateFree = false;
  }
  if (key == '3') {
    viewMode = 3;
    setRotationInterpolator(-PI/2, -PI/2, 0);
    rotateFree = false;
  }
  if (key == '4') {
    whichSinToSee++;
    whichSinToSee = whichSinToSee % 8;
  }
  if (key == '5') {
    if (whichSinToSee == 0) whichSinToSee+=7;
    whichSinToSee--;
  }

  if (key == 'B' || key =='b') {
    showBook = !showBook;
  }
  if (key == 'V' || key =='v') {
    showVideo = !showVideo;
  }
  if (key == 'A' || key =='a') {
    showAudio = !showAudio;
  }
  if (key == 'Y' || key =='y') {
    showOtherYear = !showOtherYear;
  }
  if (key == 'H' || key == 'h') {
    showGUI = !showGUI;
  }
  if (key == 'C' || key == 'c') {
    for (int i =0; i<rowNums; i++) {
      l.getItem(i).put("state", false);
    }
  }
  if (key == 'P' || key == 'p') {
    onlyStillFrame = !onlyStillFrame;
  }
}

void setRotationInterpolator(float rx, float ry, float rz) {
  interpolator[1].set(cam.getRotations()[0]);
  interpolator[2].set(cam.getRotations()[1]);
  interpolator[3].set(cam.getRotations()[2]);
  interpolator[1].target(rx);
  interpolator[2].target(ry);
  interpolator[3].target(rz);
}
5.StillFrame.pde

Code: Select all

void drawStillFrame() {
  for (int i = 0; i< 7; i++) {
    // bar
    PVector p1 = PVector.lerp(Points[i], Points[(i+1)%7], 0.1);
    PVector p2 = PVector.lerp(Points[i], Points[(i+1)%7], 0.9);
    //println(p1);
    beginShape(LINES);
    strokeWeight(3);
    stroke(colors[i], 20);
    vertex(p1.x, p1.y, p1.z);
    strokeWeight(3);
    if (i==whichSinToSee-1 || whichSinToSee ==0) {
      stroke(colors[i], 200);
    } else {
      stroke(colors[i], 20);
    }
    vertex(p2.x, p2.y, p2.z);
    endShape();

    // count label
    pushMatrix();
    translate(p2.x, p2.y, p2.z);
    rotateZ((2*i+1)*PI/7+PI);
    textAlign(RIGHT, TOP);
    textFont(fonts[0], 20);
    text(str(MaxCheckoutCount[i]), -10, 0, 0);
    popMatrix();

    pushMatrix();
    translate(p1.x, p1.y, p1.z);
    rotateZ((2*i+1)*PI/7+PI);
    textAlign(RIGHT, BOTTOM);
    text(str(MinCheckoutCount[i]), -5, 0, 0);
    popMatrix();
  }

  beginShape(LINES);
  for (int i = 0; i< 7; i++) {
   PVector p1 = PVector.lerp(Points[i], Points[(i+1)%7], 0.1);
   PVector p2 = PVector.lerp(Points[i], Points[(i+1)%7], 0.9);
   //println(p1);
   strokeWeight(3);
   if (i==whichSinToSee-1 || whichSinToSee ==0) {
     stroke(colors[i], 255);
   } else {
     stroke(colors[i], 20);
   }
   vertex(p1.x*2, p1.y*2, p1.z);
   vertex(p2.x*2, p2.y*2, p2.z);
  }
  endShape();

  for (int i = 0; i< 7; i++) {
    PVector p3 = PVector.lerp(Points[i], Points[(i+1)%7], 0.5);
    pushMatrix();
    translate(p3.x*1.5, p3.y*1.5, p3.z);
    rotate((i+0.5)*2*PI/7+PI/2);
    fill(colors[9], 200);
    textAlign(CENTER, BOTTOM);
    textFont(fonts[0], 48);
    text(sevenDeadlySins[i], 0, 0, 0);
    popMatrix();
  }

  drawYearLabel();
}


void drawYearLabel() {
  for (int year = 1989; year<2015; year++) {
    float z = (year - interpolatorYear) * panelDistance;
    pushMatrix();
    translate(0, 0, z+2);
    rotateY(-PI/2);
    fill(colors[9], 200);
    textFont(fonts[0], 10);
    textAlign(LEFT);
    if (year== 1990)
      text("<"+str(year+1), 0, 0, 0);
    else if (year == 1989) {
      textFont(fonts[0], 20);
      //textWidth("Publish Year");
      text("Publish Year", -textWidth("Publish Year"), 0, 0);
      textFont(fonts[0], 10);
    } else
      text(str(year), 0, 0, 0);
    popMatrix();
  }
}
The old source code: (Please download the new one)
DataVis_3dVisualization.zip
Source code
(1.56 MiB) Downloaded 238 times
The new source code:
DataVis_3dVisualization_version2.zip
New source file
(1.94 MiB) Downloaded 241 times
Last edited by qiu0717 on Wed Mar 02, 2016 4:12 pm, edited 13 times in total.

theuniqueeye
Posts: 4
Joined: Wed Jan 06, 2016 12:51 pm

Re: PROJ 2: 3D INTERACTION & CHANGE OVER TIME

Post by theuniqueeye » Thu Feb 11, 2016 3:06 am

# update # 2016-2-22
Add a presentation mode,which plays the program automatically through a designed narrative.
[ start over - title view - general view - label view - event view - specific angle view ]
specificAngle.png
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

/*
When rock stars are dead, they are never gone. They keep being memorized by millions of their fans, music lovers, and the public. Their songs went on again and again. And as culture icons, their life stories are discovered, passed on, and exaggerated year by year.
*/

How does the dead rock star stay alive?
:: Jing Yan

Concept

In project 3, I completely explore the aliveness of David Bowie in Seattle Public Library, both in quantity dimension and quality dimension, by examining the checkout times and durations of David Bowie’s CDs and related books.

Data updated
Using the new tango 2, I rearranged MySQL to get more detailed data. The date becomes more specific: every day from 2005-08-01 to 2016-1-31. The titles are rearranged by the published date which is showed on the SPL’s website. This arrangement gathers more meaning than simply arrange titles by the alphabet order.

Code: Select all

 // &&&&&&&&&&&&&&&&&&   query: title type for CD and book &&&&&&&&&&&&&&&&&&&&

SELECT distinct
    itemType, title
FROM
    spl.title,
    spl.itemType,
    spl.itemToBib
WHERE
    spl.itemType.itemNumber = spl.itemToBib.itemNumber
        AND spl.itemToBib.bibNumber = spl.title.bibNumber
        AND (spl.title.bibNumber = '1836438'
        OR spl.title.bibNumber = '1965047'
        OR spl.title.bibNumber = '2277690'
        OR spl.title.bibNumber = '1823619'
        OR spl.title.bibNumber = '2613601'
        OR spl.title.bibNumber = '2707908'
        OR spl.title.bibNumber = '2723037'
        OR spl.title.bibNumber = '2815071'
        OR spl.title.bibNumber = '2917442'
        OR spl.title.bibNumber = '2941304'
        OR spl.title.bibNumber = '3029321'
        OR spl.title.bibNumber = '1952906'
        OR spl.title.bibNumber = '2148651'
        OR spl.title.bibNumber = '2023159'
        OR spl.title.bibNumber = '2362135'
        OR spl.title.bibNumber = '3029080'
        OR spl.title.bibNumber = '2023157'
        OR spl.title.bibNumber = '2299335'
        OR spl.title.bibNumber = '1954184'
        OR spl.title.bibNumber = '1736211'
        OR spl.title.bibNumber = '2627462'
        OR spl.title.bibNumber = '2128387'
        OR spl.title.bibNumber = '3061214'
        OR spl.title.bibNumber = '1959048'
        OR spl.title.bibNumber = '1950899'
        OR spl.title.bibNumber = '2444123'
        OR spl.title.bibNumber = '2515298'
        OR spl.title.bibNumber = '1976192'
        OR spl.title.bibNumber = '2086964'
        OR spl.title.bibNumber = '1953017'
        OR spl.title.bibNumber = '2867039'
        OR spl.title.bibNumber = '3057303'
        OR spl.title.bibNumber = '1639110'
        OR spl.title.bibNumber = '2363644'
        OR spl.title.bibNumber = '2567243'
        OR spl.title.bibNumber = '2211550'
        OR spl.title.bibNumber = '3067034'
        OR spl.title.bibNumber = '2631168'
        OR spl.title.bibNumber = '1954182'
        OR spl.title.bibNumber = '1880152'
        OR spl.title.bibNumber = '2412531'
        OR spl.title.bibNumber = '1976321'
        OR spl.title.bibNumber = '2296937'
        OR spl.title.bibNumber = '1972971'
        OR spl.title.bibNumber = '2448150'
        OR spl.title.bibNumber = '2612658'
        OR spl.title.bibNumber = '1953009')
ORDER BY itemType , title

Code: Select all

// &&&&&&&&&&&&&&&&&&   query: checkout event per day per title for CD and book &&&&&&&&&&&&&&&&&&&&

SELECT 
    itemType,
    title,
    DATE_FORMAT(checkOut, '20%y-%m-%d') AS date,
    COUNT(checkOut) AS checkOutTimes,
    #DATE_FORMAT(checkOut, '20%y-%m-%d')  AS coutDate,
    #DATE_FORMAT(checkInFirst, '20%y-%m-%d') AS cinDate,
    AVG(TIMESTAMPDIFF(DAY,
        checkOut,
        checkIn)) AS checkOutDuration
FROM
    spl.itemType,
    spl.title,
    spl._transactionsExploded
WHERE
    spl.itemType.itemNumber = spl._transactionsExploded.itemNumber
        AND spl.title.bibNumber = spl._transactionsExploded.bibNumber
        AND (spl.title.bibNumber = '1836438'
        OR spl.title.bibNumber = '1965047'
        OR spl.title.bibNumber = '2277690'
        OR spl.title.bibNumber = '1823619'
        OR spl.title.bibNumber = '2613601'
        OR spl.title.bibNumber = '2707908'
        OR spl.title.bibNumber = '2723037'
        OR spl.title.bibNumber = '2815071'
        OR spl.title.bibNumber = '2917442'
        OR spl.title.bibNumber = '2941304'
        OR spl.title.bibNumber = '3029321'
        
        OR spl.title.bibNumber = '1952906'
        OR spl.title.bibNumber = '2148651'
        OR spl.title.bibNumber = '2023159'
        OR spl.title.bibNumber = '2362135'
        OR spl.title.bibNumber = '3029080'
        OR spl.title.bibNumber = '2023157'
        OR spl.title.bibNumber = '2299335'
        OR spl.title.bibNumber = '1954184'
        OR spl.title.bibNumber = '1736211'
        OR spl.title.bibNumber = '2627462'
        OR spl.title.bibNumber = '2128387'
        OR spl.title.bibNumber = '3061214'
        OR spl.title.bibNumber = '1959048'
        OR spl.title.bibNumber = '1950899'
        OR spl.title.bibNumber = '2444123'
        OR spl.title.bibNumber = '2515298'
        OR spl.title.bibNumber = '1976192'
        OR spl.title.bibNumber = '2086964'
        OR spl.title.bibNumber = '1953017'
        OR spl.title.bibNumber = '2867039'
        OR spl.title.bibNumber = '3057303'
        OR spl.title.bibNumber = '1639110'
        OR spl.title.bibNumber = '2363644'
        OR spl.title.bibNumber = '2567243'
        OR spl.title.bibNumber = '2211550'
        OR spl.title.bibNumber = '3067034'
        OR spl.title.bibNumber = '2631168'
        OR spl.title.bibNumber = '1954182'
        OR spl.title.bibNumber = '1880152'
        OR spl.title.bibNumber = '2412531'
        OR spl.title.bibNumber = '1976321'
        OR spl.title.bibNumber = '2296937'
        OR spl.title.bibNumber = '1972971'
        OR spl.title.bibNumber = '2448150'
        OR spl.title.bibNumber = '2612658'
        OR spl.title.bibNumber = '1953009')
GROUP BY title , date
ORDER BY itemType, date , title

 
Visualization

Model
eventriver.png
The visualization is based on the event-river model, which I find very suitable to my concept and data. What I like about this model is that it regards each event as a creature in the river. The event is separated from the context and gain its own feature. Furthermore, the metaphor of river and fish adds a lot of imagination and possibility. In my data visualization project, I further explore this model by changing the 2D static model into a 3D dynamic model with interaction.


some sketches
sketch.JPG
The data visualization is consisted of several parts: the title, the river, the creature, labels and data, and interaction buttons.
firstview.png
normalview.png
generalview.png
closeview.png
General layout

The river serves as the context and container of the events. Its x-axis is the timeline, and the y-axis shows each title. Each checkout event of the same day with the same title is displayed at the z-axis.

The creature represents each checkout event which has two main characters the checkout times and duration. They are mapped to the events through two different methods: by scale and by motion. In scale method, the checkout duration is mapped to tail length, and checkout times mapped to square size. In motion method, the checkout duration is mapped to the tail rotate, and checkout times mapped to the fluctuation. Thought it’s a little bit redundant to map the same information with two methods, I try to explore the dynamic of data visualization and provides audience with a livelier and more intuitive view of the data.
pickeddatashow.png
withlabel.png
oneeventpickout.png
rotate.png
closeviewwithoutreddot.png
Interaction
The labels and data display allows audience to play with the visualization, get a general feeling of the data, and examine the detail information contained inside. When the label is switched on, the user can pick one row of data by mouse and both the size and motion of that row will be exaggerated to provide a clearer view of comparison. The title will change its color according to the type of the item. Without the label, the user can pick out each single event using their mouse, and check the detailed information of title, date, checkout times and duration.
The interaction buttons are built through controlP5. There are two kinds of them: checkbox and button. The label, rotate, and motion function are controlled by checkbox, and different perspectives are controlled by button. By building the perspective mode, I would like to present a more complete version of the visualization. You can get a normal view, a closer view for detail information, a far away view for general pattern. And this general pattern could be explored better through rotate camera function. User can explore the density of checkout events through looking up side down to the river.
Moreover, though it’s not fully complete, an idea of auto music display is added. When the mouse is stayed at a certain row (represent title) for a certain amount of time, the related music from that album will play automatically.

Technical Difficulty
The problem is that due to the huge amount of data (about 50000) the processing speed is really slow. The display is terribly stuck. To deal with the problem, I made three solutions. 1st, I separate the creature model buildup process and the draw process. So I build up the model of creatures of each event only once and draw them every time. 2nd, the portion of data drawn are related to the camera distance. That means the closer the river, the more data are present which is pretty reasonable comparing to how we look at things. 3rd, when display the general view, I use points instead of the objects to make the scene smoother.

Style
I continue the broad, rational, calm down, “Ryoji Ikeda” style in this visualization design. The creatures and river are all abstract and conceptual. And as it is said in the project 2, I like the way data pattern speaks for themselves, thus I make them the most important and obvious thing on the interface. And I make the labels, notes, and interaction switches as simple as possible to eliminate the distraction.

processing code and music source for test
Bowie3D_JingYan.zip
(1.44 MiB) Downloaded 223 times
SpaceOddity.mp3.zip
(4.64 MiB) Downloaded 223 times
Last edited by theuniqueeye on Tue Feb 23, 2016 12:40 am, edited 4 times in total.

mayelsherif
Posts: 4
Joined: Wed Jan 06, 2016 1:42 pm

Re: PROJ 2: 3D INTERACTION & CHANGE OVER TIME

Post by mayelsherif » Thu Feb 11, 2016 11:07 pm

3D Project: Bigram analysis for different Dewey classes

Introduction and motivation:

In this project, I aim to conduct bigram analysis for different Dewey classes. In the fields of computational linguistics and probability, an n-gram is a contiguous sequence of n items from a given sequence of text or speech [1]. So, a bigram is a contiguous sequence of 2 items. In this project, an item is an English word in the labels and titles of items in the Seattle Public Library.

Why are bigrams important?
The analysis of bigrams provides a means to do two important tasks:
1- Autocompletion: when a user types in a word in a search box, bigram analysis can be used to provide suggestions to the next word a person is going to type.
2- Recommendation and suggestion: If a user, for instance, searches for a bigram (e.g. English books), a recommender system that uses bigram analysis would suggest also English language.

Query:
I started by running a query that for every item in the Seattle Public Library in a certain Dewey class, it gets the title and concatenates the labels using (GROUP_CONCAT(spl3.subject.subject SEPARATOR ', ') AS concatLabels) and separates the labels using a comma. In the example below, we are generating the previously mentioned attributes for deweyClass 900-999. I generated 10 csv files, each corresponding to a Dewey Class.

Code: Select all

SELECT 
    deweyClass AS Dewey,
    spl3.deweyClass.bibNumber,
    checkOutCount,
    COUNT(spl3.subject.bibNumber) AS SubjectEntriesCount,
    GROUP_CONCAT(spl3.subject.subject SEPARATOR ', ') AS concatLabels, 
    spl3.title.title
FROM
    spl3.x_checkOutCountBib,
    spl3.deweyClass,
    spl3.subject,
    spl3.title
WHERE
    deweyClass >= 900 AND deweyCLass <= 999
        AND spl3.x_checkOutCountBib.bibNumber = spl3.deweyClass.bibNumber
        AND spl3.x_checkOutCountBib.bibNumber = spl3.subject.bibNumber
        AND spl3.x_checkOutCountBib.bibNumber = spl3.title.bibNumber
        AND deweyCLass != ''
        AND (spl3.subject.subject != ''
        OR spl3.subject.subject IS NOT NULL)
GROUP BY bibNumber
ORDER BY deweyClass;
Text analysis:

The next step was doing the text processing analysis using the tm (text mining) package in R. Below is a sample of the code. We begin by forming a text corpus of all the titles and the concatenated labels. The next steps were removing repetitions in each string, transforming all the text to lower case characters and removing English stopwords.

Code: Select all

dew0Data = read.csv(paste("/Users/mayelsherif/Desktop/CSVFiles/dew", toString(deweyClass), ".csv", sep=''), header = TRUE)
# Remove the commas from the string
dew0Data$concatLabels = gsub(",", "", dew0Data$concatLabels)


BigramTokenizer =
  function(x)
    unlist(lapply(ngrams(words(x), 2), paste, collapse = " "), use.names = FALSE)
corpus = Corpus(VectorSource(dew0Data$concatLabels), VectorSource(dew0Data$title))
# Convert to lower case and remove stopwords
corpus = tm_map(corpus, content_transformer(tolower))
corpus = tm_map(corpus, removeWords, stopwords("english"))
inspect(corpus)  # same as print but provides more info 
tdmLabelsTitles <- TermDocumentMatrix(corpus, control = list(tokenize = BigramTokenizer))
bigrams0 = tdmLabelsTitles$dimnames$Terms
reps0 = formDeweyCSVFile(bigrams0, deweyClass)
After the pre-processing phase, I generated 10 csv files. Each file contains four entries ("Bigram1, Bigram2, Dewey, Popularity").
  • Bigram1 and Bigram 2 refer to the first and second word respectively in the bigram.
    Dewey represents the Dewey class from 0 to 9.
    Popularity refers to the number of bigrams that contains the first half of the bigram (pivots).
Since the data generated was huge, I decided to do some post-processing. I generated the top 25 first half of bigrams for each Dewey class.

Visulization and interaction:
To visualize the bigrams, I plotted each pivot on a vertex of a central polygon and the associated words with it filling the space around it in a star shape. I did that for 10 randomly picked first halves from the top 25. Every time you render a certain Dewey class, 10 elements are chosen randomly. The words rotate in a continuous manner around the pivots. Pressing numbers from 0-9 render Dewey classes from 0 to 9 respectively. Clicking on a certain pivot will show you the words associated with it in the Seattle Public Library in the text area on the left. Attached are some snapshots of the 3D visualization.
Screen Shot 2016-02-25 at 11.36.23 PM.png
Screen Shot 2016-02-25 at 11.35.57 PM.png
Screen Shot 2016-02-25 at 11.35.28 PM.png
[1]- https://en.wikipedia.org/wiki/N-gram
Attachments
MayElSherif_ImprovedProj3D.zip
(6.96 KiB) Downloaded 175 times
Last edited by mayelsherif on Thu Feb 25, 2016 11:55 pm, edited 3 times in total.

lliu
Posts: 9
Joined: Wed Jan 06, 2016 1:41 pm

Re: PROJ 2: 3D INTERACTION & CHANGE OVER TIME

Post by lliu » Tue Feb 16, 2016 12:13 am

FILM ADAPTATION INFLUENCE
The Trend of Checkout Numbers of Books During
Corresponding Adaptation Film Released Time

Books and movies remain the most popular cultural represent forms.
Will they have mutual impact on each other?
For example: When a film adapted from a book released,
will the checkout number of this book in library increase?
Screen Shot 2016-02-15 at 10.13.47 PM.png
I chose several adapted films respectively released on 2006, 2009, 2012 and 2014.
Compare the checkout number of specific book in the normal time and
the time after adaptation film released to find the trend over months and years.
Screen Shot 2016-02-15 at 10.16.19 PM.png
Description:
Press "a" OR "A" on keyboard to show all the information of database
Press "s" OR "S" on keyboard to show label.
Click the specific movie item on the label to see more details information about this adaptation movie and its correspond book.
press "p" OR ''P'': Display the record of every checkout by point.
press "b" OR "B": Display the record of every checkout by box.

The ellipses represent the years. (from 2006 to 2014).
The vertical axis represents the time of the day(from 12am to 12pm).
The lines above the ellipses represent the trend of checkout of every month.
The color represents the amount of specific month. The brighter the color is, the larger the checkout number is.
The size of box represents the checkout time of each record.
Screen Shot 2016-02-15 at 10.19.05 PM.png
Screen Shot 2016-02-15 at 10.18.20 PM.png
QQ20160223-2@2x.png
MySQL Example Code:

Code: Select all

SELECT 
    DATE(checkOut) AS Dates,
    TIME(checkOut) AS Times,
    
    -- COUNT(title) AS CheckoutCount,
    TIMESTAMPDIFF(DAY, checkOut, checkIn) AS CheckoutDur
FROM
    spl3._rawXmlDataCheckIns
WHERE
    title LIKE '% the da vinci code %'
  AND SUBSTRING(itemType, 3, 4) = 'bk'
    AND DATE(checkOut)>'20051231'
-- GROUP BY CheckoutYear , CheckoutMonth
Attachments
visualizationHW3.zip
(125.86 KiB) Downloaded 153 times
Last edited by lliu on Tue Feb 23, 2016 11:42 am, edited 2 times in total.

akibmayadav
Posts: 3
Joined: Tue Jan 12, 2016 11:57 am

Re: PROJ 2: 3D INTERACTION & CHANGE OVER TIME

Post by akibmayadav » Tue Feb 16, 2016 12:34 am

WHAT IS THE TIME ?
Ambika Yadav

An attempt to visualize the number of checkouts from Seattle Public library on an hourly basis over the past 10 years. I wanted to extend my last project where I looked into the number of checkouts on a daily basis to observe the number of checkouts on an hourly basis.
This visualization gives a better prediction of the trends which are formed over the years . The variation of the hours of max checkouts of various months depending on the weather is a clear trend visible in the visualizations.

CONCEPT :
To concept can be better explained using the sketch below. I have extruded the dates over the z axis . The concentric circles depict the time ,wherein the radius tells us what time are we talking about it. Also to make time, the most important parameter here more comprehensible, I have added a color code to them. The last parameter of the count is depicted using length of the arcs ,which means the longer the arc, more are the number of checkouts.
IMG_4370.jpg
Sketch
SQL QUERY :

Code: Select all

SELECT
 hour(Checkout) As Hour,
 date(CheckOut) AS Date, 
 COUNT(date(CheckOut)) AS TotalCheckouts
FROM
 spl3.x_transactionsExcludeNullCheckIns
GROUP BY date
ORDER BY date,hour
My SQL query was inspired by my last project , and was modified to accomodate the time analysis of the number of checkouts.

INTERACTIONS :
1. The user can go through the visualization over years by pressing keys 1-9 . The year being seen can be looked into is highlighted on the top right corner.
2. The user can also observe the trend of the over the years during a particular time. For example: how have the number of checkouts varied at 5 PM across the years. This an be done by just scrolling the mouse on the vertical color time index on the left side of the screen.

PROCESSING CODE :
Final_3D_Viz.zip
(233.08 KiB) Downloaded 161 times
FINAL OUTPUT :
Screen Shot 2016-02-25 at 7.55.33 PM.png
Snapshot 1
Screen Shot 2016-02-25 at 7.56.03 PM.png
Snapshot 2
Screen Shot 2016-02-25 at 7.56.32 PM.png
Snapshot 3
Screen Shot 2016-02-25 at 7.57.06 PM.png
Snapshot 4
Last edited by akibmayadav on Thu Feb 25, 2016 8:09 pm, edited 1 time in total.

changhe
Posts: 6
Joined: Wed Jan 06, 2016 1:39 pm

Re: PROJ 2: 3D INTERACTION & CHANGE OVER TIME

Post by changhe » Tue Feb 16, 2016 12:55 am

3D: When "New" Books Are No Longer New

Concept:

I continued my interests in new books and did my project by asking how are those new books' performances.

I was inspired by Karl's work and a concept in Business Intelligence, called OLAP Cube. (https://en.wikipedia.org/wiki/OLAP_cube)
In my previous design, 2D visualization, I used a lot of aggregation data in my project. So all the numbers are summed up by month or year. However, Karl did it in another way. He used every single data. I really like this perspective. So I chose to visualize my data in this way, show every single record that are related to my topic instead of using aggregation function and use summed up numbers.

Therefor this project enumerates every checkout records of new books based on its checkout time, checkout duration and publication year with book type.
sketch.JPG
sketch
Visualization Design:

Every records are presented by a white line with a color point at its end. It's length is determined by loan duration in days. Position is affected by its checkout time. X axis is based on time dimension. Y coordinate is defined by the book type. Fiction books are placed at top, non-fiction books are at bottom. Z axis is increment determined by checkout amount within a day.
v3_ice.png
screenshot2
Blue means the book is published in 2015. Yellow means 2014, and 2013 publications is made in red color.

In OLAP cube, user can switch to different dimensions to see data in different perspective without changing data set in order to discover more valuable information. I also want my visualzation be able to do this. So I added 3 standard views to look at my data shape. By taping 0, 1 and 2, user can see my project with 3 different focus: x-y, x-z and detailed 3-D. From x-y perspective, user can see new book's population pattern in time. X-z can show the general loan duration information. Normal 3-D allows user to zoom into the shape of single data.
v3_yellow+blue.png
screenshot3
About Data:

I did query based on my interest of data: fiction and non-fiction checkouts for 2015, 2014 and 2013. Because of the data size, I export them into 6 file: fiction for 2015, 2014, 2013 and non-fiction for 2015, 2014, 2013.
The total data size is about 56 Mb, which includes 663,778 records, which is a half million. And my project visualizes every single of them.

Here is one of my MySQL query:

Code: Select all

SELECT 
	spl.transactions.bibNumber,
	spl.transactions.itemNumber,
	spl.title.title,
	spl.transactions.checkOut,
    TIMESTAMPDIFF(DAY, checkOut, checkInFirst)  AS 'check Out Days'
    
FROM
    spl.transactions, spl.callNumber, spl.deweyClass, spl.collectionCode, spl.itemType, spl.title

WHERE
	spl.callNumber.itemNumber = spl.transactions.itemNumber
	AND	spl.deweyClass.bibNumber = spl.transactions.bibNumber
	AND spl.collectionCode.itemNumber = spl.transactions.itemNumber
	AND spl.itemType.itemNumber = spl.transactions.itemNumber
	And spl.title.bibNumber = spl.transactions.bibNumber
    AND substring(collectionCode from 3 for 3) = 'new'
	AND right(callNumber, 4) = 2015
	AND length(deweyClass) = 0  
	AND itemType = 'acbk'
	AND checkOut != "1970-01-01 00:00:00"
	AND TIMESTAMPDIFF(DAY, checkOut, checkInFirst) >= 0

ORDER BY checkOut,  bibNumber, itemNumber 
Interactions:

User can interact with my program by many ways:
1. You can use mouse and keyboard to change perspectives to see clearly at the shapes.
Available keys: 0, 1, 2, UP, DOWN, LEFT and RIGHT.
2. You can click on the button on the top left corner to show different books based on their publication year.
Available choice: 2013, 2014 and 2015. (You can turn them on or off)
3. The best, you can type in book name and search for individual performance about their checkouts. After hit ENTER key, you will see information about this books, such as how many copies, total checkouts it has.
v3_full+search.png
screenshot4
These user interaction is one of the major function provided in this project.
Because the data set used by my project is big, which include millions records. So the visualization tends to reveal general information. User can see clearly about patterns and trends. However, I want the program also be able to show detailed information about individual books, which means the visualization can zoom out from "overview" to zoom in at "insite". This is what a good data visualization should be to me.
So, I added a searching function in my project. User can type in the book title, and the system returns all the corresponding records. User can see how this book was loaned after publication based on the curves shown on the basic shape. Additionally, some other information about this book will also be shown at the top right corner under the searching text field.
v3_blue.png
screenshot1
Technic Problems:

Because of the data size, the program reaches the threshold of GPU with desired frame rate. I have tried hard to optimize my algorithm. What I have achieved is the project can run properly in processing, and data for 2015 publications can be move around smoothly. For showing more data, it needs more patients. But all of the data are correct. The only problem is a little bit slow in interactive graphic display.
Attachments
MAT259_hw2_Hilda_version2.zip
zip file for version 2
(26.39 MiB) Downloaded 158 times
Last edited by changhe on Mon Feb 29, 2016 5:47 pm, edited 5 times in total.

junxiangyao
Posts: 10
Joined: Wed Jan 06, 2016 1:38 pm

Re: PROJ 2: 3D INTERACTION & CHANGE OVER TIME

Post by junxiangyao » Tue Feb 16, 2016 1:17 am

Checkout Times and Duration Times about the Former 6 Movies in the Star Wars Series in Seattle Public Library
JunxiangYao

In this project, I tried to dig deeper. I decided to find the data of a movie series or a novels series in SPL as the database. Since Star Wars 7 had just been released last Christmas, I was curious about the patterns of the former 6 movies in this movie series. And I chose years, months, movie titles, checkout times and duration times as the columns I used in the visualization. Basically, I calculated the total checkout times and the duration times, which is calculated using timediff() function in MySQL, and sorted the data by the order of month and year.

Here is the query of calculating checkout times:

Code: Select all

Select YEAR(checkout) AS Year, MONTH(checkout) AS Month, 
SUM(CASE
WHEN spl.title.title like '%The Phantom Menace%' Then 1 
ELSE 0 END) AS 'StarWar1',
SUM(CASE
WHEN spl.title.title like '%Attack of the Clones%' Then 1 
ELSE 0 END) AS 'StarWar2',
SUM(CASE
WHEN spl.title.title like '%Revenge of the Sith%' Then 1 
ELSE 0 END) AS 'StarWar3',
SUM(CASE
WHEN spl.title.title like '%A New Hope%' Then 1 
ELSE 0 END) AS 'StarWar4',
SUM(CASE
WHEN spl.title.title like '%The Empire Strikes Back%' Then 1 
ELSE 0 END) AS 'StarWar5',
SUM(CASE
WHEN spl.title.title like '%Return of the Jedi%' Then 1 
ELSE 0 END) AS 'StarWar6'
From spl._transactionsExploded, spl.title
WHERE spl._transactionsExploded.bibNumber = spl.title.bibNumber
AND YEAR(checkOut) >= '2006'
AND YEAR(checkOut) < '2016'
GROUP BY MONTH(checkOut) , YEAR(checkOut) 
ORDER BY YEAR(checkOut) , MONTH(checkOut)  
And the query of calculating duration times of Star War 4: The New Hope

Code: Select all

Select YEAR(checkOut) AS Year, 
MONTH(checkOut) AS Month,  
Count(TIMESTAMPDIFF(DAY,checkOut,checkIn))AS'starwas4duration'
From spl._transactionsExploded, spl.title
WHERE spl._transactionsExploded.bibNumber = spl.title.bibNumber
AND spl.title.title like '%A New Hope%'
AND YEAR(checkOut) >= '2006'
AND YEAR(checkOut) < '2016'
GROUP BY MONTH(checkOut) , YEAR(checkOut) 
ORDER BY YEAR(checkOut) , MONTH(checkOut)
My original idea is like this:

The revised version:
屏幕快照 2016-02-18 下午11.50.53.png
My processing code:

Code: Select all

/************************************************************
 * MAT259 PROJ 2 : 3D Interaction & Change Over Time        *
 *                                                          *     
 * Junxiang Yao                                             *   
 *                                                          *
 *                                                          *
 * Usage: Press 1 / 2 / 3 / 4 / 5 / 6 to check movie        *
 *        individually.                                     * 
 *                                                          *  
 *        Press 7 / 8 to check the original / prequel       *
 *        trilogy.                                          *
 *                                                          *
 *        Press 9 / 0 to check all in one / different       *
 *        cordinate systems.                                *
 *                                                          *
 *        Press D to show / hide dots of duration           *
 *        times.                                            *
 *                                                          *
 *        Press S to show / hide the solids.                *
 *                                                          *
 *        Press N to show / hide the cromatic frames.       *
 *                                                          * 
 *        Press F to show / hide grey frames.               *
 *                                                          *    
 *        Press T to show / hide the verbal information.    * 
 *                                                          *
 *        Press L to show / hide the cordinate axis and     *
 *        lables.                                           *
 *                                                          * 
 *        Press G to show / hide the grid system.           *
 *                                                          * 
 *                                                          *
 * Tags:  Interaction - Keyboard Control                    *
 *                                                          *
 *        data        - Containing the data() function      *
 *                      which draws the cordinate axises    * 
 *                      and the dots and calls other        * 
 *                      ralated functions.                  *
 *                                                          *
 *        drawLine    - Including drawHLine() & drawVLine() *
 *                      which draw longitude and latitude.  *
 *                                                          *
 *        drawShape   - Containing drawShape() which paints *
 *                      the color between longitude and     *
 *                      latitude.                           *
 *                                                          *  
 *        gui         - draw verbal information and legends.*
 *                                                          *
 *        mousePressed- Containing mouse pressing events    *
 *                      related code.                       *
 *                                                          *
 ************************************************************/




import controlP5.*;

ControlP5 cp5;

import peasy.*;
import peasy.org.apache.commons.math.*;
import peasy.org.apache.commons.math.geometry.*;
import peasy.test.*;

PeasyCam cam;

PFont f;


int horMargin = 90;
int verMargin = 100;

Table table;//for checkout times
Table table1;//for duration times
Table table2;
Table table3;
Table table4;
Table table5;
Table table6;

int rows;
//matrix countaining data about checkout times
float[][] dataMatrix1;
float[][] dataMatrix2;
float[][] dataMatrix3;
float[][] dataMatrix4;
float[][] dataMatrix5;
float[][] dataMatrix6;

//matrix countaining data about duration times
float[][] duMatrix1;
float[][] duMatrix2;
float[][] duMatrix3;
float[][] duMatrix4;
float[][] duMatrix5;
float[][] duMatrix6;


int year = 10, month =12;
float radM, radY;



boolean fill = true;// paint color on each surfaces
boolean duration = true;//show dots
boolean line = false;//hide the grey frames
boolean cline = true;//show the cromatic frames
boolean [] s;//whether the structure is show or not
boolean [] center;//whether the structure is shown on the center or not

boolean [] highlightingYear;//whether the data of years are highlighted 
boolean [] highlightingMonth;//whether the data of months are highlighted 
boolean grid = false;//hide the grid system
boolean discription = true;//show the verbal information
boolean label = true;//show the cordinate circles and lables
boolean showTitle = true;//show the title of the movie near the cordinate circles
boolean showLegend = false;//hide the legend

String[] monthName = {"January", "February", "March", "April", "May", "June", "July", "August", 
  "September", "October", "November", "December"};
String[] m = {"Jan.", "Feb.", "Mar.", "Apr.", "May", "Jun.", "Jul.", "Aug.", 
  "Sep.", "Oct.", "Nov.", "Dec."};
String[] movieTitle = {"Star Wars I : \nThe Phantom Menace\n1999 ", 
  //"Star War I : \nThe Phantom Menace     \n1999       ", 
  "Star Wars II : \nAttack of the Clones\n2002 ", 
  "Star Wars III : \nRevenge of the Sith\n2005 ", 
  "Star Wars IV : \nA New Hope\n1977 ", 
  "Star Wars V : \nThe Empire Strikes Back\n1980 ", 
  "Star Wars VI : \nReturn of the Jedi\n1983 "};


void setup() {
  size(1280, 720, P3D);

  cam = new PeasyCam(this, 1620);
  cam.setMinimumDistance(200);
  cam.setMaximumDistance(1800);

  f = createFont("Arial", 100);


  highlightingYear = new boolean [10];
  highlightingMonth = new boolean [12];
  s = new boolean [6];
  center = new boolean [6];
  for (int i = 0; i < year; i++) {
    highlightingYear[i]=false;
  }
  for (int i = 0; i < month; i++) {
    highlightingMonth[i]=false;
  }

  for (int i = 0; i < 6; i++) {
    s[i]=true;
  }
  for (int i = 0; i < 6; i++) {
    center[i]=false;
  }

  table = new Table();
  //table1 = new Table();
  table = loadTable("starwarcheckout.csv", "header");

  table1 = loadTable("starwar1_duration.csv", "header");
  table2 = loadTable("starwar2_duration.csv", "header");
  table3 = loadTable("starwar3_duration.csv", "header");
  table4 = loadTable("starwar4_duration.csv", "header");
  table5 = loadTable("starwar5_duration.csv", "header");
  table6 = loadTable("starwar6_duration.csv", "header");


//------------------------------
//Initialize the checkout data
//------------------------------


  cp5 = new ControlP5(this);
  dataMatrix1 = new float[year][month];
  dataMatrix2 = new float[year][month];
  dataMatrix3 = new float[year][month];
  dataMatrix4 = new float[year][month];
  dataMatrix5 = new float[year][month];
  dataMatrix6 = new float[year][month];



  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      dataMatrix1[i][month-1-j] = table.getInt(i*month+j, 2);
    }
  }

  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      dataMatrix2[i][month-1-j] = table.getInt(i*month+j, 3);
    }
  }
  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      dataMatrix3[i][month-1-j] = table.getInt(i*month+j, 4);
    }
  }
  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      dataMatrix4[i][month-1-j] = table.getInt(i*month+j, 5);
    }
  }
  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      dataMatrix5[i][month-1-j] = table.getInt(i*month+j, 6);
    }
  }
  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      dataMatrix6[i][month-1-j] = table.getInt(i*month+j, 7);
    }
  }
    
    
//-----------------------------
//Initialize the duration data
//-----------------------------

  duMatrix1 = new float[year][month];
  duMatrix2 = new float[year][month];
  duMatrix3 = new float[year][month];
  duMatrix4 = new float[year][month];
  duMatrix5 = new float[year][month];
  duMatrix6 = new float[year][month];
  
  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      duMatrix1[i][month-1-j] = table1.getInt(i*month+j, 2);
    }
  }

  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      duMatrix2[i][month-1-j] = table2.getInt(i*month+j, 2);
    }
  }
  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      duMatrix3[i][month-1-j] = table3.getInt(i*month+j, 2);
    }
  }
  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      duMatrix4[i][month-1-j] = table4.getInt(i*month+j, 2);
    }
  }
  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      duMatrix5[i][month-1-j] = table5.getInt(i*month+j, 2);
    }
  }
  for (int i = 0; i < year; i++) {
    for (int j = month-1; j >=0; j--) {
      duMatrix6[i][month-1-j] = table6.getInt(i*month+j, 2);
    }
  }
}


void draw() {  
  smooth();
  rotateX(-.5);
  rotateY(-.5);
  background(56, 48, 60);
  if (s[0]) {
    pushMatrix();  
    int move1;
    if (center[0]) {
      move1 = 0;
      rotateY(0);
    } else {
      move1 = 600;
      rotateY(2*PI/3+PI);
    }
    data(dataMatrix1, move1, 0, color(#ff3535), color(#ffcccc), 
      20, 100, duMatrix1, movieTitle[0]);
    popMatrix();
  }
  if (s[1]) {
    pushMatrix();
    int move2;
    if (center[1]) {
      move2 = 0;
      rotateY(0);
    } else {
      move2 = 600;
      rotateY(TWO_PI);
    }
    data(dataMatrix2, move2, 0, color(#fe9a2e), color(#fcd7ae), 
      20, 100, duMatrix2, movieTitle[1]);
    popMatrix();
  }
  if (s[2]) {
    pushMatrix();
    int move3;
    if (center[2]) {
      move3 = 0;
      rotateY(0);
    } else {
      move3 = 600; 
      rotateY(TWO_PI+PI/3);
    }
    data(dataMatrix3, move3, 0, color(#edc628), color(#edeadc), 
      20, 100, duMatrix3, movieTitle[2]);
    popMatrix();
  }
  if (s[3]) {
    pushMatrix();   
    int move4;
    if (center[3]) {
      move4 = 0;
      rotateY(0);
    } else {
      move4 = 600; 
      rotateY(TWO_PI+2*PI/3);
    }
    data(dataMatrix4, move4, 0, color(#70b70a), color(#b8fcf0), 
      20, 100, duMatrix4, movieTitle[3]);
    popMatrix();
  }
  if (s[4]) {
    pushMatrix();
    int move5;
    if (center[4]) {
      move5 = 0;
      rotateY(0);
    } else {
      move5 = 600;
      rotateY(TWO_PI+PI);
    }
    data(dataMatrix5, move5, 0, color(#4c97dc), color(#b7cbff), 
      20, 100, duMatrix5, movieTitle[4]);
    popMatrix();
  }
  if (s[5]) {
    pushMatrix();    
    int move6;
    if (center[5]) {
      move6 = 0;
      rotateY(0);
    } else {
      move6 = 600;
      rotateY(PI/3+PI);
    }
    data(dataMatrix6, move6, 0, color(#6d6cca), color(#c898df), 
      20, 100, duMatrix6, movieTitle[5]);
    popMatrix();
  }

  if (discription) {
    gui();
  }
}

void keyPressed() {
  // generating surfaces
  if (key == 's' || key == 'S') {
    fill = ! fill;
  }
  
  //showing dots
  if (key == 'd' || key == 'D') {
    duration = ! duration;
  }
  
  //showing grey frames
  if (key == 'f' || key == 'F') {
    line = ! line;
  }
  
  //showing cromatic frames
  if (key == 'n' || key == 'N') {
    cline = ! cline;
  }
  
  //showing verbal information
  if (key == 't' || key == 'T') {
    discription = ! discription;
  }
  
  //showing labels and cordinate circles
  if (key == 'l' || key == 'L') {
    label = ! label;
  }
  
  //showing grid system
  if (key == 'g' || key == 'G') {
    grid = ! grid;
  }


//-----------------------------
//number key controlling
//-----------------------------

//show one structure only
  if (key == '1' || key == '!')
  {
    showTitle = true;
    showLegend = false;
    s[0] = true;
    s[1] = false;
    s[2] = false;
    s[3] = false;
    s[4] = false;
    s[5] = false;
    center[0]=true;
    center[1]=false;
    center[2]=false;
    center[3]=false;
    center[4]=false;
    center[5]=false;
  }
  if (key == '2' || key == '@')
  {
    showTitle = true;
    showLegend = false;
    s[0] = false;
    s[1] = true;
    s[2] = false;
    s[3] = false;
    s[4] = false;
    s[5] = false;
    center[0]=false;
    center[1]=true;
    center[2]=false;
    center[3]=false;
    center[4]=false;
    center[5]=false;
  }
  if (key == '3' || key == '#')
  {
    showTitle = true;
    showLegend = false;
    s[0] = false;
    s[1] = false;
    s[2] = true;
    s[3] = false;
    s[4] = false;
    s[5] = false;
    center[0]=false;
    center[1]=false;
    center[2]=true;
    center[3]=false;
    center[4]=false;
    center[5]=false;
  }
  if (key == '4' || key == '$')
  {
    showTitle = true;
    showLegend = false;
    s[0] = false;
    s[1] = false;
    s[2] = false;
    s[3] = true;
    s[4] = false;
    s[5] = false;
    center[0]=false;
    center[1]=false;
    center[2]=false;
    center[3]=true;
    center[4]=false;
    center[5]=false;
  }
  if (key == '5' || key == '%')
  {
    showTitle = true;
    showLegend = false;
    s[0] = false;
    s[1] = false;
    s[2] = false;
    s[3] = false;
    s[4] = true;
    s[5] = false;
    center[0]=false;
    center[1]=false;
    center[2]=false;
    center[3]=false;
    center[4]=true;
    center[5]=false;
  }
  if (key == '6' || key == '^')
  {
    showTitle = true;
    showLegend = false;
    s[0] = false;
    s[1] = false;
    s[2] = false;
    s[3] = false;
    s[4] = false;
    s[5] = true;
    center[0]=false;
    center[1]=false;
    center[2]=false;
    center[3]=false;
    center[4]=false;
    center[5]=true;
  }
  
//show triology
  if (key == '7' || key == '&')
  {
    showTitle = false;
    showLegend = true;
    s[0] = false;
    s[1] = false;
    s[2] = false;
    s[3] = true;
    s[4] = true;
    s[5] = true;

    center[0]=true;
    center[1]=true;
    center[2]=true;
    center[3]=true;
    center[4]=true;
    center[5]=true;
  }
  if (key == '8' || key == '*')
  {
    showTitle = false;
    showLegend = true;
    s[0] = true;
    s[1] = true;
    s[2] = true;
    s[3] = false;
    s[4] = false;
    s[5] = false;
    center[0]=true;
    center[1]=true;
    center[2]=true;
    center[3]=true;
    center[4]=true;
    center[5]=true;
  }
  
  
  
//show all
  //in one cordinate system
  if (key == '9'|| key =='(' )
  {
    showTitle = false;
    showLegend = true;
    for (int i = 0; i < 6; i++) {
      s[i]=true;
    }
    center[0]=true;
    center[1]=true;
    center[2]=true;
    center[3]=true;
    center[4]=true;
    center[5]=true;
  }
  
  
  //in multi-cordinate systems
  if (key == '0'|| key ==')' )
  {    
    showTitle = true;
    showLegend = false;
    for (int i = 0; i < 6; i++) {
      s[i]=true;
    }
    center[0]=false;
    center[1]=false;
    center[2]=false;
    center[3]=false;
    center[4]=false;
    center[5]=false;
  }
}

void data(float[][]dataMatrix, float x, float z, color c, color cb, int a, 
  color cl, float[][]duMatrix, String movieTitle) {
  pushMatrix();
  fill(10);
  translate(x, 0, z);


  //-----------------------------
  //draw sordinats and labels
  //-----------------------------

  //draw coordinate_month--------
  if (label) {
    pushMatrix();
    noFill();
    rotateY(PI/2);
    stroke(180);
    strokeWeight(1);
    ellipse(0, 0, 400, 400);

    for (int i = 0; i < month; i++) {
      noFill();
      pushMatrix();
      float theta = (i+1)*PI/13;
      translate(200*cos(theta+PI/2), 200*sin(theta+PI/2));
      rotate(theta+PI/2+PI);
      textAlign(LEFT, CENTER);
      fill(180);
      textSize(10);
      text(m[month-1-i], 1, 0);
      popMatrix();
    }
    if (showTitle) {
      textAlign(RIGHT, CENTER);
      fill(180);
      textSize(20);
      text(movieTitle, 190, 0);
      //text(movieTitle, 190, 80);
    }
    popMatrix();



    //draw coordinate_year------------------------
    pushMatrix();
    noFill();
    rotateX(PI/2);
    stroke(180);
    strokeWeight(1);
    ellipse(0, 0, 400, 400);

    for (int i = 2006; i < 2006+year; i++) {
      pushMatrix();
      float theta = (2006+year-i)*TWO_PI/10;
      translate(200*cos(theta+PI/2), 200*sin(theta+PI/2));
      rotate(theta+PI/2+PI);
      textAlign(RIGHT, CENTER);
      fill(180);
      textSize(12);
      text(i+" ", 0, 0);
      popMatrix();
    }
    popMatrix();
  }



  //-----------------------------
  //draw dots
  //-----------------------------
  if (duration) {
    for (int i = 0; i < year; i++) {
      color dcolor = c;
      for (int k = 0; k < year; k++) {
        if (highlightingYear[k]==true && k == i) {
          dcolor = cb;
        }
      }
      radY=i*TWO_PI/year;
      for (int j = 0; j < month; j++) {
        stroke(dcolor, 150);
        for (int k = 0; k < month; k++) {
          if (highlightingMonth[k]==true && k == month - j - 1) {
            stroke(cb, 150);
          }
        }
        radM=(j+1)*(float)PI/13;

        strokeWeight(duMatrix[i][j]/10);
        float r = dataMatrix[i][j];  
        point(r*sin(radY)*sin(radM), r*cos(radM), r*cos(radY)*sin(radM));
      }
    }
  }



  //-----------------------------
  //call other functions
  //-----------------------------

  //for surface
  if (fill) {
    drawShape(dataMatrix, c, cb, a);
  }

  //for cromatic frame
  if (cline) {
    drawHLine(dataMatrix, c);
    drawVLine(dataMatrix, c);
  }
  
  
  //for grey frame
  if (line) {
    drawHLine(dataMatrix, cl);
    drawVLine(dataMatrix, cl);
  } 
  popMatrix();
}

//-----------------------------
//draw horizontal lines
//-----------------------------
void drawHLine(float[][] dataMatrix,color c) { 
    for (int i = 0; i < 10; i++) {
    radY=i*TWO_PI/10;
    for (int j = 0; j < month-1; j++) {
      radM=(j+1)*(float)PI/13;
      stroke(c);
      strokeWeight(1);
      float r = dataMatrix[i][j];
      //int r = 200;
      line(r*sin(radY)*sin(radM), r*cos(radM), r*cos(radY)*sin(radM), 
        dataMatrix[i][j+1]*sin(radY)*sin(radM+PI/13), dataMatrix[i][j+1]*cos(radM+PI/13), dataMatrix[i][j+1]*cos(radY)*sin(radM+PI/13));
    }
  }
}


//-----------------------------
//draw vertical lines
//-----------------------------
void drawVLine(float[][] dataMatrix,color c) {
  for (int j = 0; j < month; j++) {
    radM=(j+1)*(float)PI/13;
    for (int i = 0; i < 10; i++) {
      radY=i*TWO_PI/10;
      stroke(c);
      strokeWeight(1);
      float r = dataMatrix[i][j];
      if (i<9) {
        line(r*sin(radY)*sin(radM), r*cos(radM), r*cos(radY)*sin(radM), 
          dataMatrix[i+1][j]*sin(radY+TWO_PI/10)*sin(radM), dataMatrix[i+1][j]*cos(radM), dataMatrix[i+1][j]*cos(radY+TWO_PI/10)*sin(radM));
      }
      if (i==9) {
        line(r*sin(radY)*sin(radM), r*cos(radM), r*cos(radY)*sin(radM), 
          dataMatrix[0][j]*sin(radY+TWO_PI/10)*sin(radM), dataMatrix[0][j]*cos(radM), dataMatrix[0][j]*cos(radY+TWO_PI/10)*sin(radM));
      }
    }
  }
}


void drawShape(float[][] dataMatrix, color c, color cb, float a) {
  for (int i = 0; i < 10; i++) {
    radY=i*TWO_PI/10;
    for (int j = 0; j < month-1; j++) {
      radM=(j+1)*(float)PI/13;
      noStroke();
      if(cline){
      stroke(c);}
      strokeWeight(1);
      float r = dataMatrix[i][j];
      //int r = 200;
      if (i<9) {
        beginShape();
        fill(c, a);
        vertex(r*sin(radY)*sin(radM), r*cos(radM), r*cos(radY)*sin(radM)); 
        vertex(dataMatrix[i][j+1]*sin(radY)*sin(radM+PI/13), dataMatrix[i][j+1]*cos(radM+PI/13), dataMatrix[i][j+1]*cos(radY)*sin(radM+PI/13));
        vertex(dataMatrix[i+1][j+1]*sin(radY+TWO_PI/10)*sin(radM+PI/13), dataMatrix[i+1][j+1]*cos(radM+PI/13), dataMatrix[i+1][j+1]*cos(radY+TWO_PI/10)*sin(radM+PI/13));
        endShape();
        beginShape();
        fill(c, a);
        vertex(r*sin(radY)*sin(radM), r*cos(radM), r*cos(radY)*sin(radM)); 
        vertex(dataMatrix[i+1][j]*sin(radY+TWO_PI/10)*sin(radM), dataMatrix[i+1][j]*cos(radM), dataMatrix[i+1][j]*cos(radY+TWO_PI/10)*sin(radM));
        vertex(dataMatrix[i+1][j+1]*sin(radY+TWO_PI/10)*sin(radM+PI/13), dataMatrix[i+1][j+1]*cos(radM+PI/13), dataMatrix[i+1][j+1]*cos(radY+TWO_PI/10)*sin(radM+PI/13));
        endShape();
      }
      if (i == 9) {
        beginShape();
        fill(c, a);
        vertex(r*sin(radY)*sin(radM), r*cos(radM), r*cos(radY)*sin(radM)); 
        vertex(dataMatrix[i][j+1]*sin(radY)*sin(radM+PI/13), dataMatrix[i][j+1]*cos(radM+PI/13), dataMatrix[i][j+1]*cos(radY)*sin(radM+PI/13));
        vertex(dataMatrix[0][j+1]*sin(radY+TWO_PI/10)*sin(radM+PI/13), dataMatrix[0][j+1]*cos(radM+PI/13), dataMatrix[0][j+1]*cos(radY+TWO_PI/10)*sin(radM+PI/13));
        endShape();

        beginShape();
        fill(c, a);
        vertex(r*sin(radY)*sin(radM), r*cos(radM), r*cos(radY)*sin(radM)); 
        vertex(dataMatrix[0][j]*sin(radY+TWO_PI/10)*sin(radM), dataMatrix[0][j]*cos(radM), dataMatrix[0][j]*cos(radY+TWO_PI/10)*sin(radM));
        vertex(dataMatrix[0][j+1]*sin(radY+TWO_PI/10)*sin(radM+PI/13), dataMatrix[0][j+1]*cos(radM+PI/13), dataMatrix[0][j+1]*cos(radY+TWO_PI/10)*sin(radM+PI/13));
        endShape();
      }
    }
  }





//-----------------------------
//surfaces on the top & bottom
//-----------------------------

//top--------------------------
  beginShape();
  fill(c, a);
  int k = 1;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 2;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 3;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 3;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 4;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 1;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 0;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 1;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 4;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 0;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 4;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 5;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 9;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 0;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 5;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 9;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 5;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 6;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 9;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 8;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 6;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 6;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 7;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  k = 8;
  vertex(dataMatrix[k][0]*sin(TWO_PI/10*k)*sin(PI/13), dataMatrix[k][0]*cos(PI/13), dataMatrix[k][0]*cos(TWO_PI/10*k)*sin(PI/13));
  endShape();







//bottom---------------------------------------
  beginShape();
  fill(c, a);
  k = 1;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 2;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 3;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 3;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 4;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 1;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 0;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 1;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 4;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 0;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 4;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 5;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 9;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 0;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 5;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 9;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 5;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 6;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 9;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 8;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 6;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  endShape();

  beginShape();
  fill(c, a);
  k = 6;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 7;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  k = 8;
  vertex(dataMatrix[k][11]*sin(TWO_PI/10*k)*sin(12*PI/13), dataMatrix[k][11]*cos(12*PI/13), dataMatrix[k][11]*cos(TWO_PI/10*k)*sin(12*PI/13));
  endShape();
}

void gui() {
  hint(DISABLE_DEPTH_TEST);
  cam.beginHUD();
  cp5.draw();
  //-----------------------------
  //title
  //-----------------------------
  fill(230);
  textAlign(LEFT);
  textFont(f);
  textSize(50);
  text("STAR WARS NEBULA", horMargin, verMargin);
  textSize(16);
  //text("Checkout Times and Duration Times of the", 
  //  horMargin+320, verMargin-40);
  //text("Former 6 in the Serie in Seattle Public Library ", 
  //  horMargin+320, verMargin-20);
  //text("Checkout Times and Duration Times of the", 
  //  horMargin, verMargin+18-20);
  //text("Former 6 in the Serie in Seattle Public Library ", 
  //  horMargin, verMargin+36-20);
  text("Using Data of Checkout Times and Duration Times of the Former 6 in This Movie Series in Seattle Public Library", 
    horMargin, verMargin+18);



  //-----------------------------
  //button for highlighting
  //-----------------------------

  //YEAR-------------------------

  textAlign(LEFT, CENTER);
  fill(200);
  textSize(20);
  text("Year", 
    horMargin, verMargin+72-22);
  rectMode(CORNER);
  for (int i = 0; i < year; i++) {
    if (horMargin<mouseX&&mouseX<horMargin+42) {
      if (mouseY>verMargin+14*i-6+90-20&&mouseY<verMargin+14*i+6+90-20) {
        noStroke();
        fill(200, 50);
        rect(horMargin, verMargin+14*i-6+90-21, 42, 12);
      }
    }
    if (highlightingYear[i]) {
      noStroke();
      fill(255, 100);
      rect(horMargin, verMargin+14*i-6+90-21, 42, 12);
    }
  }
  int startYear=2006;
  for (int i = 0; i < year; i++) {
    textAlign(LEFT, CENTER);
    textSize(12);
    fill(200);
    text(startYear+i, horMargin+1, verMargin + 14*i + 90-22);
  }


  //Month-------------------------------------------------------
  textSize(20);
  text("Month", 
    horMargin+80, verMargin+72-22);
  for (int i = 0; i < month; i++) {
    if (horMargin+80<mouseX&&mouseX<horMargin+151) {
      if (mouseY>verMargin+14*i-6+90-20&&mouseY<verMargin+14*i+6+90-20) {
        noStroke();
        fill(200, 50);
        rect(horMargin+80, verMargin+14*i-6+90-20, 60, 12);
      }
    }
    if (highlightingMonth[i]) {
      noStroke();
      fill(255, 100);
      rect(horMargin+80, verMargin+14*i-6+90-20, 60, 12);
    }
  }
  for (int i = 0; i < month; i++) {
    textAlign(LEFT, CENTER);
    textSize(12);
    fill(200);
    text(monthName[i], horMargin+1+80, verMargin + 14*i + 90-22);
  }


  //Reset------------------------------------------------------------
  textSize(20);
  fill(200);
  text("Reset", 
    horMargin, verMargin+250-4);
  textSize(12);
  textAlign(LEFT, CENTER);
  text("Years", 
    horMargin+1, verMargin+250+14);
  text("Months", 
    horMargin+1, verMargin+250+28);
  text("All", 
    horMargin+1, verMargin+250+42);
  for (int i = 0; i < 3; i++) {
    if (horMargin<mouseX&&mouseX<horMargin+52) {
      if (mouseY>verMargin+14*(i+1)+250&&mouseY<verMargin+14*(i+2)+250) {
        noStroke();
        fill(200, 50);
        rect(horMargin, verMargin+14*(i+1)+250-5, 52, 12);
      }
    }
  }




  //-----------------------------
  //name
  //-----------------------------
  fill(200);
  textAlign(LEFT, CENTER);
  textSize(14);
  text("Junxiang Yao", 
    width - horMargin - 200, verMargin+330);
  text("MAT259 PROJ 2", 
    width - horMargin - 200, verMargin+346);
  text("3D Interaction & Change Over Time", 
    width - horMargin - 200, verMargin+360);



  //-----------------------------
  //grid system
  //----------------------------- 
  if (grid) {
    stroke(#6d6cca);
    strokeWeight(1);
    line(0, verMargin, width, verMargin);
    line(0, verMargin+8+16, width, verMargin+8+16);
    line(0, verMargin+8+16+20, width, verMargin+8+16+20);
    line(0, verMargin+8+16+40, width, verMargin+8+16+40);
    line(0, verMargin+8+16+206, width, verMargin+8+16+206);
    line(0, verMargin+8+16+216, width, verMargin+8+16+216);
    line(0, verMargin+8+16+304, width, verMargin+8+16+304);
    line(0, verMargin+412, width, verMargin+412);
    line(0, height-verMargin, width, height-verMargin);

    line(horMargin, 0, horMargin, height);
    line(horMargin + 80, 0, horMargin + 80, height);
    line(horMargin + 160, 0, horMargin + 160, height);
    line(width - horMargin - 200, 0, width - horMargin - 200, height); 
    line(width-horMargin, 0, width-horMargin, height);
  }


  //-----------------------------
  //keyboard  control discription
  //-----------------------------
  fill(200);
  textSize(20);
  text("Keyboard Control", 
    horMargin, verMargin+416);


  textSize(12);
  textAlign(LEFT, CENTER);

  text("Press 1 / 2 / 3 / 4 / 5 / 6 to check movie individually", 
    horMargin, verMargin+416+20);
  text("Press 7 / 8 to check the original / prequel trilogy", 
    horMargin, verMargin+14+416+20);
  text("Press 9 / 0 to check all in one / different cordinate systems", 
    horMargin, verMargin+28+416+20);
  text("Press D to show / hide dots of duration times", 
    horMargin, verMargin+42+416+20);  
  text("Press S to show / hide the solids", 
    horMargin, verMargin+56+416+20);
  text("Press N to show / hide the cromatic frames", 
    horMargin, verMargin+70+416+20);
  text("Press F to show / hide grey frames", 
    horMargin, verMargin+84+416+20);
  text("Press T to show / hide the verbal information", 
    horMargin, verMargin+98+416+20);
  text("Press L to show / hide the cordinate axis and lables", 
    horMargin, verMargin+112+416+20);


  //-----------------------------
  //scaling legend
  //-----------------------------
  fill(200);
  textSize(12);
  text("The radius of the circular cordinate", 
    width - horMargin - 200, verMargin+416);
  text("axis is 200 checkout times.", 
    width - horMargin - 200, verMargin+430);
  text("Duration time scaling:", 
    width - horMargin - 200, verMargin+458);
  textSize(10);
  for (int i = 0; i < 6; i++) {
    noStroke();
    textAlign(CENTER);
    fill(200, 150);
    ellipse( width - horMargin - 200 + 24*i + 12*i + 6, verMargin+490, 4 *(i+1), 4*(i+1));
    fill(200);
    text(40*(i+1), width - horMargin - 200 + 24*i + 12*i + 6, verMargin+490+24);
  }


  //-----------------------------
  //color legend
  //-----------------------------
  if (showLegend) {
    fill(200);
    textSize(12);
    textAlign(LEFT, CENTER);
    text("Star Wars I (1999)", 
      horMargin + 6 + 160, verMargin+330+1);
    text("Star Wars II (2002)", 
      horMargin + 6 + 160, verMargin+344+1);
    text("Star Wars III (2005)", 
      horMargin + 6 + 160, verMargin+358+1);
    text("Star Wars IV (1977)", 
      horMargin + 6, verMargin+330+1);
    text("Star Wars V (1980)", 
      horMargin + 6, verMargin+344+1);
    text("Star Wars VI (1983)", 
      horMargin + 6, verMargin+358+1);
    rectMode(CENTER);
    fill(color(#ff3535)); 
    noStroke(); 
    rect(horMargin + 1 + 160, verMargin+330+2, 2, 10);
    fill(color(#fe9a2e)); 
    noStroke(); 
    rect(horMargin + 1 + 160, verMargin+344+2, 2, 10);
    fill(color(#edc628)); 
    noStroke(); 
    rect(horMargin + 1 + 160, verMargin+358+2, 2, 10);
    fill(color(#70b70a)); 
    noStroke(); 
    rect(horMargin + 1, verMargin+330+2, 2, 10);
    fill(color(#4c97dc)); 
    noStroke(); 
    rect(horMargin + 1, verMargin+344+2, 2, 10);
    fill(color(#6d6cca)); 
    noStroke(); 
    rect(horMargin + 1, verMargin+358+2, 2, 10);
  }



  cam.endHUD();
  hint(ENABLE_DEPTH_TEST);
}



I used grid system while designing the layout.
屏幕快照 2016-02-19 上午12.09.50.png
Final Result:
屏幕快照 2016-02-18 下午11.52.53.png
屏幕快照 2016-02-18 下午11.53.05.png
屏幕快照 2016-02-18 下午11.53.35.png
屏幕快照 2016-02-18 下午11.54.15.png
屏幕快照 2016-02-18 下午11.54.52.png
屏幕快照 2016-02-18 下午11.55.19.png
屏幕快照 2016-02-18 下午11.56.22.png
屏幕快照 2016-02-18 下午11.56.51.png
Attachments
JunxiangYaoProj2V3.zip
(16.15 KiB) Downloaded 154 times
Last edited by junxiangyao on Fri Feb 19, 2016 12:12 am, edited 9 times in total.

joo
Posts: 4
Joined: Thu Jan 07, 2016 10:19 am

Re: PROJ 2: 3D INTERACTION & CHANGE OVER TIME (updated)

Post by joo » Tue Feb 16, 2016 1:33 am

Travel Books Checkouts from 2010 to 2015

I am going to look closely into dewey class between 914 and 919 since the data that I used last time contains some of non-travel books. This version only shows travel-related books and the top lists in each travel category.

My additional questions are:
where is the most popular spot in each dewey class?
How does checkout frequency change from month to month, year to year?
The checkout period comparison among all travel dewey classes.

I observed some checkout rate changes every month for 6 years, and also checked the popular books at the top of the list in this category. I attached my SQL query combining 5 tables from a new spl DB.

Each dewey class has a certain color within the hue range (0 to 360). The width of the unit varies depends on the checkout frequencies, and the fill colors of all units change according to popularities increasing or decreasing RGB values.

Below is examples of the final screen shots including control P5. Control P5 allows to turn on and off line connecting each units, showing labels, and the movement of all units.

The graph description
X-axis: Date from the first week of 2010 to the last week of 2015 (Week Based)
Y-axis: Checkout Time between 10AM to 20PM
Z-axis: Dewey Class between 914 to 919
Unit Stroke Color: Dewey Classification
Unit Size and Fill Color: Checkout rates

Time-Year View
11.png
Dewey Class
22.png
Lebels X: Time(Week Based), Y: Time, Z: Category
33.png
Zoom In
4.png
Zoom In Z Axis View
5.png
Regular Z Axis View
6.png
Zoom In
7 .png
Zoom In connecting lines
8.png
Zoom In connecting lines
9.png
Interaction
The check boxes from dewey class 914 to 919 draw lines between all units to check the range of fluctuation.
Label On/Off: It shows what data each axis contains.
Motion On/Off: Based on the value each unit has, it animates all shapes changing the width.
Rotating: The graph is rotating automatically by default.

SQL

Code: Select all

#3D assignment 914
SELECT 
    deweyClass AS Dewey,
    title AS BookTitle,
    subject AS Category,
    DATE(checkOut) AS CheckoutDate,
    TIME(checkOut) AS CheckoutTime,
	COUNT(checkOut) AS CheckoutCount,
    itemtype AS ItemType,
    TIMESTAMPDIFF(DAY, checkOut, checkInFirst)
FROM
    spl.deweyClass,
    spl.transactions,
    spl.title,
    spl.itemType,
    spl.itemToBib,
    spl.subject
WHERE
    deweyClass = 914
		-- And (TIMESTAMPDIFF(DAY, checkOut, checkInFirst) != '')
		#AND deweyClass <= 919
        AND spl.deweyClass.bibNumber = spl.transactions.bibNumber
        AND spl.deweyClass.bibNumber = spl.title.bibNumber
        AND spl.deweyClass.bibNumber = spl.subject.bibNumber
        AND spl.deweyClass.bibNumber = spl.itemToBib.bibNumber
        AND spl.itemToBib.itemNumber = spl.itemType.itemNumber
        AND (spl.subject.subject LIKE '%travel%' 
				OR spl.subject.subject LIKE '%guide%' 
                OR spl.subject.subject LIKE '%guidebook%')
		AND (itemType = 'acbk' 
				OR itemType = 'acdvd'
				OR itemType = 'acvhs'
				OR itemType = 'jcbk'
				OR itemType = 'jcdvd'
				OR itemType = 'jcvhs')
		AND YEAR(checkOut) >= '2010'
GROUP BY title
ORDER BY CheckoutCount DESC

#3D assignment 915
SELECT 
    deweyClass AS Dewey,
    title AS BookTitle,
    subject AS Category,
    DATE(checkOut) AS CheckoutDate,
    TIME(checkOut) AS CheckoutTime,
	COUNT(checkOut) AS CheckoutCount,
    itemtype AS ItemType,
    TIMESTAMPDIFF(DAY, checkOut, checkInFirst)
FROM
    spl.deweyClass,
    spl.transactions,
    spl.title,
    spl.itemType,
    spl.itemToBib,
    spl.subject
WHERE
    deweyClass = 915
		-- And (TIMESTAMPDIFF(DAY, checkOut, checkInFirst) != '')
		#AND deweyClass <= 919
        AND spl.deweyClass.bibNumber = spl.transactions.bibNumber
        AND spl.deweyClass.bibNumber = spl.title.bibNumber
        AND spl.deweyClass.bibNumber = spl.subject.bibNumber
        AND spl.deweyClass.bibNumber = spl.itemToBib.bibNumber
        AND spl.itemToBib.itemNumber = spl.itemType.itemNumber
        AND (spl.subject.subject LIKE '%travel%' 
				OR spl.subject.subject LIKE '%guide%' 
                OR spl.subject.subject LIKE '%guidebook%')
		AND (itemType = 'acbk' 
				OR itemType = 'acdvd'
				OR itemType = 'acvhs'
				OR itemType = 'jcbk'
				OR itemType = 'jcdvd'
				OR itemType = 'jcvhs')
		AND YEAR(checkOut) >= '2010'
GROUP BY title
ORDER BY CheckoutCount DESC

#3D assignment 916
SELECT 
    deweyClass AS Dewey,
    title AS BookTitle,
    subject AS Category,
    DATE(checkOut) AS CheckoutDate,
    TIME(checkOut) AS CheckoutTime,
	COUNT(checkOut) AS CheckoutCount,
    itemtype AS ItemType,
    TIMESTAMPDIFF(DAY, checkOut, checkInFirst)
FROM
    spl.deweyClass,
    spl.transactions,
    spl.title,
    spl.itemType,
    spl.itemToBib,
    spl.subject
WHERE
    deweyClass = 916
		-- And (TIMESTAMPDIFF(DAY, checkOut, checkInFirst) != '')
		#AND deweyClass <= 919
        AND spl.deweyClass.bibNumber = spl.transactions.bibNumber
        AND spl.deweyClass.bibNumber = spl.title.bibNumber
        AND spl.deweyClass.bibNumber = spl.subject.bibNumber
        AND spl.deweyClass.bibNumber = spl.itemToBib.bibNumber
        AND spl.itemToBib.itemNumber = spl.itemType.itemNumber
        AND (spl.subject.subject LIKE '%travel%' 
				OR spl.subject.subject LIKE '%guide%' 
                OR spl.subject.subject LIKE '%guidebook%')
		AND (itemType = 'acbk' 
				OR itemType = 'acdvd'
				OR itemType = 'acvhs'
				OR itemType = 'jcbk'
				OR itemType = 'jcdvd'
				OR itemType = 'jcvhs')
		AND YEAR(checkOut) >= '2010'
GROUP BY title
ORDER BY CheckoutCount DESC

#3D assignment 917
SELECT 
    deweyClass AS Dewey,
    title AS BookTitle,
    subject AS Category,
    DATE(checkOut) AS CheckoutDate,
    TIME(checkOut) AS CheckoutTime,
	COUNT(checkOut) AS CheckoutCount,
    itemtype AS ItemType,
    TIMESTAMPDIFF(DAY, checkOut, checkInFirst)
FROM
    spl.deweyClass,
    spl.transactions,
    spl.title,
    spl.itemType,
    spl.itemToBib,
    spl.subject
WHERE
    deweyClass = 917
		-- And (TIMESTAMPDIFF(DAY, checkOut, checkInFirst) != '')
		#AND deweyClass <= 919
        AND spl.deweyClass.bibNumber = spl.transactions.bibNumber
        AND spl.deweyClass.bibNumber = spl.title.bibNumber
        AND spl.deweyClass.bibNumber = spl.subject.bibNumber
        AND spl.deweyClass.bibNumber = spl.itemToBib.bibNumber
        AND spl.itemToBib.itemNumber = spl.itemType.itemNumber
        AND (spl.subject.subject LIKE '%travel%' 
				OR spl.subject.subject LIKE '%guide%' 
                OR spl.subject.subject LIKE '%guidebook%')
		AND (itemType = 'acbk' 
				OR itemType = 'acdvd'
				OR itemType = 'acvhs'
				OR itemType = 'jcbk'
				OR itemType = 'jcdvd'
				OR itemType = 'jcvhs')
		AND YEAR(checkOut) >= '2010'
GROUP BY title
ORDER BY CheckoutCount DESC

#3D assignment 918
SELECT 
    deweyClass AS Dewey,
    title AS BookTitle,
    subject AS Category,
    DATE(checkOut) AS CheckoutDate,
    TIME(checkOut) AS CheckoutTime,
	COUNT(checkOut) AS CheckoutCount,
    itemtype AS ItemType,
    TIMESTAMPDIFF(DAY, checkOut, checkInFirst)
FROM
    spl.deweyClass,
    spl.transactions,
    spl.title,
    spl.itemType,
    spl.itemToBib,
    spl.subject
WHERE
    deweyClass = 918
		-- And (TIMESTAMPDIFF(DAY, checkOut, checkInFirst) != '')
		#AND deweyClass <= 919
        AND spl.deweyClass.bibNumber = spl.transactions.bibNumber
        AND spl.deweyClass.bibNumber = spl.title.bibNumber
        AND spl.deweyClass.bibNumber = spl.subject.bibNumber
        AND spl.deweyClass.bibNumber = spl.itemToBib.bibNumber
        AND spl.itemToBib.itemNumber = spl.itemType.itemNumber
        AND (spl.subject.subject LIKE '%travel%' 
				OR spl.subject.subject LIKE '%guide%' 
                OR spl.subject.subject LIKE '%guidebook%')
		AND (itemType = 'acbk' 
				OR itemType = 'acdvd'
				OR itemType = 'acvhs'
				OR itemType = 'jcbk'
				OR itemType = 'jcdvd'
				OR itemType = 'jcvhs')
		AND YEAR(checkOut) >= '2010'
GROUP BY title
ORDER BY CheckoutCount DESC

#3D assignment 919
SELECT 
    deweyClass AS Dewey,
    title AS BookTitle,
    subject AS Category,
    DATE(checkOut) AS CheckoutDate,
    TIME(checkOut) AS CheckoutTime,
	COUNT(checkOut) AS CheckoutCount,
    itemtype AS ItemType,
    TIMESTAMPDIFF(DAY, checkOut, checkInFirst)
FROM
    spl.deweyClass,
    spl.transactions,
    spl.title,
    spl.itemType,
    spl.itemToBib,
    spl.subject
WHERE
    deweyClass = 919
		-- And (TIMESTAMPDIFF(DAY, checkOut, checkInFirst) != '')
		#AND deweyClass <= 919
        AND spl.deweyClass.bibNumber = spl.transactions.bibNumber
        AND spl.deweyClass.bibNumber = spl.title.bibNumber
        AND spl.deweyClass.bibNumber = spl.subject.bibNumber
        AND spl.deweyClass.bibNumber = spl.itemToBib.bibNumber
        AND spl.itemToBib.itemNumber = spl.itemType.itemNumber
        AND (spl.subject.subject LIKE '%travel%' 
				OR spl.subject.subject LIKE '%guide%' 
                OR spl.subject.subject LIKE '%guidebook%')
		AND (itemType = 'acbk' 
				OR itemType = 'acdvd'
				OR itemType = 'acvhs'
				OR itemType = 'jcbk'
				OR itemType = 'jcdvd'
				OR itemType = 'jcvhs')
		AND YEAR(checkOut) >= '2010'
GROUP BY title
ORDER BY CheckoutCount DESC
Processing Code (Newly Updated)

Code: Select all

//3D assignment 
//Woohun Joo

import peasy.*;
PeasyCam cam;

import controlP5.*;
import processing.opengl.*;

ControlP5 cp5;

//checkbox
CheckBox checkbox;
CheckBox checkbox1;
int myColorBackground;

Table table;
int rowNums;

int boxSize = 1200;
boolean lining = false;
boolean lining1 = false;
boolean lining2 = false;
boolean lining3 = false;
boolean lining4 = false;
boolean lining5 = false;
boolean lining6 = false;

boolean text1 = false;
boolean text2 = false;
boolean text3 = false;
boolean mov = false;
boolean rot = true;
boolean dir = false;

//rotating unit
float y = 0.1;

//moving size
float moving = 1.0;
boolean movPos = true;


//book array
ArrayList<Travelbook> books = new ArrayList<Travelbook>();

//font
PFont myFont1;

//dewey
String [] deweyClass = {"EUROPE","ASIA","AFRICA","S.AMERICA","N.AMERICA","ETC"};
//time
String [] timeRange = {"10:00 AM", "11:00 AM", "12:00 PM", "1:00 PM", "2:00 PM", 
                      "3:00 PM", "4:00 PM", "5:00 PM", "6:00 PM", "7:00 PM", "8:00 PM"};
//time
String [] yearRange = {"2010", "2011", "2012", "2013", "2014", "2015"};      



void setup(){
  size(1928, 1024, P3D);
  cam = new PeasyCam(this, 2000);
  //cam.lookAt(frameCount, 0, 0);
  
 
  cp5 = new ControlP5(this);
  cp5.setAutoDraw(false);
  
  //checkbox
  checkbox = cp5.addCheckBox("checkBox")
                .setPosition(60, 130)
                .setSize(10, 10)
                .setItemsPerRow(1)
                .setSpacingColumn(30)
                .setSpacingRow(10)
                .setColorLabel(color(0,0,0))
                .addItem("914: Europe", 0)
                .addItem("915: Asia", 50)
                .addItem("916: Africa", 100)
                .addItem("917: N.America", 150)
                .addItem("918: S.America", 200)
                .addItem("919: Australasia, Pacific, Atlantic Ocean, Arctic islands, Antarctica", 250)
                .addItem("ALL", 300)
                ;
                
    checkbox1 = cp5.addCheckBox("checkBox1")
                .setPosition(60, 280)
                .setSize(10, 10)
                .setItemsPerRow(1)
                .setSpacingColumn(30)
                .setSpacingRow(10)
                .setColorLabel(color(0,0,0))
             
                .addItem("LABEL ON/OFF", 0)
                .addItem("MOTION ON/OFF", 50)
                .addItem("ROTATING", 100)
                ;                

  //font
  myFont1 = createFont("DIN Bold",18);
  
  table = loadTable("total2.csv", "header");
  rowNums = table.getRowCount();
  println("Rows: " + rowNums);
  
  //get table data
  for(int i=0; i<rowNums; i++){
    int dewey = table.getInt(i, 0); //z axis
    String title = table.getString(i, 1); //mouse over
    String date = table.getString(i, 3); //x axis
    String time = table.getString(i, 4); //y axis
    int count = table.getInt(i, 5); //size?
    int keep = table.getInt(i, 7); //color variation
    books.add(new Travelbook(dewey, title, date, time, count, keep));
  }
  
  //print row data
  println("Number of Books: " + books.size());
  println("Dewey: " +books.get(0).dewey);
  println("Title: " +books.get(0).title);
  println("Date: " +books.get(0).date);
  println("Time: " +books.get(0).time);
  println("Checkouts: " +books.get(0).count);
}

//treemap
//controlP5


void draw(){
  
  background(210, 210, 210);
  
  if(rot == true){
  rotateY(frameCount*-0.001);
  }
  
  stroke(255, 0, 0);
  
  //float add = 0.0;
  
  //if(mov == true){
  //moving++;
  //}
  //if(mov == true) {
  //  if(dir == false){
  //    moving++;
  //  }if(dir == true){
  //    moving--;
  //  }
  
  //}
  
  if(mov == true) {
    if(movPos == true) moving++;
    else moving --;
  }
  
  //data parser
  for(int i=0; i<books.size()-1; i++){
    
    //x = date / 2005~2015 / 6 years / week-based
    float dateAxis = map(weekParser(books.get(i).date), 0, 6 * 365 / 7, -boxSize/2, boxSize/2);
    //y = time / 10am ~ 20pm
    float timeAxis = map(timeParser(books.get(i).time), 600, 1200, -boxSize/2, boxSize/2);
    //z = deweyclass
    float deweyAxis = map(books.get(i).dewey, 914, 919, -boxSize/2, boxSize/2);
    //unit width = checkout counts
    float countAxis = map(log(books.get(i).count), log(1), log(170000), 5, 300);
    //unit color = checkout counts

    float colorAxis = map(log(books.get(i).count), log(1), log(170000), 0, 255);
    
    //temp x
    float dateAxis1 = map(weekParser(books.get(i+1).date), 0, 6 * 365 / 7, -boxSize/2, boxSize/2);
    //temp y
    float timeAxis1 = map(timeParser(books.get(i+1).time), 600, 1200, -boxSize/2, boxSize/2);
    ////temp z
    float deweyAxis1 = map(books.get(i+1).dewey, 914, 919, -boxSize/2, boxSize/2);
    
    //unit color
    colorMode(HSB, 360, 100, 100);
    color c = unitColor(books.get(i).dewey);
    
    colorMode(RGB, 255, 255, 255);
    //unit color and transparency
    //255 opaque, 0 transparent , rgb, alpha
    if(books.get(i).dewey == 914){
      fill(255, colorAxis, 0, 230);
    } else if(books.get(i).dewey == 915){
      fill(colorAxis, 255, 0, 230);
    } else if(books.get(i).dewey == 916){
      fill(0,colorAxis, 255, 230);
    } else if(books.get(i).dewey == 917){
      fill(colorAxis, 100, 255, 230);
    } else if(books.get(i).dewey == 918){
      fill(60, 100, colorAxis+50, 230);
    } else if(books.get(i).dewey == 919){
      fill(320, 100, colorAxis, 230);
    }
     
    //unit stroke, strokeweight, fillcolor
    strokeWeight(0.5);
    stroke(c);
    //fill();
    colorMode(RGB, 255, 255, 255);
    
    pushMatrix();
    
    if(timeAxis <= boxSize/2 & timeAxis >= -boxSize/2 
      & dateAxis <= boxSize/2 & dateAxis >= -boxSize/2
      & deweyAxis <= boxSize/2 & deweyAxis >= -boxSize/2
      & countAxis <= boxSize/2 & countAxis >= -boxSize/2){
      translate(dateAxis, timeAxis, deweyAxis);
      
      //moving unit size
      if(moving > countAxis*4) movPos = false;
      if(moving < 3) movPos = true;
      
      box(10, 10, countAxis+moving); //w, h, d
    }
    popMatrix();
    
    //connecting line stroke
    strokeWeight(0.5);
    
    
    //line
    if(lining == true){
      stroke(50);
      line(dateAxis, timeAxis, deweyAxis, dateAxis1, timeAxis1, deweyAxis1);
    }else if(lining1 == true & books.get(i).dewey == 914){
      stroke(255, 0, 0);
      line(dateAxis, timeAxis, deweyAxis, dateAxis1, timeAxis1, deweyAxis1);
    }else if (lining2 == true & books.get(i).dewey == 915){
      stroke(0, 255, 0);
      line(dateAxis, timeAxis, deweyAxis, dateAxis1, timeAxis1, deweyAxis1);
    }else if (lining3 == true & books.get(i).dewey == 916){
      stroke(0, 150, 255);
      line(dateAxis, timeAxis, deweyAxis, dateAxis1, timeAxis1, deweyAxis1);
    }else if (lining4 == true & books.get(i).dewey == 917){
      stroke(0, 170, 255);
      line(dateAxis, timeAxis, deweyAxis, dateAxis1, timeAxis1, deweyAxis1);
    }else if (lining5 == true & books.get(i).dewey == 918){
      stroke(43, 0, 255);
      line(dateAxis, timeAxis, deweyAxis, dateAxis1, timeAxis1, deweyAxis1);
    }else if (lining6 == true & books.get(i).dewey == 919){
      stroke(255, 0, 170);
      line(dateAxis, timeAxis, deweyAxis, dateAxis1, timeAxis1, deweyAxis1);
    } 
  }
  
  //text dewey
  for(int dw=0; dw<6; dw++){
    if(dw==0){
      fill(255, 0, 0);
    }else if(dw==1){
      fill(0, 160, 0);
    }else if(dw==2){
      fill(0, 97, 255);
    }else if(dw==3){
      fill(0, 170, 255);
    }else if(dw==4){
      fill(43, 0, 255);
    }else if(dw==5){
      fill(255, 0, 170);
    }
    textFont(myFont1);
    textAlign(LEFT, CENTER);
    
    if(text1 == true){
    text(deweyClass[dw], boxSize/2 + 10, boxSize/2, (boxSize/5)*dw-(boxSize/2));
    }
  }
  //text time
  for(int tm=0; tm<11; tm++){
    textFont(myFont1);
    textAlign(LEFT, CENTER);
    fill(0, 0, 0);
    if(text2 == true){
    text(timeRange[tm], -boxSize/2 - 90, (-boxSize/10)*tm+(boxSize/2), boxSize/2);
    }
  }
  //text year
  for(int yr=0; yr<6; yr++){
    textFont(myFont1);
    textAlign(LEFT, CENTER);
    fill(0, 0, 0);
    if(text3 == true){
    text(yearRange[yr], (boxSize/5)*yr-(boxSize/2), boxSize/2 + 50, boxSize/2);  
    }
  }
  
  //big box stroke
  //strokeWeight(5);
  noStroke();
  //stroke(255, 0, 0, 255);
  //inner cube
  noFill();
  box(boxSize);
  gui();
  
}

void gui() {
  hint(DISABLE_DEPTH_TEST);
  cam.beginHUD();
  cp5.draw();
  cam.endHUD();
  hint(ENABLE_DEPTH_TEST);
}

void checkBox(float[] a) {
  println(a);
}

class Travelbook{
  int dewey;
  String title;
  String date;
  String time;
  int count;
  int keep;
  
  
  Travelbook(int dewey, String title, String date, String time, int count, int keep){
    this.dewey = dewey;
    this.title = title;
    this.date = date;
    this.time = time;
    this.count = count;
    this.keep = keep;
  }
}

color unitColor(int subject){
  color c = #FFFFFF;
  if(subject == 914){
    c = color(0, 100, 100);
  } else if(subject == 915){
    c = color(30, 100, 100);
  } else if(subject == 916){
    c = color(140, 100, 100);
  } else if(subject == 917){
    c = color(200, 100, 100);
  } else if(subject == 918){
    c = color(250, 100, 100);
  } else if(subject == 919){
    c = color(320, 100, 100);
  }
  return c;
}




float timeParser(String rawTime){
  String[] times = split(rawTime, ':');
  float parsedTime = float(times[0])*60 + float(times[1]);
  return parsedTime;
}

int startYear = 2010;

//calculate
float dateParser(String rawDate){
  String[] dates = split(rawDate, '-');
  float parsedDate = (float(dates[0])-startYear)*365 + (float(dates[1])-1)*30 + float(dates[2]);
  return parsedDate;
}

float weekParser(String rawDate) {
  float day =  dateParser(rawDate);
  return day / 7;
}

void keyPressed() {
  //line
  if(key == 'l' || key == 'L'){
    if(lining == false) lining = true;
    else if(lining == true) lining = false;
  }
  
  if(key == '4' || key == '$'){
    if(lining1 == false) lining1 = true;
    else if(lining1 == true) lining1 = false;
  }
  
  if(key == '5' || key == '%'){
    if(lining2 == false) lining2 = true;
    else if(lining2 == true) lining2 = false;
  }
  
  if(key == '6' || key == '^'){
    if(lining3 == false) lining3 = true;
    else if(lining3 == true) lining3 = false;
  }
  
  if(key == '7' || key == '&'){
    if(lining4 == false) lining4 = true;
    else if(lining4 == true) lining4 = false;
  }
  
  if(key == '8' || key == '*'){
    if(lining5 == false) lining5 = true;
    else if(lining5 == true) lining5 = false;
  }
  
  if(key == '9' || key == '('){
    if(lining6 == false) lining6 = true;
    else if(lining6 == true) lining6 = false;
  }
  

  
  //checkbox
  if (key==' ') {
    checkbox.deactivateAll();
  } 
  else {
    for (int i=0;i<7;i++) {
      // check if key 0-5 have been pressed and toggle
      // the checkbox item accordingly.
      if (keyCode==(48 + i)) { 
        // the index of checkbox items start at 0
        checkbox.toggle(i);
        println("toggle "+checkbox.getItem(i).getName());
        // also see 
        // checkbox.activate(index);
        // checkbox.deactivate(index);
      }
    }
  }
}

public void controlEvent(ControlEvent c) {
  // when a value change from a ColorPicker is received, extract the ARGB values
  // from the controller's array value

  
  //checkbox
   if (c.isFrom(checkbox)) {

    for (int i=0;i<checkbox.getArrayValue().length;i++) {
      int n = (int)checkbox.getArrayValue()[i];
      print(n);
      if(i==0 && n==0) {
        lining1 = false;
      }else if(i==0 && n==1) {
        lining1 = true;
      }
      if(i==1 && n==0) {
        lining2 = false;
      }else if(i==1 && n==1) {
        lining2 = true;
      }    
      if(i==2 && n==0) {
        lining3 = false;
      }else if(i==2 && n==1) {
        lining3 = true;
      }
      if(i==3 && n==0) {
        lining4 = false;
      }else if(i==3 && n==1) {
        lining4 = true;
      }
      if(i==4 && n==0) {
        lining5 = false;
      }else if(i==4 && n==1) {
        lining5 = true;
      } 
      if(i==5 && n==0) {
        lining6 = false;
      }else if(i==5 && n==1) {
        lining6 = true;
      }       
      if(i==6 && n==0) {
        lining = false;
      }else if(i==6 && n==1) {
        lining = true;
      } 
    }
    println();    
  }
  
  //checkbox 2
   if (c.isFrom(checkbox1)) {

    for (int i=0;i<checkbox1.getArrayValue().length;i++) {
      int n = (int)checkbox1.getArrayValue()[i];
      print(n);
      if(i==0 && n==0) {
        text1 = false;
        text2 = false;
        text3 = false;
      }else if(i==0 && n==1) {
        text1 = true;
        text2 = true;
        text3 = true;
      }
      if(i==1 && n==0) {
        mov = false;
      }else if(i==1 && n==1) {
        mov = true;
      }
      if(i==2 && n==0) {
        rot = true;
      }else if(i==2 && n==1) {
        rot = false;
      }
    }
    println();    
  }
}

void picker(int col) {
  println("picker\talpha:"+alpha(col)+"\tred:"+red(col)+"\tgreen:"+green(col)+"\tblue:"+blue(col)+"\tcol"+col);
}
Last edited by joo on Sun Feb 28, 2016 9:56 pm, edited 7 times in total.

d.aleman.24.da
Posts: 4
Joined: Wed Jan 06, 2016 1:40 pm

Re: PROJ 2: 3D INTERACTION & CHANGE OVER TIME

Post by d.aleman.24.da » Tue Feb 16, 2016 1:49 am

As we continue to rely on technology to get us through the day, the demand for engineers and computer scientists are high. New products seem to be released everyday which will create an interest in people to learn more and research on topics such as: programming, engineering, etc. I attempt to visualize how The Seattle Public Library attempts to keep their collection relevant with books and other media relating to these keywords: Technology, Programming, Engineering, Code, and Computer.

With the query shown below, I decided to extract the the title, itemType, callNumber, date of first check out and the amount of books they have of that type (counts).

Code: Select all

SELECT DISTINCT
    title.title,
    (CASE
        WHEN SUBSTRING(itemType.itemType, 3, 3) = 'bk' THEN 'book'
        WHEN SUBSTRING(itemType.itemType, 3, 3) = 'cd' THEN 'audioBook'
        WHEN SUBSTRING(itemType.itemType, 3, 3) = 'cdr' THEN 'CDMedia'
        WHEN SUBSTRING(itemType.itemType, 3, 3) = 'vhs' THEN 'video'
        WHEN SUBSTRING(itemType.itemType, 3, 3) = 'dvd' THEN 'video'
        ELSE 'OTHERS'
    END) AS type,
    (CASE
        WHEN spl.keyword.keyword = 'Technology' THEN 'Tech'
        WHEN spl.keyword.keyword = 'Programming' THEN 'Programming'
        WHEN spl.keyword.keyword = 'Engineering' THEN 'Engineering'
        WHEN spl.keyword.keyword = 'Code' THEN 'Coding'
        WHEN spl.keyword.keyword = 'Computer' THEN 'Computing'
        ELSE 'OTHERS'
    END) AS keyWord,
    DATE(checkOut) AS Dates,
    SUBSTRING(callNumber, - 4) AS PubYear,
    COUNT(spl.transactions.bibNumber) AS Counts
FROM
    spl.itemToBib,
    spl.title,
    spl.itemType,
    spl.keyword,
    spl.callNumber,
    spl.transactions
WHERE
    spl.itemToBib.itemNumber = spl.itemType.itemNumber
        AND spl.itemToBib.itemNumber = spl.transactions.itemNumber
        AND spl.itemToBib.itemNumber = spl.callNumber.itemNumber
        AND spl.itemToBib.bibNumber = spl.keyword.bibNumber
        AND spl.itemToBib.bibNumber = spl.title.bibNumber
        AND spl.itemToBib.bibNumber = spl.transactions.bibNumber
        AND spl.itemType.itemNumber = spl.itemToBib.itemNumber
        AND (spl.keyword.keyword = 'Technology'
        OR spl.keyword.keyword = 'Programming'
        OR spl.keyword.keyword = 'Engineering'
    or spl.keyword.keyword = 'Code'
    or spl.keyword.keyword = 'Computer')
    and date(checkOut) >= '20060101'
     and date(checkOut) <= '20151231'
        AND CAST(SUBSTRING(callNumber, - 4) AS UNSIGNED) > 2005
        AND CAST(SUBSTRING(callNumber, - 4) AS UNSIGNED) < 2016
GROUP BY spl.itemToBib.bibNumber
I restricted my search with new books the library has acquired starting from 2006 till 2015. The callNumbers most of the time contain the year of publication and so I based the year and the date of the first check out as the time the Library acquired such book.

In terms of my visual, the white ellipses signify the start of a new year and its circumference is the time (day) of the month. The rectangles surrounding the ellipses are the item type according to color, the height or size is the amount of books of that title, and its position is the date of acquirement.

Below is the Processing Code:

Code: Select all

import peasy.*;
PeasyCam cam;

Table table;
int rowNums;

int ellipseSize = 300;

float countAxis;
float dateAxis;
color c; 
float monthAxis;

float constantHorizontalMargin = 160;
float constantVerticalMargin = 100;


PFont myFont;

ArrayList<Book> books = new ArrayList<Book>();

void setup(){
  size(1280, 720, P3D);
  cam = new PeasyCam(this, 200);
  
  table = loadTable("data2006-2015.csv", "header");
  rowNums = table.getRowCount();
  println("Rows: " + rowNums);
  
  for (int i = 0; i<rowNums; i++){
    String title = table.getString(i,0);
    String type = table.getString(i,1);
    String date = table.getString(i,3);
    int count = table.getInt(1,5);
    books.add(new Book(type, date, count, title));
  }
  
  println("Number of Books: " + books.size());
  
  println(books.get(0).title);
  println(books.get(0).date);
  println(books.get(0).type);
  println(books.get(0).count);
  println(dateAxis);
  
  myFont = createFont("Consola.ttf",5);
  smooth();
  
}

void draw(){
  background(0);
  
  for (int i=0; i<books.size(); i++){
    dateAxis = map(dateParser(books.get(i).date), 0, 3650, 0, ellipseSize/2);
    countAxis = map((books.get(i).count), 0, 6500, 0, ellipseSize/2);
    c = typeDetermine(books.get(i).type);
    
    noStroke();
    fill(c);
    pushMatrix();
    translate(150*cos(dateAxis), 150*sin(dateAxis), i);
    rotateX(PI/2);
    //rotateY(3*PI/2);
    rect(0, books.get(i).count/4, 20, books.get(i).count/4);
    popMatrix();
  }
  
 for (int i =0; i<10; i++){
   for(int j=0; j<12; j++){
  stroke(255);
  noFill();
  pushMatrix();
  translate(0, 0, i*300);
  ellipse(0, 0, 300,300);
  popMatrix();
  
  int y = 2006+i;
  
  fill(255);
  textAlign(RIGHT, CENTER);
  textSize(30);
  pushMatrix();
  translate(0,0,i*300);
  text(y, -350, 0);
  popMatrix();
  
  fill(255);
  textAlign(LEFT,CENTER);
  textSize(25);
  pushMatrix();
  translate(0, 0,j*25);
  text(months[j],0,350);
  popMatrix();
  
  
   }
 }
 
 renderTitle();
 
 }
Here are some screenshots:
screenShot1.png
screenShot2.png
screenShot3.png
Attachments
Project3D.zip
(1.02 MiB) Downloaded 135 times
Last edited by d.aleman.24.da on Tue Mar 15, 2016 7:36 am, edited 4 times in total.

Post Reply