/* Posts to the Moped Army member's forum by branch (volume + participation) Simon King (sjking@andrew.cmu.edu) Table code and initial structure from Ben Fry. GUI library: Interfascia (http://www.superstable.net/interfascia/) */ // gui library import interfascia.*; GUIController gui; IFButton[] divisionList; IFButton[] logoList; IFButton vizOption1, vizOption2; IFLookAndFeel defaultLook, transparentLook, logoButtons; FloatTable postsData, posterData; float postsDataMin, postsDataMax, posterDataMin, posterDataMax; float plotX1, plotY1, plotX2, plotY2; int currentColumn = 0; int numDivision; PFont titleFont, smallFont; int activeMonth = -5; // start off lower than the first month (0) int currentViz = 1; // allow both vizualizations to stay, but we'll default to #1 color[] branchColors = { color(240, 105, 22), // decepticons * color(148, 173, 12), // bombardment society * color(238, 51, 56), // the guns * color(16, 86, 175), // mosquito fleet * color(26, 1, 82), // the tom cruisers * color(0, 228, 231), // motion left * color(218, 1, 164), // peddy cash * color(73, 51, 3), // hell's satans * color(41, 88, 90), // kHz * color(188, 0, 0), // mission 23 * color(0, 204, 139), // 50:1 * color(28, 3, 178), // ghost riders * color(80, 134, 1), // creatures * color(0, 152, 204), // hell's bombshells * color(122, 15, 0), // puddle cutters * color(180, 129, 0), // bourbon bandits * color(5, 77, 16), // landsquids color(49, 77, 96) // switcHANDsignal * }; PImage[] branchLogos; boolean[] branchesCompared; int initialBranch1; int initialBranch2; String[] branchPostingData = { "","","","","","","","","","","","","","","","","",""}; PImage viz1, viz2; void setup() { size(800,600); postsData = new FloatTable("forum_posts.tsv"); postsDataMin = postsData.getTableMin(); postsDataMax = postsData.getTableMax(); posterData = new FloatTable("forum_posters.tsv"); posterDataMin = posterData.getTableMin(); posterDataMax = posterData.getTableMax(); titleFont = loadFont("NeoSansIntel-Light-20.vlw"); smallFont = loadFont("Verdana-9.vlw"); gui = new GUIController(this); defaultLook = new IFLookAndFeel(this, IFLookAndFeel.DEFAULT); transparentLook = new IFLookAndFeel(this, IFLookAndFeel.DEFAULT); transparentLook.baseColor = color(100, 180, 100, 0); transparentLook.highlightColor = color(180, 50); transparentLook.borderColor = color(70, 135, 70, 0); transparentLook.activeColor = color(255, 145, 26, 50); gui.setLookAndFeel(transparentLook); logoButtons = new IFLookAndFeel(this, IFLookAndFeel.DEFAULT); logoButtons.baseColor = color(255, 253, 234, 0); logoButtons.highlightColor = color(255, 164, 15, 80); logoButtons.borderColor = color(70, 135, 70, 0); logoButtons.activeColor = color(255, 217, 0, 80); // location of the plotted time series plotX1 = 40; plotX2 = 760; plotY1 = 70; plotY2 = 400; // rollover months createDivisionButtons(); // load 'em loadLogos(); // make them into button (kind of a hack) createLogoButtons(); int columnCount = postsData.getColumnCount(); // randomize the initial comparison initialBranch1 = int(random(0,4)); initialBranch2 = int(random(0,columnCount-2)); // make sure we don't get the same one twice while (initialBranch2 == initialBranch1) { initialBranch2 = int(random(0,columnCount-2)); } branchesCompared = new boolean[columnCount]; branchesCompared[initialBranch1] = true; branchesCompared[initialBranch2] = true; // change viz buttons viz1 = loadImage("viz_1.gif"); viz2 = loadImage("viz_2.gif"); vizOption1 = new IFButton ("", int(plotX1 + 140), int(plotY2 + 153), 30, 30); vizOption1.addActionListener(this); gui.add(vizOption1); vizOption1.setLookAndFeel(logoButtons); vizOption2 = new IFButton ("", int(plotX1 + 100), int(plotY2 + 153), 30, 30); vizOption2.addActionListener(this); gui.add(vizOption2); vizOption2.setLookAndFeel(logoButtons); } void draw() { background(255); fill(255); smooth(); noStroke(); // - title fill(0); textFont(titleFont); text("Posts to the Moped Army member's forum by branch (volume + participation)", plotX1, plotY1 - 40); // - side fill(180); textFont(smallFont); pushMatrix(); translate(30,250); rotate(radians(-90)); text("Number of posts", 0, 0); popMatrix(); // - side data text(int(postsDataMax), plotX1 + 5, plotY1); // - bottom text("Months (rollover + click for detail )", (plotX2/2) - 80, plotY2 + 20); // - legend textFont(smallFont); text("Posts/People", plotX1, plotY2 + 170); rect(plotX1, plotY2 + 178, 40, 5); // - vizualization changer image(viz1, plotX1 + 140, plotY2 + 153); image(viz2, plotX1 + 100, plotY2 + 153); noFill(); stroke(180); rect(plotX1 + 100, plotY2 + 153, 30, 30); rect(plotX1 + 140, plotY2 + 153, 30, 30); // plot lines noFill(); stroke(220); beginShape(); vertex(plotX1, plotY1 - 10); vertex(plotX1, plotY2); vertex(plotX2 + 3, plotY2); endShape(); // draw our initial two comparisons for (int i=0; i -1) { String monthName = postsData.getRowName(activeMonth); int buttonX = divisionList[activeMonth].getX(); int buttonY = divisionList[activeMonth].getY(); int buttonW = divisionList[activeMonth].getWidth(); int buttonH = divisionList[activeMonth].getHeight(); fill(color(255, 164, 15, 50)); rect(buttonX,buttonY,buttonW,buttonH); noFill(); textFont(smallFont); fill(#EA8705); text(monthName, buttonX - 15, buttonY - 5); } } void loadLogos() { int columnCount = postsData.getColumnCount(); branchLogos = new PImage[columnCount]; for (int col = 0; col < columnCount-1; col++) { String branchNames[] = split(postsData.getColumnName(col), "|"); String branch = branchNames[0]; String code = branchNames[1]; String filename = "branch_logo_" + code + "_sm.gif"; branchLogos[col] = loadImage(filename); } } void createLogoButtons() { // it's a hack to use this gui library, but it sure makes things easier // it doesn't have all the flexibility I want though, so: // TODO: make all buttons work without GUI library int totalBranches = branchLogos.length-1; logoList = new IFButton[totalBranches]; for (int i = 0; i < totalBranches; i++) { int x = int(plotX1 + (40 * i)); int y = int(plotY2 + 85); logoList[i] = new IFButton ("", x, y - 8, 40, 40); logoList[i].addActionListener(this); gui.add(logoList[i]); logoList[i].setLookAndFeel(logoButtons); } } void showLogos() { for (int i = 0; i < branchLogos.length-1; i++) { int imageOffset = (40 - branchLogos[i].width) / 2; int x = int(plotX1 + (40 * i)); int y = int(plotY2 + 85); image(branchLogos[i], x + imageOffset, y); noStroke(); fill(branchColors[i], 80); int rectY = (branchesCompared[i]) ? y-25 : y-13; rect(x, rectY, 40, 5); fill(branchColors[i]); textFont(smallFont); text(branchPostingData[i], x, rectY - 8); } } void createDivisionButtons() { int rowCount = postsData.getRowCount(); divisionList = new IFButton[rowCount]; for (int row = 0; row < rowCount; row++) { // draw a division float x = map(row, 0, rowCount, plotX1 - 5, plotX2 + 5); float divisionWidth = (plotX2 - plotX1) / rowCount; float divisionHeight = plotY2 - plotY1 + 10; color buttoncolor = color(random(0,255), random(0,255), random(0,255)); color highlight = color(random(0,255), random(0,255), random(0,255)); divisionList[row] = new IFButton ("", int(x), int(plotY1 - 10), int(divisionWidth), int(divisionHeight)); divisionList[row].addActionListener(this); gui.add(divisionList[row]); } } void actionPerformed (GUIEvent e) { // dividers for (int i=0; i rightEdge) rightEdge = x; // ditto for right edge curveVertex(x,y); if (row == firstValidRow) curveVertex(x,y); // extra point at the beginning and end (needed by curveVertex) } } // plot posts on the way back to show number of people in the depth of the shape for (int row = rowCount-1; row >= 0; row--) { float numPosts = postsData.get(row, col); float numPosters = posterData.get(row, col); if (posterData.valid(row, col)) { float x = map(row, 0, rowCount-1, plotX1, plotX2); float postsY = map(numPosts, postsDataMin, postsDataMax, plotY2, plotY1); // already drawn point plotting post data float posterShapeHeight = map(numPosters, posterDataMin, posterDataMax, 1, 40); // get the number of posters float y = postsY + posterShapeHeight; // computer a new data point relative to the old one curveVertex(x,y); // plot location of poster data if (row == firstValidRow) curveVertex(x,y); // extra point at the end } } //vertex(rightEdge, plotY2); //vertex(leftEdge, plotY2); endShape(CLOSE); }