Catch me if you can

Demin Hu
Data Mining the City
10 min readDec 16, 2017

We now living in a digital world where we depend on Internet to get all the information. However, the physical world is sometimes too complicated to catch it digitally.

Museums are a great cultural asset to our cities, but what if you don’t want to spend $20 on a single outing? Luckily for us, New York City has many museums that offer free days — — — or do they? How easy is it to catch a museum when it’s free? How many chances do I have per week?

The actual time for the museums is like a maze in the digital world and unreachable in the physical world.

Maze of Time

We wanted to visualize the complexity of NYC’s museum admission prices and occurrences of opportunities. Organized as if in an exhibition gallery, museums are arranged by their adult ticket price, ranging from free to donation-based, up to a hefty $33 admission price. Additionally, museums move locations as they become free throughout the week — but good luck catching them!

It is displayed in a digital room and you can never experience it in the physical world.

Sources:
-museum names: https://data.cityofnewyork.us/Recreation/Museums-and-galleries/kcrm-j9hh
-museum hours: each museum website from the list above

We are using UDP to transfer on time information from grasshopper to processing. We are also using the twitter API to get twitter data using Java libraries.

The first part of the script is calling libraries and data.

import twitter4j.conf.*;
import twitter4j.api.*;
import twitter4j.*;
import java.util.List;
import java.util.Iterator;
import hypermedia.net.*;
UDP udpr; // define the UDP object;
UDP udps; // define the UDP object;
String message;
int mx=0;
int my=0;
int mx2=0;
int my2, mx3, my3, mx4, my4, mx5, my5, mx6, my6, mx7, my7, mx8, my8, mx9, my9, mx10, my10, mx11, my11, mx12, my12, mx13, my13, mx14, my14, mx15, my15, mx16, my16, mx17, my17, mx18, my18, mx19, my19, mx20, my20 = 0;
int mx21, my21, mx22, my22, mx23, my23, mx24, my24, mx25, my25, mx26, my26, mx27, my27, mx28, my28, mx29, my29, mx30, my30, mx31, my31, mx32, my32, mx33, my33, mx34, my34, mx35, my35, mx36, my36, mx37, my37, mx38, my38, mx39, my39, mx40, my40 = 0;
int mx41, my41, mx42, my42, mx43, my43, mx44, my44, mx45, my45, mx46, my46, mx47, my47, mx48, my48, mx49, my49, mx50, my50 = 0;
int mx51, my51, mx52, my52, mx53, my53, mx54, my54, mx55, my55, mx56, my56, mx57, my57, mx58, my58, mx59, my59, mx60, my60, mx61, my61, mx62, my62, mx63, my63, mx64, my64, mx65, my65, mx66, my66, mx67, my67, mx68, my68, mx69, my69, mx70, my70 = 0;
int mx71, my71, mx72, my72, mx73, my73, mx74, my74, mx75, my75, mx76, my76, mx77, my77, mx78, my78, mx79, my79, mx80, my80 = 0;
int mxtoday, mytoday ,mysunday, mxsunday= 0;
int image_width, image_length;
ConfigurationBuilder cb;
Query query;
Twitter twitter;
ArrayList<String> twittersList;
Timer time;
//Number twitters per search
int numberSearch = 20;
PFont font;
int fontSize = 14;
PImage img2,img3, img4, img5, img6, img7, img8, img9, img10, img11, img12, img13, img14, img15, img16, img17, img18, img19, img20, img21, img22, img23, img24, img25, img26, img27, img28, img29, img30;
PImage img31, img32, img33, img34, img35, img36, img37, img38, img39, img40, img41, img42, img43, img44, img45, img46, img47, img48, img49, img50;
PImage img51, img52, img53, img54, img55, img56, img57, img58, img59, img60, img61, img62, img63, img64, img65, img66, img67, img68, img69, img70;
PImage img71, img72, img73, img74, img75, img76, img77, img78, img79, img80;

The next part is assign variables including pictures of the museum and twitter query data.

void setup() {
size(1900, 900);
background(0);
smooth(4);
udpr = new UDP( this, 7000);
udps = new UDP( this, 6999);
udpr.listen( true );
img2 = loadImage("2.jpg");
img3 = loadImage("3.jpg");
img4 = loadImage("4.jpg");
img5 = loadImage("5.jpg");
img6 = loadImage("6.jpg");
img7 = loadImage("7.jpg");
img8 = loadImage("8.jpg");
img9 = loadImage("9.jpg");
img10 = loadImage("10.jpg");
img11 = loadImage("11.jpg");
img12 = loadImage("12.jpg");
img13 = loadImage("13.jpg");
img14 = loadImage("14.jpg");
img15 = loadImage("15.jpg");
img16 = loadImage("16.jpg");
img17 = loadImage("17.jpg");
img18 = loadImage("18.jpg");
img19 = loadImage("19.jpg");
img20 = loadImage("20.jpg");
img21 = loadImage("21.jpg");
img22 = loadImage("22.jpg");
img23 = loadImage("23.jpg");
img24 = loadImage("24.jpg");
img25 = loadImage("25.jpg");
img26 = loadImage("26.jpg");
img27 = loadImage("27.jpg");
img28 = loadImage("28.jpg");
img29 = loadImage("29.jpg");
img30 = loadImage("30.jpg");
img31 = loadImage("31.jpg");
img32 = loadImage("32.jpg");
img33 = loadImage("33.jpg");
img34 = loadImage("34.jpg");
img35 = loadImage("35.jpg");
img36 = loadImage("36.jpg");
img37 = loadImage("37.jpg");
img38 = loadImage("38.jpg");
img39 = loadImage("39.jpg");
img40 = loadImage("40.jpg");
img41 = loadImage("41.jpg");
img42 = loadImage("42.jpg");
img43 = loadImage("43.jpg");
img44 = loadImage("44.jpg");
img45 = loadImage("45.jpg");
img46 = loadImage("46.jpg");
img47 = loadImage("47.jpg");
img48 = loadImage("48.jpg");
img49 = loadImage("49.jpg");
img50 = loadImage("50.jpg");
img51 = loadImage("51.jpg");
img52 = loadImage("52.jpg");
img53 = loadImage("53.jpg");
img54 = loadImage("54.jpg");
img55 = loadImage("55.jpg");
img56 = loadImage("56.jpg");
img57 = loadImage("57.jpg");
img58 = loadImage("58.jpg");
img59 = loadImage("59.jpg");
img60 = loadImage("60.jpg");
img61 = loadImage("61.jpg");
img62 = loadImage("62.jpg");
img63 = loadImage("63.jpg");
img64 = loadImage("64.jpg");
img65 = loadImage("65.jpg");
img66 = loadImage("66.jpg");
img67 = loadImage("67.jpg");
img68 = loadImage("68.jpg");
img69 = loadImage("69.jpg");
img70 = loadImage("70.jpg");
img71 = loadImage("71.jpg");
img72 = loadImage("72.jpg");
img73 = loadImage("73.jpg");
img74 = loadImage("74.jpg");
img75 = loadImage("75.jpg");
img76 = loadImage("76.jpg");
img77 = loadImage("77.jpg");
img78 = loadImage("78.jpg");
img79 = loadImage("79.jpg");
img80 = loadImage("80.jpg");
//FONT
font = createFont("NexaLight-16.vlw", fontSize, true);
textFont(font, fontSize);
//You can only search once every 1 minute
time = new Timer(70000); //1 min with 10 secs
//Acreditacion
cb = new ConfigurationBuilder();
cb.setOAuthConsumerKey("GRQuUh52FgPfQCRrgwZHaQn5W");
cb.setOAuthConsumerSecret("EwA7NCpNhqT2fTXchFh1hvAuYT0MEzYD5fCyICHpFh4yi2qrQI");
cb.setOAuthAccessToken("869697582959910912-9sCUwhZ5iEcFHzhJDhghbCIJDgYLF5N");
cb.setOAuthAccessTokenSecret("RDHZZUVEgW1KYfodyS1VFDRL581pHVj03bRXE9ha5LMT8");
//Make the twitter object and prepare the query
twitter = new TwitterFactory(cb.build()).getInstance();
//SEARCH
twittersList = queryTwitter(numberSearch);
}

The draw function first receives and process the data acquired from grasshopper UDP.

void draw() {
background(255);
fill(232, 178, 186);
rect(255, 553, 1000, -432);
fill(255);
rect(1580, 553, 300, -432);
line(1255, 121, 1510, 0);
line(1510, 652, 1255, 553);
line(255, 553, 0, 652);
line(255, 121, 0,0);
line (1255, 785, 703, 785);
line(1255, 765, 1255, 815);
line(1176, 765, 1176, 815);
line(861, 765, 861, 815);
line(940, 765, 940, 815);
line(1020, 765, 1020, 815);
line(1098, 765,1098, 815);
line(782, 765, 782, 815);
line(703, 765, 703, 815);
String[] coo = split(message, ',');
//print(coo.length);
if (coo != null)
{
mx2 = int(coo[0]);
my2 = int(coo[1]);
mx3 = int(coo[2]);
my3 = int(coo[3]);
mx4 = int(coo[4]);
my4 = int(coo[5]);
mx5 = int(coo[6]);
my5 = int(coo[7]);
mx6 = int(coo[8]);
my6 = int(coo[9]);
mx7 = int(coo[10]);
my7 = int(coo[11]);
mx8 = int(coo[12]);
my8 = int(coo[13]);
mx9 = int(coo[14]);
my9 = int(coo[15]);
mx10 = int(coo[16]);
my10 = int(coo[17]);
mx11 = int(coo[18]);
my11 = int(coo[19]);
mx12 = int(coo[20]);
my12 = int(coo[21]);
mx13 = int(coo[22]);
my13 = int(coo[23]);
mx14 = int(coo[24]);
my14 = int(coo[25]);
mx15 = int(coo[26]);
my15 = int(coo[27]);
mx16 = int(coo[28]);
my16 = int(coo[29]);
mx17 = int(coo[30]);
my17 = int(coo[31]);
mx18 = int(coo[32]);
my18 = int(coo[33]);
mx19 = int(coo[34]);
my19 = int(coo[35]);
mx20 = int(coo[36]);
my20 = int(coo[37]);
mx21 = int(coo[38]);
my21 = int(coo[39]);
mx22 = int(coo[40]);
my22 = int(coo[41]);
mx23 = int(coo[42]);
my23 = int(coo[43]);
mx24 = int(coo[44]);
my24 = int(coo[45]);
mx25 = int(coo[46]);
my25 = int(coo[47]);
mx26 = int(coo[48]);
my26 = int(coo[49]);
mx27 = int(coo[50]);
my27 = int(coo[51]);
mx28 = int(coo[52]);
my28 = int(coo[53]);
mx29 = int(coo[54]);
my29 = int(coo[55]);
mx30 = int(coo[56]);
my30 = int(coo[57]);
mx31 = int(coo[58]);
my31 = int(coo[59]);
mx32 = int(coo[60]);
my32 = int(coo[61]);
mx33 = int(coo[62]);
my33 = int(coo[63]);
mx34 = int(coo[64]);
my34 = int(coo[65]);
mx35 = int(coo[66]);
my35 = int(coo[67]);
mx36 = int(coo[68]);
my36 = int(coo[69]);
mx37 = int(coo[70]);
my37 = int(coo[71]);
mx38 = int(coo[72]);
my38 = int(coo[73]);
mx39 = int(coo[74]);
my39 = int(coo[75]);
mx40 = int(coo[76]);
my40 = int(coo[77]);
mx41 = int(coo[78]);
my41 = int(coo[79]);
mx42 = int(coo[80]);
my42 = int(coo[81]);
mx43 = int(coo[82]);
my43 = int(coo[83]);
mx44 = int(coo[84]);
my44 = int(coo[85]);
mx45 = int(coo[86]);
my45 = int(coo[87]);
mx46 = int(coo[88]);
my46 = int(coo[89]);
mx47 = int(coo[90]);
my47 = int(coo[91]);
mx48 = int(coo[92]);
my48 = int(coo[93]);
mx49 = int(coo[94]);
my49 = int(coo[95]);
mx50 = int(coo[96]);
my50 = int(coo[97]);
mx51 = int(coo[98]);
my51 = int(coo[99]);
mx52 = int(coo[100]);
my52 = int(coo[101]);
mx53 = int(coo[102]);
my53 = int(coo[103]);
mx54 = int(coo[104]);
my54 = int(coo[105]);
mx55 = int(coo[106]);
my55 = int(coo[107]);
mx56 = int(coo[108]);
my56 = int(coo[109]);
mx57 = int(coo[110]);
my57 = int(coo[111]);
mx58 = int(coo[112]);
my58 = int(coo[113]);
mx59 = int(coo[114]);
my59 = int(coo[115]);
mx60 = int(coo[116]);
my60 = int(coo[117]);
mx61 = int(coo[118]);
my61 = int(coo[119]);
mx62 = int(coo[120]);
my62 = int(coo[121]);
mx63 = int(coo[122]);
my63 = int(coo[123]);
mx64 = int(coo[124]);
my64 = int(coo[125]);
mx65 = int(coo[126]);
my65 = int(coo[127]);
mx66 = int(coo[128]);
my66 = int(coo[129]);
mx67 = int(coo[130]);
my67 = int(coo[131]);
mx68 = int(coo[132]);
my68 = int(coo[133]);
mx69 = int(coo[134]);
my69 = int(coo[135]);
mx70 = int(coo[136]);
my70 = int(coo[137]);
mx71 = int(coo[138]);
my71 = int(coo[139]);
mx72 = int(coo[140]);
my72 = int(coo[141]);
mx73 = int(coo[142]);
my73 = int(coo[143]);
mx74 = int(coo[144]);
my74 = int(coo[145]);
mx75 = int(coo[146]);
my75 = int(coo[147]);
mx76 = int(coo[148]);
my76 = int(coo[149]);
mx77 = int(coo[150]);
my77 = int(coo[151]);
mx78 = int(coo[152]);
my78 = int(coo[153]);
mx79 = int(coo[154]);
my79 = int(coo[155]);
mx80 = int(coo[156]);
my80 = int(coo[157]);
mxtoday = int(coo[158]);
mytoday = int(coo[159]);
mxsunday = int(coo[160]);
mysunday = int(coo[161]);
}

Then we draw the moving pictures and print the twitter message.

fill(122);
stroke(0);
image_width = 40;
image_length = 40;
image(img2, mx2, my2, image_width, image_length);
image(img3, mx3, my3, image_width, image_length);
image(img4, mx4, my4, image_width, image_length);
image(img5, mx5, my5, image_width, image_length);
image(img6, mx6, my6, image_width, image_length);
image(img7, mx7, my7, image_width, image_length);
image(img8, mx8, my8, image_width, image_length);
image(img9, mx9, my9, image_width, image_length);
image(img10, mx10, my10, image_width, image_length);
image(img11, mx11, my11, image_width, image_length);
image(img12, mx12, my12, image_width, image_length);
image(img13, mx13, my13, image_width, image_length);
image(img14, mx14, my14, image_width, image_length);
image(img15, mx15, my15, image_width, image_length);
image(img16, mx16, my16, image_width, image_length);
image(img17, mx17, my17, image_width, image_length);
image(img18, mx18, my18, image_width, image_length);
image(img19, mx19, my19, image_width, image_length);
image(img20, mx20, my20, image_width, image_length);
image(img21, mx21, my21, image_width, image_length);
image(img22, mx22, my22, image_width, image_length);
image(img23, mx23, my23, image_width, image_length);
image(img24, mx24, my24, image_width, image_length);
image(img25, mx25, my25, image_width, image_length);
image(img26, mx26, my26, image_width, image_length);
image(img27, mx27, my27, image_width, image_length);
image(img28, mx28, my28, image_width, image_length);
image(img29, mx29, my29, image_width, image_length);
image(img30, mx30, my30, image_width, image_length);
image(img31, mx31, my31, image_width, image_length);
image(img32, mx32, my32, image_width, image_length);
image(img33, mx33, my33, image_width, image_length);
image(img34, mx34, my34, image_width, image_length);
image(img35, mx35, my35, image_width, image_length);
image(img36, mx36, my36, image_width, image_length);
image(img37, mx37, my37, image_width, image_length);
image(img38, mx38, my38, image_width, image_length);
image(img39, mx39, my39, image_width, image_length);
image(img40, mx40, my40, image_width, image_length);
image(img41, mx41, my41, image_width, image_length);
image(img42, mx42, my42, image_width, image_length);
image(img43, mx43, my43, image_width, image_length);
image(img44, mx44, my44, image_width, image_length);
image(img45, mx45, my45, image_width, image_length);
image(img46, mx46, my46, image_width, image_length);
image(img47, mx47, my47, image_width, image_length);
image(img48, mx48, my48, image_width, image_length);
image(img49, mx49, my49, image_width, image_length);
image(img50, mx50, my50, image_width, image_length);
image(img51, mx51, my51, image_width, image_length);
image(img52, mx52, my52, image_width, image_length);
image(img53, mx53, my53, image_width, image_length);
image(img54, mx54, my54, image_width, image_length);
image(img55, mx55, my55, image_width, image_length);
image(img56, mx56, my56, image_width, image_length);
image(img57, mx57, my57, image_width, image_length);
image(img58, mx58, my58, image_width, image_length);
image(img59, mx59, my59, image_width, image_length);
image(img60, mx60, my60, image_width, image_length);
image(img61, mx61, my61, image_width, image_length);
image(img62, mx62, my62, image_width, image_length);
image(img63, mx63, my63, image_width, image_length);
image(img64, mx64, my64, image_width, image_length);
image(img65, mx65, my65, image_width, image_length);
image(img66, mx66, my66, image_width, image_length);
image(img67, mx67, my67, image_width, image_length);
image(img68, mx68, my68, image_width, image_length);
image(img69, mx69, my69, image_width, image_length);
image(img70, mx70, my70, image_width, image_length);
image(img71, mx71, my71, image_width, image_length);
image(img72, mx72, my72, image_width, image_length);
image(img73, mx73, my73, image_width, image_length);
image(img74, mx74, my74, image_width, image_length);
image(img75, mx75, my75, image_width, image_length);
image(img76, mx76, my76, image_width, image_length);
image(img77, mx77, my77, image_width, image_length);
image(img78, mx78, my78, image_width, image_length);
image(img79, mx79, my79, image_width, image_length);
image(img80, mx80, my80, image_width, image_length);
print (mxtoday);
ellipse(mxtoday, mytoday, 10,10);
text("Today", mxtoday+5, mytoday-5);
//ellipse(mxsunday, mysunday, 10,10);
fill(105);
text("Monday", 680, 840);
text("Sunday", 1235, 840);
text("$16 - $33", 1170, 210);
text("$10 - $15", 1170, 272);
text("$4 - $10", 1170, 335);
text("donation", 1170, 430);
text("free!", 1170, 477);
text("in the news", 1580,100);
//draw twitters
drawTwitters(twittersList);
if (time.isDone()) {
twittersList = queryTwitter(numberSearch);
time.reset();
}

text(time.getCurrentTime(), 20, 30);
time.update();
}
void drawTwitters(ArrayList<String> tw) {
Iterator<String> it = tw.iterator();
int i = 0;
while (it.hasNext ()) {
String twitt = it.next();
fill(150);
text(i + 1, 1585, 120 + i*(fontSize)*4 + fontSize);
fill(150);
text(twitt, 1595, 120 + i*(fontSize)*4, 280, fontSize*4);
i++;
}
}
ArrayList<String> queryTwitter(int nSearch) {
ArrayList<String> twitt = new ArrayList<String>();
query = new Query("#Metropolitan Museum of Art");
query.setCount(nSearch);
try {
QueryResult result = twitter.search(query);
List<Status> tweets = result.getTweets();
println("New Tweet : ");
for (Status tw : tweets) {
String msg = tw.getText();
String usr = tw.getUser().getScreenName();
String twStr = "@"+usr+": "+msg;
println(twStr);
twitt.add(twStr);
}
}
catch (TwitterException te) {
println("Couldn't connect: " + te);
}
return twitt;
}
void receive( byte[] data, String ip, int port ) { // <-- extended handler


// get the "real" message =
// forget the ";\n" at the end <-- !!! only for a communication with Pd !!!
data = subset(data, 0, data.length);
message = new String( data );

// print the result
println( "receive: \""+message+"\" from "+ip+" on port "+port );



}

Lastly, we make a time to record the whole process and refresh the twitter data.

class Timer {
int savedTime; // When Timer started
int totalTime; // How long Timer should last
float msTime;
int tempTime;
boolean end;Timer(int tempTotalTime) {
totalTime = tempTotalTime;
}
void start() {
// When the timer starts it stores the current time in milliseconds.
savedTime = millis();
}
float getCurrentTime() {
return (msTime = tempTime/1000.0);
}
void reset() {
tempTime = 0;
start();
}

boolean isDone(){
return end;
}
// The function isFinished() returns true if 5,000 ms have passed.
// The work of the timer is farmed out to this method.
void update() {
// Check how much time has passed
tempTime = millis()- savedTime;
if (tempTime > totalTime) {
end = true;
}
else {
end = false;
}
}
}

--

--