visualización de datos 3D de las últimas mensajes de twitter que contienen un término o un conjunto de terminos. la aplicación fue hecha en processing, utilizando una versión resumida de la biblioteca twitter4j y el twitter API. este fue un ejercicio propuesto para el taller datajockey, que ocurrió durante los días 17 y 31 de mayo de 2011, en el Museo de la Imagen y del Sonido de San Pablo, Brasil.
el sketch hace una búsqueda por un término en los últimos tweets almacenados en el banco de datos de twitter, exhibiendo los resultados en un espacio 3D. la posición y el color son atribuidos de acuerdo con el horario en que cada tweet fue almacenado en el banco. si dos o más tweets fueron almacenados en horarios próximos, una línea los conecta en el espacio 3D de visualización, generando estructuras. el tamaño de los cubos es atribuido segundo el valor respectivo a los minutos del horario en que el tweet fue almacenado en el banco.





una lástima que no puedo exhibir la propia aplicación acá, debido a limitaciones del processing.js. pero el código-fuente se encuentra abajo. fíjese que, antes de testarlo en processing, es necesario bajar la biblioteca de twitter4j y inserir el archivo en una carpeta llamada ‘code’, que debe quedarse adentro de la carpeta de tu sketch de processing. es necesario también inserir algunas claves de acceso al banco de datos del twitter, registrando una nueva aplicación en el sitio del API. después, injerí las respectivas claves en las variables indicadas en el código.
//twitter 3D data visualization //by medul.la //http://medul.la //based on the sketch '3D Processing World', by Josue Page //http://www.openprocessing.org/visuals/?visualID=19216 //the twitter connection is made by using the twitter4j java library: //http://twitter4j.org // Before you use this sketch, register your Twitter application at dev.twitter.com // Once registered, you will have the info for the OAuth tokens //setting twitter API info: static String OAuthConsumerKey = "PUT YOUR CONSUMER KEY HERE"; static String OAuthConsumerSecret = "PUT YOUR CONSUMER SECRET KEY HERE"; static String AccessToken = "PUT YOUR ACCESS TOKEN HERE"; static String AccessTokenSecret = "PUT YOUR ACCESS TOKEN SECRET HERE"; //define parameters //a word to search for in the tweets database: String searchTerm = "PUT YOUR SEARCH TERM HERE"; //a number of tweets to work with (you can choose any number up to 100) : int numOfTweets = 50; java.util.List statuses = null; Twitter twitter = new TwitterFactory().getInstance(); RequestToken requestToken; String[] theSearchTweets = new String[numOfTweets]; Date[] tweetTimeData = new Date[numOfTweets]; String[] tweetTimeStrings = new String[0]; int[] tweetTimeInts = new int[0]; color[] colors = new color[0]; int[] coords = new int[0]; int objects = numOfTweets, zoom = -300, xCube, yCube, zCube; Pts[] cubes = new Pts[objects]; color bgColor = 0, lineColor = 255; float R, G, B; PFont theFont; void setup() { size(1024, 750, P3D); connectTwitter(); getSearchTweets(searchTerm); convertDateToString(); convertStringToInts(); convertIntsToColor(); convertIntsToPosition(); checkColors(); checkCoords(); background(255); translate(width, 0, 0); theFont = createFont("Arial",1000); for (int i = 0; i < numOfTweets ; i++) { String t = theSearchTweets[i]; //println(t); cubes[i] = new Pts(coords[i], coords[i+1], coords[i+2], colors[i], 1, t); } } void draw() { translate(width/2, height/2, width/2+zoom); rotateX(map(mouseY, 0, height, -2*PI, 2*PI)); rotateY(map(mouseX, 0, width, -2*PI, 2*PI)); background(bgColor, 50); for (int u = 0; u < objects ; u++) { cubes[u].drawCubes(); for (int v=0;v<objects;v++) { if (abs(cubes[u].z-cubes[v].z)<200) { if (abs(cubes[u].x-cubes[v].x)<200) { if (abs(cubes[u].y-cubes[v].y)<200) { stroke(lineColor, 50); beginShape(LINES); vertex(cubes[u].x, cubes[u].y, cubes[u].z); vertex(cubes[v].x, cubes[v].y, cubes[v].z); endShape(); } } } } cubes[u].change(); } if (mousePressed) { bgColor = 255; lineColor = color(255, 0, 0); } else { bgColor = 0; lineColor = 255; } } class Pts { int x, y, z; float tem; color cubeColorC; String theText; Pts(int a, int b, int c, color d, float e, String t) { x = a; y = b; z = c; cubeColorC = d; tem = b/20; theText = t; } void drawCubes() { if (mousePressed) { fill(0, 50); } else { fill(lineColor, 50); } noStroke(); fill(cubeColorC); text(theText, x+30, y, 100, 1000, z); pushMatrix(); translate(x, y, z); fill(cubeColorC); box(tem); popMatrix(); } void change() { if (x <- width) { x =- width + 10; } else { if (x > height) { x = height - 10; } else { x = x + int(random(-3, 3)); } } if (y <- height) { y =- height+10; } else { if (y > width) { y = width - 10; } else { y = y + int(random(-5, 5)); } if (z > width) { z = width - 10; } else { z = z + int(random(-5, 5)); } if ( z<- width) { z =- width + 10; } } } } void keyPressed() { if (keyCode == 40) { zoom -= 300; } if (keyCode == 38) { zoom += 300; } } //twitter API functions // Initial connection void connectTwitter() { twitter.setOAuthConsumer(OAuthConsumerKey, OAuthConsumerSecret); AccessToken accessToken = loadAccessToken(); twitter.setOAuthAccessToken(accessToken); } // Loading up the access token private static AccessToken loadAccessToken() { return new AccessToken(AccessToken, AccessTokenSecret); } // Search for tweets void getSearchTweets(String searchTerm) { String queryStr = searchTerm; try { Query query = new Query(queryStr); query.setRpp(numOfTweets); // Get 10 of the 100 search results QueryResult result = twitter.search(query); ArrayList tweets = (ArrayList) result.getTweets(); for (int i=0; i<tweets.size(); i++) { Tweet t = (Tweet)tweets.get(i); String user = t.getFromUser(); String msg = t.getText(); Date d = t.getCreatedAt(); theSearchTweets[i] = msg; tweetTimeData[i] = d; println(theSearchTweets[i]); println("----------------"); println("Tweet by " + user + " at " + d); println("----------------"); println(tweetTimeData[i]); println("----------------"); } } catch (TwitterException e) { println("Search tweets: " + e); } } void convertDateToString(){ for (int i = 0; i < tweetTimeData.length; i++){ SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy/HH/mm/ss"); String s = df.format(tweetTimeData[i]); String sArray[] = new String [0]; sArray = splitTokens(s, "/"); for (int j = 0; j < sArray.length; j++){ tweetTimeStrings = append(tweetTimeStrings, sArray[j]); println(tweetTimeStrings[j]); } } } void convertStringToInts(){ for (int i = 0; i < tweetTimeStrings.length; i++){ int num = int(tweetTimeStrings[i]); tweetTimeInts = append(tweetTimeInts, num); println("tweetTimeInts at the index of " + i + " is: " + num); } } void convertIntsToColor(){ for (int i = 3; i < tweetTimeInts.length; i = i+6){ R = map (tweetTimeInts[i], 0, 24, 0, 255); G = map (tweetTimeInts[(i+1)], 0, 60, 0, 255); B = map (tweetTimeInts[(i+2)], 0, 60, 0, 255); color clr = color (R, G, B); colors = append (colors, clr); //println("color stored is = R " + red(clr) + ", G " + green(clr) + ", B " + blue(clr)); } } void convertIntsToPosition(){ for (int i = 3; i < tweetTimeInts.length; i = i+6){ xCube = int(map (tweetTimeInts[i], 0, 24, -width, width)); yCube = int(map (tweetTimeInts[(i+1)], 0, 60, -height, height)); zCube = int(map (tweetTimeInts[(i+2)], 0, 60, -width, width)); coords = append (coords, xCube); coords = append (coords, yCube); coords = append (coords, zCube); //println("position stored is = xCube " + xCube + ", yCube " + yCube + ", zCube " + zCube); } } void checkColors(){ for (int i = 0; i < objects; i++){ println("color stored is = R " + red(colors[i]) + ", G " + green(colors[i]) + ", B " + blue(colors[i])); } } void checkCoords(){ for (int i = 0; i < coords.length; i=i+3){ println("position stored is = xCube " + coords[i] + ", yCube " + coords[i+1] + ", zCube " + coords[i+2]); } }