Proj 4: 3D Volumetric, Spacial Visualization

nataly_moreno
Posts: 5
Joined: Sat Jan 10, 2015 11:31 am

Re: Proj 4: 3D Volumetric, Spacial Visualization

Post by nataly_moreno » Thu Feb 19, 2015 10:41 am

I am interested in looking at the books related to birds that have been checked out over time. This query is only for the ones with a dewey class, but I would also like to look into the ones that are related to pets or children's books.

Code: Select all

SELECT 
    title,
    itemtype AS 'itemtype',
    deweyClass AS 'dewey',
    MONTH(cout) AS 'month',
    DAY(cout) AS 'day',
    YEAR(cout) AS 'year'
FROM
    spl2.inraw
WHERE
    YEAR(cout) > 2004
        AND (deweyClass = 568
        OR deweyClass = 598)
ORDER BY YEAR(cout) , MONTH(cout) , DAY(cout)
I want to organize the data in different ways. The processing code I currently have is simply drawing the shape shown below, but is not reading in any data yet. I wanted to get the basic shape outline working before adding in any data. I will add the data in and other ways to organize the data.
red_swirly.png
Shape outline without data
One way in which I would like to organize the data would be to make a point cloud and put the day and time of day plotted on the xz plane in a circle, y would be the month/year. This would look sort of like an hour-glass.

Update:
I made 3 different patterns. However, the one I thought would look like an hour glass actually looks like some sort of fan, however, it makes sense: 1 line for every 24 hours.
PointSwirl.png
PointStar.png
Swirlex.png
There was tons of data without looking into other bird books, so I just looked into the books related to birds within two dewey classes.

Code: Select all

SELECT 
    title,
    itemtype AS 'itemtype',
    deweyClass AS 'dewey',
    cout,
    cin
FROM
    spl2.inraw
WHERE
    YEAR(cout) > 2005
        AND (deweyClass = 568
        OR deweyClass = 598)
ORDER BY YEAR(cout) , MONTH(cout) , DAY(cout)
Update Feb 27, 2015:
Processing Code is now attached.
Screen Shot 2015-02-27 at 11.42.35 AM.png
Screen Shot 2015-02-27 at 11.41.20 AM.png
Screen Shot 2015-02-27 at 11.40.02 AM.png
Attachments
Project_3D_Nataly.zip
(178.54 KiB) Downloaded 271 times
Last edited by nataly_moreno on Fri Feb 27, 2015 11:44 am, edited 2 times in total.

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

Re: Proj 4: 3D Volumetric, Spacial Visualization

Post by nedda.amini » Thu Feb 19, 2015 5:38 pm

For the 3D visualization, I decided to stay within the same query and idea, which was to find and visualize absence from the library database. To do this, I had to modify my query to include more data sets. Because I wanted to look at the collection of books as an entity, I decided to add popularity, or amount of checkouts to my query. I was interested in looking at specific books that are popular, or rather checkout a grate deal, and also look at their absence from the collection, to see if they are lost or taken more often.
This visualization was mainly me trying to stretch my artistic abilities within processing.

Here is my modified query

Code: Select all

SELECT 
    Floor(deweyClass/10)*10,
    x_checkOutCountItem.itemNumber,
    checkOutCount,
    (TIMESTAMPDIFF(MONTH, checkOut, checkIn))
FROM
    spl3._rawXmlDataCheckIns
        INNER JOIN
    spl3.x_checkOutCountItem ON spl3._rawXmlDataCheckIns.itemNumber = spl3.x_checkOutCountItem.itemNumber
WHERE
    (itemtype = 'acbk'
        AND (12 < TIMESTAMPDIFF(MONTH, checkOut, checkIn)
        AND 70 > TIMESTAMPDIFF(MONTH, checkOut, checkIn))
        AND deweyClass > 700
        And deweyClass < 900)
In it I still looked at Dewey, but I also included popularity and itemNumber.

For my visualization, I wanted to show the absence as gaping holes. I don't think I was very successful for my first try, but I played around with different ways to create visual queues for the viewer (particularly concentric circles). The number of circles within a initial plot point show the number of months the book as been checked out. I created a slider so that the circled could be spaced out more, to allow an easier side view. The overall size of the whole shows the popularity of the book, so larger circles are books that are checked out more. A large circle with few concentric circles within is a book thats popular but not checkout long. Small circles with many rings are books that are the converse, not as popular, but checked out for many months.


Attached is my processing code with screenshots as well.
Attachments
sketch_3D_Vis 3.zip
(8.79 KiB) Downloaded 237 times
images.zip
(2 MiB) Downloaded 255 times
Last edited by nedda.amini on Sun Mar 22, 2015 7:47 pm, edited 1 time in total.

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

Re: Proj 4: 3D Volumetric, Spacial Visualization

Post by matzewagner » Fri Feb 20, 2015 8:53 pm

The mess that is our universe

For this project, I wanted to find out whether there is a detectable difference in regards to the usage of time and space in item titles. I enquired about the number of checkouts per day that include either temporal verbiage, spatial verbiage or both (trans). The query is by no means exhaustive, but covers some of the most common words and roots.

SQL QUERY:

Code: Select all

SELECT 
    DAY(cout),
    MONTH(cout),
    YEAR(cout),
    SUM(CASE
        WHEN
            ((title LIKE '%chron%'
                OR title LIKE '%temp%'
                OR title LIKE '%time%'
                OR title LIKE '%pre%'
                OR title LIKE '%post%'
                OR title LIKE '%before%'
                OR title LIKE '%after%'
                OR title LIKE '%ever%'
                OR title LIKE '%eter%'
                OR title LIKE '%ago%'
))
        THEN
            1
        ELSE 0
    END) AS time,
    SUM(CASE
        WHEN
            ((title LIKE '%trans%'
		OR title LIKE '%space%'
                OR title LIKE '%aero%'
                OR title LIKE '%astro%'
                OR title LIKE '%aster%'
                OR title LIKE '%gon%'
                OR title LIKE '%spat%'
                OR title LIKE '%left%'
                OR title LIKE '%right%'
                OR title LIKE '%above%'
                OR title LIKE '%under%'
                OR title LIKE '%behind%'
                OR title LIKE '%front%'
))
        THEN
            1
        ELSE 0
    END) AS space,
    SUM(CASE
        WHEN
            ((title LIKE '%trans%'
                OR title LIKE '%aero%'
                OR title LIKE '%astro%'
                OR title LIKE '%aster%'
                OR title LIKE '%gon%'
                OR title LIKE '%space%'
                OR title LIKE '%spat%'
                OR title LIKE '%left%'
                OR title LIKE '%right%'
                OR title LIKE '%above%'
                OR title LIKE '%under%'
                OR title LIKE '%behind%'
                OR title LIKE '%front%'
)
                AND (title LIKE '%chron%'
                OR title LIKE '%temp%'
                OR title LIKE '%time%'
                OR title LIKE '%pre%'
                OR title LIKE '%post%'
                OR title LIKE '%before%'
                OR title LIKE '%after%'
                OR title LIKE '%ever%'
                OR title LIKE '%eter%'
                OR title LIKE '%ago%'
))
        THEN
            1
        ELSE 0
    END) AS trans
FROM
    spl2.inraw
WHERE
    DATE(cout) > '2005-12-31'
        AND DATE(cout) <= '2013-12-31'
GROUP BY DAY(cout) , MONTH(cout) , YEAR(cout)
ORDER BY YEAR(cout) , MONTH(cout) , DAY(cout)
For the visualization, I chose a spiral graph in which each revolution captures one year in the period from 2006 to 2013. Each cell represents the number of checkouts for that particular day in one of the three categories. The further the cells are away from the center, the higher the number of checkouts.

Two observations become readily apparent: Spatial language seems to be much less common in comparison to temporal language. Titles that include both domains are significantly rarer, still. Second, the shape of the graph also clearly indicates that the overall number of checkouts is largest towards the middle of the time period, and tapers off towards both ends.

IMAGES
1.png
2.png
3.png
4.png
5.png
PROCESSING SKETCH
matthias_project_4.zip
(62.82 KiB) Downloaded 238 times
Last edited by matzewagner on Tue Mar 24, 2015 1:51 pm, edited 3 times in total.

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

Re: Proj 4: 3D Volumetric, Spacial Visualization

Post by boyan » Mon Feb 23, 2015 1:13 am

Mapping Your Book Publishers

As a student in the geography department, I'm more interested in the geo aspect of the dataset. Unfortunately, there aren't any geo information in the spl database. The only one that is geo related is the publishers of the books. So my project is to geolocate the publishers of the books in Seattle Public Library, and visualize them on a 3D globe.

In order to map the publishers on the globe, I have to find the coordinates of the publishers first. This process is called "geocoding". I used google geocoding api to do this and due to the limits on the api, I can only geocode 2500 publishers in every 24 hours, so it takes me some time to process all the data I need. The geocoding api also tells me the country code for each coordinate pair, so I downloaded a csv file that tells me the corresponding continent for each country code, I use this information to categorize all those coordinates into different continents and color coded them.

The publishers are mapped on the globe as points, the color of the points corresponds to the continent. The visualization is interactive, you can change the point size, change the color scheme, turn on/off the globe grid and choose between different years.

This visualization clearly shows that North America is among the most active areas for book publishers, especially the United States, and you can even see the outline of the United States in this point cloud visualization. Then there are other point clusters in Europe and Asia.
Attachments
MAT259_PROJ4_BYAN.zip
(50.58 KiB) Downloaded 293 times
Screen Shot 2015-02-23 at 1.02.17 AM.png
Screen Shot 2015-02-23 at 1.01.32 AM.png
Screen Shot 2015-02-23 at 1.00.57 AM.png

rodgerljl
Posts: 5
Joined: Sat Jan 10, 2015 11:29 am

Re: Proj 4: 3D Volumetric, Spacial Visualization

Post by rodgerljl » Mon Feb 23, 2015 4:58 pm

Countries

This data visualization examines the popularities and classifications of the books, which the title includes one the following countries: America, China, Germany, India, Korea, and Mexico. Each book is projected on a virtual plane in circular shape, where the radius indicates the copies of the book. The two axises of the virtual plane represents dewey category and checkout counts of the books. All the books are applied with six different colors for six different countries. And the books from the same countries are connected by the same color of arcs in the z axis. On the other direction of z axis, each book connects with its title and the length of the line represents the copies of the book as well.

The 2nd edition will implement filtering function that audience can explore the data with different combinations of countries and dewey categories.
1.jpeg
2.jpeg
3.jpeg
4.jpeg

Code: Select all

SELECT 
    keyword,
    title,
    itemCount AS Copies,
    checkOutCount,
    deweyClass
FROM
    spl3.x_keyword,
    spl3.title,
    spl3.x_oneBibManyItem,
    spl3.deweyClass,
    spl3.x_checkOutCountBib
WHERE
    (keyword = 'china' OR keyword = 'korea'
        OR keyword = 'america'
        OR keyword = 'mexico'
        OR keyword = 'germany'
        OR keyword = 'india')
        AND x_keyword.bibNumber = title.bibNumber
        AND x_keyword.bibNumber = x_oneBibManyItem.bibNumber
        AND x_keyword.bibNumber = deweyClass.bibNumber
        AND x_keyword.bibNumber = x_checkOutCountBib.bibNumber
        AND deweyClass > 0
        AND checkOutCount > 100
Countries.zip
(1.96 MiB) Downloaded 276 times

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

Re: Proj 4: 3D Volumetric, Spacial Visualization

Post by dimberman » Tue Feb 24, 2015 10:15 am

For my project, I wanted to create an image similar to a heart monitor. Each line is a deweyclass, as it checks through each day of the year. I created a tail to give a better visualization of how the values are changing over time.

To create the tail I needed to create a rolling buffer in processing that would allow the program to save the previous 300 values of each moving tail of deweyClass.

To improve this project, I plan to create options that will allow users to limit the range of classes they are looking at, as well as choose between normalized and non normalized values

Code: Select all

	SELECT  outday.d as d, floor(outday.class), sum(sumCounter)
			FROM
			(
					SELECT dayofyear(cout) as d, floor(deweyClass) as class, 1 as sumCounter
					FROM spl2.inraw
					WHERE year(cout)!=1970 
			) as outday
	group by outday.class, outday.d
Attachments
heartbeat_sketch.zip
(756.85 KiB) Downloaded 215 times

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

Empirical hours of a library across adjustable dimensions

Post by menzer » Mon Mar 02, 2015 6:43 pm

Empirical hours of a library across adjustable dimensions

For the 3D interactive project I had two main objectives:

1.) 2D ==> 3D
Translate my 2D visualization of awake times to 3D space by incorporating another layer of data. I selected the Dewey classes and itemtypes for this third dimension, none of which I had used for previous visualizations. This required me to run queries on the SPL2 database on a subset marked by individual dewey classes and itemtypes, and subsequently defining the “awake time” in each of these classes. As in my previous work, the awake time is defined as the difference (in minutes) between the first check out of a day and a last checkout of a day.

2.) Interactivity
Make an interactive visualization that lets the user adjust the position and perspective of the visualization using ControlP5 modules, but also has an option to highlight specific layers/dimensions of the data. For the former, I used standard ControlP5 slider objects (upper left corner of the screen) as used widely in class demos. For the selection/highlighting of specific data dimensions, I used a ControlP5 listbox item (upper right corner of the screen). I extended the ControlP5 listbox item class so it can show the currently selected item in a different color than the rest of the list (“active color”).

Additional features:
- awake times can be highlighted on top of boxes by via toggle button
- transparency of inactive layers can be controlled via slider
- panning can be done via three sliders in the x, y and z directions (lower left corner of the screen). This greatly simplifies panning through the three dimensional data matrix in interactive mode, especially when looking at the matrix from wide range of angles or zoom levels covering coarse and more granular scales in one and the same application.
- perspective and distances between layers can also be altered in all three spacial dimensions (lower right corner of the screen). This feature was implemented by modifying the p parameter in p*(a,b,c)*d, where a, b and c are the three dimensional lengths of the individual building blocks and d is the number of the layer.

Other applications of this code include multi-year data sets and the animated visualization of data collected at a high temporal sampling rate.
initialView.png
Fig.1: Initial view of the 3D data cube.
dataLayersUnfold.png
Fig.2: Data Layers can be unfolded in all directions of 3D space.
layesUnfoldAndSelect3.png
Fig.3: Data Layers can be highlighted as needed.
LayersUnfoldInvestigated.png
Fig.4: Each data layer can be more closely investigated, but still in the context of dimensions in its vicinity.
DeepDataExploration.png
Fig.5.1: The Interactive Tool allows for data exploration at both coarse (5.1) scales and fine (5.2) scales.
fineScale.png
Fig.5.2: The Interactive Tool allows for data exploration at both coarse (5.1) scales and fine (5.2) scales.
zipper.png
Fig.5.3

Code: Select all

// importing peasycam into processing, peasycam is used for manipualting the camera positions
import peasy.test.*;
import peasy.org.apache.commons.math.*;
import peasy.*;
import peasy.org.apache.commons.math.geometry.*;


// setting up PeasyCam
PeasyCam cam;

// including  ControlP5

import controlP5.*;
ControlP5 controlP5;
ControlP5 controlP5List;
ListBox l;

PMatrix3D currCameraMatrix;
PGraphics3D g3; 

// setting up fonts for text
PFont  myHelvetica10 = createFont("Helvetica",10, true);
PFont  myHelvetica12 = createFont("Helvetica",12, true);
PFont  myHelvetica16 = createFont("Helvetica",16, true);
PFont  myHelvetica20 = createFont("Helvetica",20, true);
PFont  myHelvetica24 = createFont("Helvetica",24, true);

color colForeground = 0xffaa0000;
color colBackground = 0xff660000;
color colActive = 0xffff0000;

//to store the data table
float [][][] dataMatrix = null;

int numWeekdays = 7;
int numWeeks = 52;
int numDewey = 10;

String[] weekdayNames = {
  "Sunday", 
  "Monday", 
  "Tuesday", 
  "Wednesday", 
  "Thursday", 
  "Friday", 
  "Saturday"
};

String[] deweyNames = {
  "1-100", 
  "100-200", 
  "200-300", 
  "300-400", 
  "400-500", 
  "500-600",
  "600-700", 
  "700-800", 
  "800-900", 
  "900-1000"   
};

float factDepth;
float morningShift;

int [][][] dataAwake = null;
int [][][] dataEarliestCout = null;
int [][][] dataLatestCout = null;
int maxAwake; //store max value
int numRowsGlobal = 3300;
int numRows;
int numCols = 8; //# of rows and columns of original data file

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

//  text formatting variables 
float constantMarginOnRows = 160;
float constantMarginOnColumns = 100;
Table myTable; 

float blockWidth = 40;
float blockHeight = 60;   // initial 80
float blockDepth = 35;

int p5Margin = 30;
int p5Distance = 22;

int buttonWidth = 150;
int buttonHeight = 20;

boolean textFlag= false;
boolean numberFlag = false;
boolean lineFlag = false; 

//int minimumNumber = 1;

// init values for interactivity PARAMS:
int transparency = 64;
int alpha;

float pHeight = 0;
float pWidth = 0;
float pDepth = 1;

float xPos = -5;
float yPos = 10;
float zPos = -36;

int deweySelect = 1; 


void drawGUI() 
      {
        currCameraMatrix = new PMatrix3D(g3.camera);
        camera();
        controlP5.draw();
        g3.camera = currCameraMatrix;
      }


void setupGUI()
      {        
              controlP5= new ControlP5(this);
              
                controlP5.setColorForeground(colForeground);
                controlP5.setColorBackground(colBackground);
                controlP5.setColorLabel(0xffdddddd);
                controlP5.setColorValue(color(220));//(0xffff88ff);
                 controlP5.setColorActive(colActive);
              controlP5.setFont(myHelvetica12);
              controlP5.setColorLabel(color(255,128));
              //controlP5.setBackground(color(40));
              //controlP5.setColorBackground(s2DbuttonBackCol);
              //controlP5.setColorForeground(s2DbuttonForeCol);
              controlP5.setColorCaptionLabel(color(220));
             Tab theParent;
              Toggle t1 = controlP5.addToggle("Labels",false,  p5Margin, p5Margin + 2 * p5Distance , buttonWidth , buttonHeight) ;  
              t1.setLabel("Labels");
        controlP5.Label lt1 = t1.captionLabel();
lt1.style().marginTop = -23; //move upwards (relative to button size)
lt1.style().marginLeft = 2; //move to the right
              //controlP5.addToggle("Text Flag",  p5Margin, p5Margin + 2 * p5Distance , buttonWidth , buttonHeight) ;             
             // controlP5.addToggle("Number Flag",p5Margin, p5Margin + 3 * p5Distance , buttonWidth , buttonHeight) ;           
              Toggle t = controlP5.addToggle("Awake Times",false, p5Margin, p5Margin + 3 * p5Distance , buttonWidth , buttonHeight) ;
                   t.setLabel("Awake Times");
        controlP5.Label lt = t.captionLabel();
lt.style().marginTop = -23; //move upwards (relative to button size)
lt.style().marginLeft = 2; //move to the right           
              //controlP5.addToggle("Line Flag",p5Margin, p5Margin + 4 * p5Distance , buttonWidth , buttonHeight) ;                                    
              Slider sAlpha = controlP5.addSlider("alpha", (int)255*0.2  ,(int)255*0.8 ,transparency ,p5Margin, p5Margin + 4 * p5Distance , buttonWidth , buttonHeight) ;
              
              controlP5.Label sAlphaLabel = sAlpha.captionLabel();
              sAlphaLabel.style().marginLeft = -45; //move horizontally 
              
              //block distance and layer perspective sliders
               // add blank button for heading
                controlP5.addButton("Layer distance & perspective")
                .setPosition(p5Margin+1200-30, p5Margin + 680)
                .setSize(0 , buttonHeight)
                .setColorBackground(color(255))
                .setColorForeground(color(255))
                .setColorCaptionLabel(color(1));
              
              Slider sPerspX = controlP5.addSlider("pHeight" ,-25 ,25,p5Margin+1200, p5Margin + 680+ p5Distance , buttonWidth , buttonHeight) ;
              Slider sPerspY = controlP5.addSlider("pWidth" ,-25 ,25 ,p5Margin+1200, p5Margin + 680+ 2*p5Distance , buttonWidth , buttonHeight) ;
              Slider sPerspZ = controlP5.addSlider("pDepth" ,1 ,25 ,p5Margin+1200, p5Margin + 680+ 3*p5Distance , buttonWidth , buttonHeight) ;
              
              controlP5.Label sPerspLabelX = sPerspX.captionLabel();
              controlP5.Label sPerspLabelY = sPerspY.captionLabel();
              controlP5.Label sPerspLabelZ = sPerspZ.captionLabel();
              sPerspLabelX.style().marginLeft = -61; //move horizontally 
              sPerspLabelY.style().marginLeft = -61; //move horizontally 
              sPerspLabelZ.style().marginLeft = -61; //move horizontally                
              
              //three dimensional panning sliders
               // add blank button for heading
                controlP5.addButton("3D Panning")
                .setPosition(p5Margin+30, p5Margin + 680)
                .setSize(0 , buttonHeight)
                .setColorBackground(color(255))
                .setColorForeground(color(255))
                .setColorCaptionLabel(color(1));
              Slider sPanning = controlP5.addSlider("xPos" ,-100 ,100,p5Margin, p5Margin + 680+ p5Distance , buttonWidth , buttonHeight) ;
              //sPanning.setLabel("xPos");
        controlP5.Label sPanningLabel = sPanning.captionLabel();
//sPanningLabel.style().marginTop = 1; //move upwards (relative to button size)
sPanningLabel.style().marginLeft = -42; //move horizontally   

              Slider sPanningY = controlP5.addSlider("yPos" ,-50 ,50 ,p5Margin, p5Margin + 680+ 2*p5Distance , buttonWidth , buttonHeight) ;
              Slider sPanningZ = controlP5.addSlider("zPos" ,-150 ,50 ,p5Margin, p5Margin + 680+ 3*p5Distance , buttonWidth , buttonHeight) ;
              //controlP5.addButton("Number Flag",1.0 , p5Margin, p5Margin + 3 * p5Distance , buttonWidth , buttonHeight) ; 
              
              controlP5.Label sPanningLabelY = sPanningY.captionLabel();
              controlP5.Label sPanningLabelZ = sPanningZ.captionLabel();
              sPanningLabelY.style().marginLeft = -42; //move horizontally 
              sPanningLabelZ.style().marginLeft = -42; //move horizontally   
              
              //controlP5List.setColorLabel(color(1,128));
              //controlP5List.setColorCaptionLabel(color(1));
              //ListBox l;
              l = controlP5.addListBox("myList")
                 .setPosition(p5Margin+1200, p5Margin + 3 * p5Distance)
                 .setSize(buttonWidth,buttonWidth)
                 .setItemHeight(14)
                 .setBarHeight(buttonHeight)
                 .setColorActive(colActive)
                 .setColorForeground(colForeground)
                 .setColorBackground(colBackground)
                 ;

                  l.captionLabel().toUpperCase(true);
                  l.captionLabel().set("Select Dewey Class");
                  //l.captionLabel().setColor(0xffff0000);
                  l.captionLabel().style().marginTop = 3;
                  l.valueLabel().style().marginTop = 3;
  
                  for (int i=0;i<numDewey;i++) {
                    ListBoxItem lbi = l.addItem(deweyNames[i], i);
                    //lbi.setColorBackground(0xffff0000);
                    //l.setValue(i);
                    if (i==deweySelect){lbi.setColorBackground(colActive);}
                  }
              
              
              controlP5.setAutoDraw(false);
        }  


void controlEvent(ControlEvent theEvent) 
                {
  
                 
                if(theEvent.isController()) 
                  {
              
                  if(theEvent.controller().name()=="Labels") {
                                                                          if(theEvent.controller().value()==1)
                                                                             {
                                                                               textFlag = true;
                                                                             }
                                                                           else
                                                                             {
                                                                               textFlag = false;                                                                       
                                                                             }                                                                               
                                                                       
                                                                    }
                                                                   
                                                                          
                   if(theEvent.controller().name()=="Awake Times") {
                                                                           if(theEvent.controller().value()==1)
                                                                             {
                                                                               numberFlag = true;
                                                                             }
                                                                           else
                                                                             {
                                                                               numberFlag = false;                                                                       
                                                                             }                                                                             
                                                                          }     
                  
      
                    
                   if(theEvent.controller().name()=="alpha") {
                                                                    transparency = int ( theEvent.controller().value() ) ;
                                                                    }     
               
                   if(theEvent.controller().name()=="pHeight") {
                                                                    pHeight = int ( -theEvent.controller().value() ) ;
                                                                    }     
               
                    if(theEvent.controller().name()=="pWidth") {
                                                                    pWidth = int ( theEvent.controller().value() ) ;
                                                                    }     
                    
                    if(theEvent.controller().name()=="pDepth") {
                                                                    pDepth = int ( theEvent.controller().value() ) ;
                                                                    }  
                    if(theEvent.controller().name()=="xPos") {
                                                                    xPos = int ( theEvent.controller().value() ) ;
                                                                    }     
               
                    if(theEvent.controller().name()=="yPos") {
                                                                    yPos = int ( theEvent.controller().value() ) ;
                                                                    }     
                    
                    if(theEvent.controller().name()=="zPos") {
                                                                    zPos = int ( theEvent.controller().value() ) ;
                                                                    }  
                                                                 
                   //if(theEvent.controller().name()=="myList") {
                   //                                                 deweySelect = int ( theEvent.controller().value() ) ;
                   //                                                 }   
    /*                                          
                    if(theEvent.controller().name()=="View 1") {
                                                                 
                                                                 cam.lookAt(0,0,0,2800,3000);
                                                                  }        
                    */
                                                                                
                  
                  print("control event from : "+theEvent.controller().name());
                  println(", value : "+theEvent.controller().value());
                  
                    }
    
    if (theEvent.isGroup()) {
    // an event from a group e.g. scrollList
    println(theEvent.group().value()+" from "+theEvent.group());
  }
  
  //   if(theEvent.isGroup() && theEvent.name().equals("myList")){
//    deweySelect = int ( theEvent.value() );
//    println("deweyClass: "+deweySelect);
//  } 
   
   //code block to highlight selected item in dewey scroll list                                       
   if(theEvent.name().equals("myList")){
    int currentIndex = (int)theEvent.group().value();
    println("oldDewey select:  "+deweySelect);
    if(deweySelect >= 0){//if something was previously selected
      l.getItem(deweySelect).setColorBackground(colBackground);
      //ListBoxItem previousItem = l.getItem(deweySelect);//get the item
      //println(previousItem.getColorBackground());
      //previousItem.setColorBackground(colBackground);//and restore the original bg colours
    }
    deweySelect = currentIndex;//update the selected index
    println("new Dewey select:  "+deweySelect);
    l.getItem(deweySelect).setColorBackground(colActive);//and set the bg colour to be the active/'selected one'...until a new selection is made and resets this, like above
   }               
             
}

void draw()
{
  // refresh the canvas everyframe
  background(255);
  //modifying the cell size according to window size

  translate( -width/2, -height/2);   // Peasycam intially sets lookAt() at (0,0,0) hence we need to transalte the axis

  if (controlP5.window(this).isMouseOver()) 
  {
    cam.setActive(false);
  } else 
  {
    cam.setActive(true);
  }

  // create base lines  
  //fill(255, 192);

  // creating grid lines in 3D

  //  if ( lineFlag)
  //  {
  //    stroke(64, 128);
  //    for ( int i =0; i <= blockWidth * (numWeekdays); i+= blockWidth)
  //    {
  //      pushMatrix();                                                  //setting up a matrix to keep the current graphi coordinates
  //      translate(constantMarginOnRows, constantMarginOnColumns);      //translate to the correct position
  //      line( i, 0, 0, i, blockHeight * (numWeeks-1), 0);              //creating a line (x,y,z)
  //      popMatrix();                                                   // going back to previos projection matrix
  //    }           
  //    for ( int i = 0; i < blockHeight* numWeeks; i+= blockHeight)
  //    {
  //      pushMatrix();
  //      translate(constantMarginOnRows, constantMarginOnColumns); 
  //      line ( 0, i, 0, blockWidth* numWeekdays, i, 0);
  //      popMatrix();
  //    }
  //  }
  //

  //displaying the cells                        
  //for ( int d = numDewey-1; d>=0; d--) {
  for ( int d = 0; d<numDewey; d++) {
    if (d == deweySelect) {//case layer is selected
      alpha = 255;
    } else { //standard setting common for all other layers
      alpha = transparency;
    }
    for ( int  i = 0; i<  numWeeks; i++) //numWeeks
    {
      for ( int  j = 0; j < numWeekdays; j++)           // -1 as the last column is empty, our dataMatrix is smaller than the table by one column
      {

        if ( dataAwake[i][j][1]!=0)
        {
          noStroke();
          colorMode(HSB);

          //draw inner box  
          pushMatrix();                                                          // doing the same for all the boxes, sadly that is the only way to do this
          fill(1, 192, 224* dataAwake[i][j][d]/maxAwake, alpha);//, 224* dataAwake[i][j]/maxAwake );

          translate(constantMarginOnRows, constantMarginOnColumns);              // translating coordiantes

            factDepth = (float)(dataLatestCout[i][j][d]-dataEarliestCout[i][j][d])/24;//hours dependent scaling factor for depth

          morningShift = (float)(((dataLatestCout[i][j][d]+dataEarliestCout[i][j][d])/2)-12)/24 * blockHeight;

          //int zTranslation = (dataAwake[1][1]*255/ maxAwake);//(dataAwake[i][j]*255/ maxAwake)* 3;
          //translate( blockWidth/2  , blockHeight/2   , i*numWeekdays*blockHeight + j*blockHeight + morningShift);
          translate( i* blockWidth + blockWidth/2 - xPos*blockWidth  + d*pWidth*blockWidth, j* blockHeight + blockHeight/2 + morningShift + yPos* blockHeight + d*pHeight*blockHeight, 1 + zPos*blockDepth - d*pDepth*blockDepth);     // translating coordiantes to box position     
          //data cube only:
          //translate( i* blockWidth + blockWidth/2 - xPos*blockWidth , j* blockHeight + blockHeight/2 + morningShift + yPos* blockHeight, 1 + zPos*blockDepth - d*blockDepth);     // translating coordiantes to box position     

          // note the movement in x position, it is half of the box's x length, this is because the box is drawn at the center
          //box( blockWidth, blockHeight, (dataMatrix[i][j])* 3  );                                    // creating a cube of appropriate size 
          box( blockWidth, blockHeight*factDepth, blockDepth);   

          // d*pDepth*blockDepth
          // ==> d*pDepth*blockDepth

            // floating boxes instad of bar graphs

          // drawing text over the boxes
          if ( numberFlag)
          {
            // box values
            translate( 0, 0, blockDepth/2 + 2 );     // translating coordinates to box position                      
            textFont(myHelvetica16);
            textAlign(CENTER, CENTER);
            fill(0);       
            text( dataAwake[i][j][d], 0, 0  );
          }

          popMatrix();

          //draw outer glass box  
          pushMatrix(); 
          stroke(120);
          strokeWeight(1);
          //colorMode(RGB); 
          fill(1, 1, 224, 0);//, 224* dataAwake[i][j]/maxAwake );
          translate(constantMarginOnRows, constantMarginOnColumns);
          translate( i* blockWidth + blockWidth/2 - xPos*blockWidth  + d*pWidth*blockWidth, j* blockHeight + blockHeight/2 + yPos* blockHeight + d*pHeight*blockHeight, 1 + zPos*blockDepth - d*pDepth*blockDepth);     // translating coordiantes to box position     
          //translate( i* blockWidth + blockWidth/2 - xPos*blockWidth  , j* blockHeight + blockHeight/2 + yPos* blockHeight, 1 + zPos*blockDepth - d*blockDepth);     // translating coordiantes to box position     
          box( blockWidth, blockHeight, blockDepth);   

          if (textFlag) {
            if (d == 0 || d == numDewey-1) { //label only first and last dimension...
              if (i==0) {//case first week of the year ==> write labels on left side of matrix
                translate( -1*blockWidth, 0, blockDepth/2 + 2 );     // translating coordinates to box position                      
                textFont(myHelvetica20);
                textAlign(RIGHT, CENTER);
                fill(66); 
                text(weekdayNames[j], 0, 0 );
                if (j == numWeekdays-1) { //case January
                  translate( blockWidth, blockHeight, blockDepth/2 + 2 );     // translating coordinates to box position                         
                  textFont(myHelvetica20);
                  textAlign(CENTER, CENTER);
                  fill(66); 
                  text("January", 0, 0 );
                }
              } else if (i == 22 & j == 0 & d!=0) { // case title
                translate(0, -2*blockHeight, blockDepth/2 + 2 );
                textFont(myHelvetica24);
                textAlign(CENTER, CENTER);
                fill(66);
                text( "Awake: Empirical hours of a library - across multiple, adjustable dimensions (darker colors refer to longer awake times)", constantMarginOnRows, constantMarginOnColumns/2 );
              } else if ((i ==numWeeks-1) & (j == numWeekdays-1)) { // case December
                translate( 0, blockHeight, blockDepth/2 + 2 );     // translating coordinates to box position                      
                textFont(myHelvetica20);
                textAlign(CENTER, CENTER);
                fill(66); 
                text("December", 0, 0 );
              }
            }
          }
          popMatrix();
        }
      }
    }
  }

  drawGUI();
}      // end of draw

void setup()
{
  
  size(1440,900,OPENGL);                      // setting up the size of window
  
  if (frame != null) {
    frame.setResizable(true);          // resizable window
  }
  
  //setting up the camera
  cam= new PeasyCam( this,0,0,0,1000);       
  cam.setMinimumDistance(-5000);        // how near the camera can get 0,0,0
  cam.setMaximumDistance(8000);       // how far the camera can travel

  //control P5 stuff      
  controlP5 = new ControlP5(this); 
  g3 = (PGraphics3D)g;     
  setupGUI();        
        
  background(240);                     //set background to white
  //noLoop();                            //to run draw() only once

  // initialize the 3D array with number of rows and columns
  dataMatrix = new float[numRowsGlobal][numCols][numDewey];
  
for ( int d = 0; d<numDewey; d++){
  myTable = new Table();                 //allocating memory to new table 
  //load the awake data set
  String filename =  "awake_dewey_" + deweyNames[d] + ".csv";
  myTable = loadTable(filename, "header");
  
  //header for col names  as follows:
  //barcode  deweyClass  weekday_num  week_num  awake  earliest_cout_hour  latest_cout_hour

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


  // copy everything from table into a 2D array

  maxAwake = 0; //find max awake value [minutes] for scaling of colorbar

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

      
   println ( "maximum value is:"+ maxAwake);
   println ( "rowCount: "+ numRows);
   println ( "columnCount: "+ numCols);

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

  dataEarliestCout = getWeekWeekday(dataMatrix, 5); // 4 is colIndex for earliest cout hour
  dataLatestCout = getWeekWeekday(dataMatrix, 6); // 4 is colIndex for earliest cout hour
}
     
   // Mapping function to convert SQL output to week-weekday matrix that is easier to plot
// This look up table could be generated much more efficiently, but given the size of the dataset it works OK.
int[][][] getWeekWeekday(float[][][]data, int colIndex) {
  int[][][] dataWeekWeekday = new int[numWeeks][numWeekdays][numDewey];
  for (int d=1; d<=numDewey; d++) {
  for (int w=1; w<=numWeeks; w++) {
    for (int wd=1; wd<=numWeekdays; wd++) {   
      dataWeekWeekday[w-1][wd-1][d-1] = 0;//zero initializer
      for (int i=0; i<data.length; i++) {//go through values in data file and sort into week weekday matrix
        if (((int)data[i][3][d-1] == w) && ((int)data[i][2][d-1] == wd)) {
          if ((int)data[i][colIndex][d-1] > dataWeekWeekday[w-1][wd-1][d-1]) {
            dataWeekWeekday[w-1][wd-1][d-1] = (int)data[i][colIndex][d-1];
          }
        }
      }
      print( dataWeekWeekday[w-1][wd-1][d-1] + " ");
    }
    println();      // switch to next line in the prompt, improves legibility
  }
  }
  return dataWeekWeekday;
}

// Interpolation function for missing values in data matrix
int[][][] interpMissing(int[][][]data) {
    for (int d=1; d<=numDewey; d++) {
  for (int w=1; w<=numWeeks; w++) {
    for (int wd=1; wd<=numWeekdays; wd++) {   
      if (data[w-1][wd-1][d-1] == 0) {
        println("zero value detected, interpolate with data for the same day from rest of the year");
        int wdaySum = 0;
        for (int w1=1; w1<=numWeeks; w1++) {
          wdaySum += data[w1-1][wd-1][d-1];
        }
        data[w-1][wd-1][d-1] = wdaySum/numWeeks;
      }
      print( data[w-1][wd-1][d-1] + " ");
    }
    println();      // switch to next line in the prompt, improves legibility
  }
    }
  return data;
}  
Attachments
AwakeTimes-3D_Interactive.zip
Data, Code and some snapshots
(1.77 MiB) Downloaded 196 times

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

Re: Proj 4: 3D Volumetric, Spacial Visualization

Post by chicobrando » Wed Mar 18, 2015 8:03 pm

In this assignment I used the same data for the 2D matrix - gothic books checked out in the Seattle Public Library from January 2006 to December 2013. I question if gothic books are more read during rainy months.

The project is based in the 3D demonstration. As the number of rows is larger than the example, I adapted the size of the boxes to get a better visualization.

Among the features, I used Control P5 to create buttons showing and hiding the text and grid. I also build a scale to indicate the average days of rain during the month and to mark the beginning of the periods of Drought and Rain.

To resemble a cloud with raindrops, I opted to paint the background with gray and used blue in the boxes to indicate the highest values of the matrix. I also tried to use spheres as a way to make the data look like raindrops, but at the end the boxes were better for the visualization.
Attachments
rain7.png
rain6.png
rain5.png
rain4.png
rain3.png
rain2.png
rain.png
Gothicrain.zip
(1.42 MiB) Downloaded 182 times

Post Reply