static int WIDTH = 1020; static int HEIGHT = 750; static int MAXBARS = 11; ArrayList transactions = new ArrayList(); ArrayList headlines; ArrayList subjectEntries = new ArrayList(31); ArrayList categoryEntries = new ArrayList(31); Map categoryMap; int[] maxSubjectCount = new int[31]; int[] maxCategoryCount = new int[31]; boolean displayType = false; // Subjects - true. Categories - false. boolean displayGrid = false; boolean displayTagCloud = false; int currentDay = 2; int displayDay = 2; int bgAlpha = 0; int currentBar = 0; void setup() { size(WIDTH, HEIGHT, P2D); background(0); //frameRate(1000); //that is, as fast as possible textFont(loadFont("GillSans-24.vlw"), 16); text("Loading...", 30, 30); long before = millis(); loadTransactions("splxmldata_trimmed.txt"); loadHeadlines("Headlines_2009-01-11_04-26"); loadCategoryMap("dewey.xml"); // It gets angry without the 0th element. subjectEntries.add(new ArrayList()); categoryEntries.add(new ArrayList()); for(int i = 1; i < 31; i++) { subjectEntries.add(i, TransactionUtils.countUniqueSubjects((ArrayList)transactions.get(i))); TransactionUtils.sortUniqueEntriesByCount((ArrayList)subjectEntries.get(i), TransactionUtils.DESCENDING); maxSubjectCount[i] = TransactionUtils.getIntValueForEntry(((ArrayList)subjectEntries.get(i)).get(0)); categoryEntries.add(i, TransactionUtils.countUniqueCategories((ArrayList)transactions.get(i))); TransactionUtils.sortUniqueEntriesByCount((ArrayList)categoryEntries.get(i), TransactionUtils.DESCENDING); //maxCategoryCount[i] = TransactionUtils.getIntValueForEntry(((ArrayList)categoryEntries.get(i)).get(0)); } } void draw() { background(0); if(displayGrid) { drawGrid(); } drawHeadlines(currentDay); if(displayType) { drawSubjects(currentDay); } else if(!displayType) { drawCategories(currentDay); } if(currentDay != displayDay) { if(bgAlpha > 255) { bgAlpha = 255; displayDay = currentDay; fill(0, 0, 0, bgAlpha); rect(0, 0, WIDTH, HEIGHT); } else { fill(0, 0, 0, bgAlpha); rect(0, 0, WIDTH, HEIGHT); bgAlpha = bgAlpha + 50; } } else if(bgAlpha > 0) { fill(0, 0, 0, bgAlpha); rect(0, 0, WIDTH, HEIGHT); bgAlpha = bgAlpha - 50; } fill(128); text("Matt Hubert - MAT 259 - January 2009", 115, HEIGHT - 5); } void keyPressed() { if(key == CODED) { if(keyCode == UP) { displayType = !displayType; currentBar = 0; } else if(keyCode == DOWN) { displayType = !displayType; currentBar = 0; } else if(keyCode == RIGHT) { if(currentDay == 30) { currentDay = 1; } else { currentDay++; } } else if(keyCode == LEFT) { if(currentDay == 1) { currentDay = 30; } else { currentDay--; } } } if(key == 'g') { displayGrid = !displayGrid; } else if(key == 't') { displayTagCloud = !displayTagCloud; } else if(key == ',') { if(currentBar != 0) { currentBar--; } } else if(key == '.') { if(displayType) { if(currentBar < ((ArrayList)subjectEntries.get(currentDay)).size() - MAXBARS) { currentBar++; } } else { if(currentBar < ((ArrayList)categoryEntries.get(currentDay)).size() - MAXBARS) { currentBar++; } } } // Fixes if you change days to a day with not enough entries as your currentBar has (from a previous day). if(currentBar > ((ArrayList)subjectEntries.get(currentDay)).size() - MAXBARS) { currentBar = ((ArrayList)subjectEntries.get(currentDay)).size() - MAXBARS; } } void drawHeadlines(int currentDay) { textSize(20); textAlign(CENTER); fill(200); text("headlines and checkouts for September, 2008", WIDTH / 2, 30); textSize(20); textAlign(RIGHT); fill(200); text(displayDay + TransactionUtils.getOrdinal(displayDay) + " of September, 2008", WIDTH - 30, 30); int headlineNumber = 1; noSmooth(); fill(255); textAlign(LEFT); for(int i = 0; i < this.headlines.size(); i++) { if(((Headline)this.headlines.get(i)).date == displayDay) { if(displayTagCloud) { textSize(((Headline)this.headlines.get(i)).headlineSize); } else { textSize(16); } stroke(255, 0, 0); strokeWeight(1.2); line(30, headlineNumber * 30 + 63, 30 + ((Headline)this.headlines.get(i)).headlineSize * 10, headlineNumber * 30 + 63); strokeWeight(1); text(((Headline)this.headlines.get(i)).headline, 30, headlineNumber * 30 + 60); headlineNumber++; } } smooth(); } void drawSubjects(int currentDay) { for(int i = currentBar; i < (MAXBARS + currentBar); i++) { if(i < ((ArrayList)subjectEntries.get(displayDay)).size()) { Map.Entry entry = (Map.Entry)((ArrayList)subjectEntries.get(displayDay)).get(i); String subject = TransactionUtils.getStringKeyForEntry(entry); int value = TransactionUtils.getIntValueForEntry(entry); float logValue = (float)Math.log(value) * 30; stroke(128); fill(16); rect((i - currentBar) * 90 + 30, HEIGHT - 90 - logValue, 60, logValue); noSmooth(); fill(255); textAlign(CENTER); textSize(16); text("" + value, (i - currentBar) * 90 + 60, HEIGHT - 100 - logValue); fill(255); textAlign(CENTER); textSize(14); text(subject, (i - currentBar) * 90 + 15, HEIGHT - 80, 90, 60); smooth(); } } } void drawCategories(int currentDay) { for(int i = currentBar; i < (MAXBARS + currentBar); i++) { if(i < ((ArrayList)categoryEntries.get(displayDay)).size()) { Map.Entry entry = (Map.Entry)((ArrayList)categoryEntries.get(displayDay)).get(i); String category = TransactionUtils.getStringKeyForEntry(entry); int value = TransactionUtils.getIntValueForEntry(entry); float logValue = (float)Math.log(value) * 30; int[] colorValues = getColor(category); stroke(128); fill(colorValues[0], colorValues[1], colorValues[2], colorValues[3]); rect((i - currentBar) * 90 + 30, HEIGHT - 90 - logValue, 60, logValue); noSmooth(); fill(255); textAlign(CENTER); textSize(16); text("" + value, (i - currentBar) * 90 + 60, HEIGHT - 100 - logValue); // Convert deweyClass to text category. String categoryName = (String)categoryMap.get(category); fill(255); textAlign(CENTER); textSize(14); if(categoryName != null) { text(categoryName, (i - currentBar) * 90 + 15, HEIGHT - 80, 90, 60); } else { text("Not assigned or no longer used", (i - currentBar) * 90 + 15, HEIGHT - 80, 90, 60); } smooth(); } } } void drawGrid() { for(int i = 1; i < HEIGHT / 30; i++) { stroke(128); line(30, 30 * i, WIDTH - 30, 30 * i); } for(int i = 1; i < WIDTH / 30; i++) { stroke(128); line(30 * i, 30, 30 * i, HEIGHT - 30); } } public void loadTransactions(String fileName) { for(int i = 0; i < 31; i++) { transactions.add(new ArrayList()); } println("Loading file \"" + fileName + "\""); String[] lines = loadStrings(fileName); for (int i = 0; i < lines.length; i++) { Transaction t = parseTransaction(lines[i]); if(Integer.parseInt(t.ckodate.substring(6, 7)) == 9) // If it was checked out in September... { ((ArrayList)transactions.get(Integer.parseInt(t.ckodate.substring(8)))).add(t); } } } public void loadHeadlines(String fileName) { headlines = new ArrayList(); println("Loading headline \"" + fileName + "\""); String[] lines = loadStrings(fileName); for (int i = 0; i < lines.length; i++) { headlines.add(parseHeadline(lines[i])); } Collections.sort(headlines, new Comparator() { public int compare(Object o1, Object o2) { return ((Headline)o2).headlineSize - ((Headline)o1).headlineSize; } }); } public void loadCategoryMap(String fileName) { categoryMap = new HashMap(); String[] sections; println("Loading category map..."); String[] lines = loadStrings(fileName); for(int i = 0; i < lines.length; i++) { sections = split(lines[i], ","); categoryMap.put(sections[0], sections[1]); } } // This function returns all the files in a directory as an array of File objects // This is useful if you want more info about the file public File[] listFiles(String dir) { File file = new File(dir); if (file.isDirectory()) { File[] files = file.listFiles(); return files; } else { // If it's not a directory return null; } } //create a new transaction obejct from a comma separated line. public Transaction parseTransaction(String line) { String sections[] = split(line, ","); Transaction t = new Transaction(); //store all fields t.itemNumber = sections[0]; t.ckodate = sections[1]; t.ckidate = sections[2]; t.itemtype = sections[3]; t.title = sections[4]; t.deweyClass = sections[5]; int numSubjects = sections.length - 6; t.subjects = new String[numSubjects]; arraycopy(sections, 6, t.subjects, 0, numSubjects); return t; } public Headline parseHeadline(String line) { String sections[] = split(line, ","); Headline headline = new Headline(); int sectionsLength = sections.length; int offset = 0; // Not all headlines contain all information, so we need to find where the wordcount starts. for(int i = sectionsLength - 1; i != 0; i--) { if(sections[i].indexOf("words") != -1) { offset = i; } } headline.words = sections[offset].trim(); headline.page = sections[offset - 1].trim(); headline.date = Integer.parseInt(sections[offset - 5].substring(11)); // Return just the number of the day. String title = ""; for(int i = 0; i != offset - 6; i++) // The headline is of arbitary size with commas, so the end of it will be the size minus the rest, which is 9. { title += sections[i] + ","; } headline.headline = title.trim().substring(0, title.trim().length() - 1); // Remove the last comma. headline.calculateHeadlineSize(); return headline; } public int[] getColor(String value) { int[] colorValue = {0, 0, 0, 0}; switch(value.charAt(0)) { case '0': colorValue[0] = 255; colorValue[1] = 255; colorValue[2] = 255; break; case '1': colorValue[0] = 128; colorValue[1] = 128; colorValue[2] = 128; break; case '2': colorValue[0] = 247; colorValue[1] = 207; colorValue[2] = 10; break; case '3': colorValue[0] = 100; colorValue[1] = 55; colorValue[2] = 176; break; case '4': colorValue[0] = 69; colorValue[1] = 172; colorValue[2] = 205; break; case '5': colorValue[0] = 252; colorValue[1] = 231; colorValue[2] = 13; break; case '6': colorValue[0] = 250; colorValue[1] = 124; colorValue[2] = 7; break; case '7': colorValue[0] = 180; colorValue[1] = 35; colorValue[2] = 16; break; case '8': colorValue[0] = 1; colorValue[1] = 34; colorValue[2] = 69; break; case '9': colorValue[0] = 143; colorValue[1] = 14; colorValue[2] = 104; break; } colorValue[0] += Integer.parseInt(value.substring(1)); colorValue[1] += Integer.parseInt(value.substring(1)); colorValue[2] += Integer.parseInt(value.substring(1)); //colorValue[3] = 100 + Integer.parseInt(value.substring(1)); colorValue[3] = 255; return colorValue; }