FloatTable data; float dataMin, dataMax; float plotX1, plotY1; float plotX2, plotY2; float labelX, labelY; int rowCount; int columnCount; int currentColumn = 0; int distanc = 15; int yearMin, yearMax; int[] years; int yearInterval = 1; int volumeInterval = 10; int volumeIntervalMinor = 2000000; // Add this above setup() //para deuda por habitante //int volumeIntervalMinor = 100; // Add this above setup() Integrator[] interpolators; PFont plotFont; void setup() { size(846, 450); //data = new FloatTable("milk-tea-coffee.tsv"); data = new FloatTable("deuda-ciudades.tsv"); //data = new FloatTable("deuda-por-persona.tsv"); rowCount = data.getRowCount(); columnCount = data.getColumnCount(); years = int(data.getRowNames()); yearMin = years[0]; yearMax = years[years.length - 1]; //println(data.getTableMin()); dataMin = 0; //data.getTableMin(); //dataMax = data.getTableMax(); dataMax = ceil(data.getTableMax() / volumeInterval) * volumeInterval; //println(dataMax); interpolators = new Integrator[rowCount]; for (int row = 0; row < rowCount; row++) { float initialValue = data.getFloat(row, 0); interpolators[row] = new Integrator(initialValue); interpolators[row].attraction = 0.1; // Set lower than the default } // Corners of the plotted time series plotX1 = 120; plotX2 = width - 160; labelX = 50; plotY1 = 90; plotY2 = height - 80; labelY = height - 25; plotFont = createFont("SansSerif", 20); textFont(plotFont); smooth(); } void draw() { background(250); // Show the plot area as a white box fill(255); rectMode(CORNERS); noStroke(); rect(plotX1, plotY1, plotX2, plotY2); drawAxisLabels(); drawCommentsVert(39,"Septiembre 2004\nComienzo de obras\nsoterramiento M30"); drawCommentsVertD(34,"Mayo 2003\nEleccciones municipales\nen Madrid"); drawYearLabels(); drawTitleTabs(); drawVolumeLabels(); //escribir comentarios en el margen derecho //drawComments(0,"\nDeuda actual suma\ncapitales de provincia"); drawComments(0,"\nSuma de deuda\nAytos. de más de \n500.000 habitantes"); drawComments(1,"\nDeuda actual \nMadrid"); drawComments(2,"\nDeuda actual \nBarcelona"); drawComments(3,"\nAcreedores largo\nplazo M30 Madrid"); drawComments(4,"\nSuma deuda Aytos. >500.000\nsin contar con Madrid"); //se remarca la línea de Madrid stroke(150); fill(0,44); drawDataLine(1); //se dibujan el área de a pestaña activa noStroke(); fill(#62CCFF,160); drawDataArea(currentColumn); //se dibujan las áreas de todas con trasparencia fill(0,19); for (int i = 0; i < columnCount; i++) { drawDataAreaStatic(i); } noFill(); //se dibuja en rojo la capa de la M30 strokeWeight(2); stroke(255,0,0); drawDataLine(3); //se hace activa para ver datos con el ratón la capa activa for (int i = 0; i < columnCount; i++) { drawDataHighlight(i); } noStroke(); for (int row = 0; row < rowCount; row++) { interpolators[row].update(); } } void drawTitle() { fill(0); textSize(20); textAlign(LEFT); String title = data.getColumnName(currentColumn); text(title, plotX1, plotY1 - 10); } float[] tabLeft, tabRight; // Add above setup() float tabTop, tabBottom; float tabPad = 10; void drawTitleTabs() { rectMode(CORNERS); noStroke(); textSize(10); textAlign(LEFT); // On first use of this method, allocate space for an array // to store the values for the left and right edges of the tabs if (tabLeft == null) { tabLeft = new float[columnCount]; tabRight = new float[columnCount]; } float runningX = plotX1; tabTop = plotY1 - textAscent() - 13-distanc; tabBottom = plotY1-distanc; for (int col = 0; col < columnCount; col++) { String title = data.getColumnName(col); tabLeft[col] = runningX; float titleWidth = textWidth(title); tabRight[col] = tabLeft[col] + tabPad + titleWidth + tabPad; fill(255); rect(tabLeft[0], tabBottom, tabRight[4], tabBottom+distanc+13); // If the current tab, set its background white, otherwise use pale gray fill(col == currentColumn ? #86C1DE : 224); rect(tabLeft[col], tabTop, tabRight[col], tabBottom); // If the current tab, use black for the text, otherwise use dark gray fill(col == currentColumn ? 255 : 64); text(title, runningX + tabPad, plotY1 - 10-distanc); runningX = tabRight[col]; } for (int col = 0; col < columnCount; col++) { stroke(150); line(tabRight[col],tabTop,tabRight[col],tabBottom-1); line(tabLeft[0],tabTop,tabLeft[0],tabBottom-1); } } void mousePressed() { if (mouseY > tabTop && mouseY < tabBottom) { for (int col = 0; col < columnCount; col++) { if (mouseX > tabLeft[col] && mouseX < tabRight[col]) { setCurrent(col); } } } } void setCurrent(int col) { currentColumn = col; for (int row = 0; row < rowCount; row++) { interpolators[row].target(data.getFloat(row, col)); } } void drawAxisLabels() { fill(0); textSize(13); textLeading(15); textAlign(LEFT); text("Millones de\nEuros", labelX-40, (plotY1+plotY2)/2); text("Años", plotX1, plotY2+45); textAlign(LEFT); textSize(18); text("Deuda de Madrid en relación con otras ciudades españolas y la M30",plotX1, plotY1/3); textSize(9); fill(100); textAlign(RIGHT); text("Fuente: Banco de España y Presupuestos Ayto. Madrid. 2010", width-5, labelY+20); } void drawYearLabels() { fill(0); textSize(10); textAlign(CENTER); // Use thin, gray lines to draw the grid stroke(234); strokeWeight(1); for (int row = 1; row < rowCount; row = row+4) { //if (years[row] % yearInterval == 0) { //float x = map(years[row], yearMin, yearMax, plotX1, plotX2); //prueba a meter más valores por cada año float x = map(row, 0, rowCount-1, plotX1, plotX2); text(years[row], x, plotY2 + textAscent() + 10); //line(x, plotY1, x, plotY2); //para lineas de abajo a arriba stroke(150); line(x, plotY2, x, plotY2+5); //} } //las rayitas de cada uno de los trimestres for (int row = 0; row < rowCount-1; row++) { float x = map(row, 0, rowCount-1, plotX1, plotX2); stroke(150); point(x, plotY2+4); } } void drawVolumeLabels() { fill(0); textSize(10); textAlign(RIGHT); stroke(128); strokeWeight(1); for (float v = dataMin; v <= dataMax; v += volumeIntervalMinor) { if (v % volumeIntervalMinor == 0) { // If a tick mark float y = map(v, dataMin, dataMax, plotY2, plotY1); if (v % volumeInterval == 0) { // If a major tick mark float textOffset = textAscent()/2; // Center vertically if (v == dataMin) { textOffset = 0; // Align by the bottom } else if (v == dataMax) { textOffset = textAscent(); // Align by the top } int vol = floor(v)/1000; String voli = nfc(vol); text(voli, plotX1 - 10, y + textOffset); //para deuda por habitante text(floor(v), plotX1 - 10, y + textOffset); line(plotX1 - 4, y, plotX1, y); // Draw major tick } else { line(plotX1 - 2, y, plotX1, y); // Draw minor tick } } } } void drawComments(int col, String nameC) { int row =rowCount-1; float value = data.getFloat(row,col); textAlign(LEFT); textLeading(10); float y = map(value, dataMin, dataMax, plotY2, plotY1); line(plotX2+4,y,plotX2+13,y); int valueF = ceil(value/1000); String valueFi = nfc(valueF); text(valueFi+" millones"+nameC,plotX2+17,y+5); } void drawCommentsVertD(int row, String nameD) { fill(20); textAlign(RIGHT); textLeading(10); float x = map(row, 0, rowCount-1, plotX1, plotX2); stroke(100); strokeWeight(1); line(x,plotY2+24,x,plotY2+60); line(x,plotY2+24,x+3,plotY2+27); line(x,plotY2+24,x-3,plotY2+27); text(nameD,x-3,plotY2+40); } void drawCommentsVert(int row, String nameD) { fill(20); textAlign(LEFT); textLeading(10); float x = map(row, 0, rowCount-1, plotX1, plotX2); stroke(100); strokeWeight(1); line(x,plotY2+12,x,plotY2+60); line(x,plotY2+12,x+3,plotY2+15); line(x,plotY2+12,x-3,plotY2+15); text(nameD,x+3,plotY2+40); //stroke(180); //line(x,plotY1+400,x,plotY2); } void drawDataArea(int col) { beginShape(); for (int row = 0; row < rowCount; row++) { if (data.isValid(row, col)) { //para hacerlo sin interpolator //float value = data.getFloat(row, col); float value = interpolators[row].value; //para hacerlo en función del año //float x = map(years[row], yearMin, yearMax, plotX1, plotX2); //prueba a meter más valores por cada año float x = map(row, 0, rowCount-1, plotX1, plotX2); float y = map(value, dataMin, dataMax, plotY2, plotY1); vertex(x, y); /*probando que se vean unos puntitos en el borde del area color(0); strokeWeight(3); point(map(row, 0, rowCount-1, plotX1, plotX2),map(value, dataMin, dataMax, plotY2, plotY1)); */ } } // Draw the lower-right and lower-left corners vertex(plotX2, plotY2); vertex(plotX1, plotY2); endShape(CLOSE); } void drawDataAreaStatic(int col) { beginShape(); for (int row = 0; row < rowCount; row++) { if (data.isValid(row, col)) { //para hacerlo sin interpolator float value = data.getFloat(row, col); //para hacerlo en función del año //float x = map(years[row], yearMin, yearMax, plotX1, plotX2); //prueba a meter más valores por cada año float x = map(row, 0, rowCount-1, plotX1, plotX2); float y = map(value, dataMin, dataMax, plotY2, plotY1); vertex(x, y); } } // Draw the lower-right and lower-left corners vertex(plotX2, plotY2); vertex(plotX1, plotY2); endShape(CLOSE); } void keyPressed() { if (key == '[') { currentColumn--; if (currentColumn < 0) { currentColumn = columnCount - 1; } } else if (key == ']') { currentColumn++; if (currentColumn == columnCount) { currentColumn = 0; } } } void drawDataHighlight(int col) { for (int row = 0; row < rowCount; row++) { if (data.isValid(row, col)) { float value = data.getFloat(row, col); //float x = map(years[row], yearMin, yearMax, plotX1, plotX2); //prueba a meter más valores por cada año float x = map(row, 0, rowCount-1, plotX1, plotX2); float valueTot = data.getFloat(row, 0); float y = map(value, dataMin, dataMax, plotY2, plotY1); if (dist(mouseX, mouseY, x, y) < 5) { stroke(0,100); strokeWeight(10); point(x, y); float valueA = value/1000; String valueI = nfc(valueA,2); String txtmillones = valueI+ "millones\n(Año " + years[row] + ")\n"+ ceil(value/valueTot*100)+ "%"; String millones = valueI+ "millones"; float millw= textWidth(millones); strokeWeight(0); rectMode(CORNER); fill(255,180); rect(x-13, y-52,millw+8,38); triangle(x-3,y-14,x+3,y-14,x,y); fill(0); textSize(10); textAlign(LEFT); textLeading(12); text(txtmillones, x-9, y-42); //text(nf(value/1000, 0, 2) + " millones\n (Año " + years[row] + ")\n"+ ceil(value/valueTot*100)+ "%", x-9, y-32); textAlign(LEFT); } } } } void drawDataLine(int col) { noFill(); beginShape(); for (int row = 0; row < rowCount; row++) { if (data.isValid(row, col)) { //para hacerlo sin interpolator float value = data.getFloat(row, col); //para hacerlo con interpolator //float value = interpolators[row].value; //para hacerlo en función del año //float x = map(years[row], yearMin, yearMax, plotX1, plotX2); //prueba a meter más valores por cada año float x = map(row, 0, rowCount-1, plotX1, plotX2); float y = map(value, dataMin, dataMax, plotY2, plotY1); vertex(x, y); } } endShape(); }