Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: mccoyjus/fb_examples
base: 2e644c5e3c
...
head fork: mccoyjus/fb_examples
compare: fe9553cf5a
  • 3 commits
  • 3 files changed
  • 0 commit comments
  • 1 contributor
Commits on Feb 04, 2012
Justin McCoy Updated the project path. 9e0fd22
Justin McCoy Initial import for example2 db2950c
Commits on Feb 09, 2012
Justin McCoy Updated to query directly from Facebook graph API using FQL. Displaying
more userdata within the visualization.
fe9553c
View
4 ...ssing/fb/userwalldata/FBUserWallData.java → ...ocessing/userwalldata/FBUserWallData.java
@@ -1,4 +1,4 @@
-package com.sholmes.processing.fb.userwalldata;
+package com.sholmes.examples.processing.userwalldata;
import java.io.BufferedReader;
import java.io.File;
@@ -27,7 +27,7 @@
public static void main(String _args[])
{
- PApplet.main(new String[] { com.sholmes.processing.fb.userwalldata.FBUserWallData.class.getName() });
+ PApplet.main(new String[] { com.sholmes.examples.processing.userwalldata.FBUserWallData.class.getName() });
}
private static final int HEIGHT = 1024;
View
1  example2/default.properties
@@ -0,0 +1 @@
+access_token=[your access token]
View
799 example2/src/com/sholmes/processing/examples/Example2.java
@@ -0,0 +1,799 @@
+package com.sholmes.processing.examples;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Type;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+import processing.core.PApplet;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+
+/**
+ *
+ * @author Justin McCoy <ahref="mailto:justinmccoy@acm.org">justinmccoy@acm.org</a>
+ *
+ */
+public class Example2 extends PApplet
+{
+
+ public static void main(String _args[])
+ {
+ PApplet.main(new String[] { com.sholmes.processing.examples.Example2.class.getName() });
+ }
+
+ private static final int HEIGHT = 1024;
+
+ private static final int WIDTH = 768;
+
+ private static final int MALE_FRIEND_COLOR = 60;
+
+ private static final int FEMALE_FRIEND_COLOR = 90;
+
+ private static final int OTHERSEX_FRIEND_COLOR = 0;
+
+ private static final int UNFRIEND_COLOR = 100;
+
+ private static final int INITIAL_CONNECTIONS = 0;
+
+ private static final int BORDER_OFFSET = 200;
+
+ private static final String ENCODING = "UTF-8";
+
+ private static final String ME = "me()";
+
+ private static final String ACCESS_TOKEN_PROPERTY = "access_token";
+
+ private static final String PROPERTIES_FILE = "default.properties";
+
+ private String ACCESS_TOKEN = "&access_token=";
+
+ private static final String FQL_QUERY_STRING = "https://api.facebook.com/method/fql.query?query=";
+
+ private static final String QUERY_FORMAT = "&format=json";
+
+ private static final Collection<String> FRIEND_ATTRIBUTES = Arrays.asList("uid", "sex", "name", "wall_count",
+ "mutual_friend_count", "likes_count", "friend_count");
+
+ private static final Collection<String> WALL_ATTRIBUTES = Arrays.asList("post_id", "actor_id", "target_id",
+ "message", "created_time", "likes");
+
+ private Properties defaultProps;
+
+ private ArrayList<Message> messages;
+
+ /*
+ * Key = user UID, Value = Object for user information
+ */
+ private HashMap<String, Friend> friends;
+
+ /*
+ * Key = user UID, Value = Object for user information
+ */
+ private HashMap<String, Integer> unfriends;
+
+ public void setup()
+ {
+ size(HEIGHT, WIDTH);
+ colorMode(HSB, 100);
+ noLoop(); // Not dynamically changing
+
+ friends = new HashMap<String, Friend>();
+ unfriends = new HashMap<String, Integer>();
+ messages = new ArrayList<Message>();
+
+ loadData();
+ }
+
+ /*
+ * With the ACCESS_TOKEN lets make application level requests to the social graph querying in a loop to collect
+ * all of the information from a users wall, and friends. With this new refined amount of data we can make more
+ * interesting assumptions about our connections. Who is the most active of friends, do they make many connections
+ * to me(), if so they would be considered a strong connection if not a weaker connection. Are there people that
+ * spend 0.x % communicating with me()?
+ */
+ public void loadData()
+ {
+ //Get the application properties
+ defaultProps = new Properties();
+ FileInputStream in;
+ try
+ {
+ in = new FileInputStream(PROPERTIES_FILE);
+
+ defaultProps.load(in);
+ in.close();
+ ACCESS_TOKEN += defaultProps.getProperty(ACCESS_TOKEN_PROPERTY);
+ }
+ catch (FileNotFoundException e)
+ {
+ //could not load the default application properties, must exit
+ System.err.println("Could not find application properties file: " + PROPERTIES_FILE);
+ System.exit(-1);
+ }
+ catch (IOException e)
+ {
+ //Error loading the default properties file, must exit
+ System.err.println("Error reading application properties file: " + PROPERTIES_FILE);
+ System.exit(-1);
+ }
+
+ String user_friend_data = queryFriendData(ME, FRIEND_ATTRIBUTES);
+ queryWallData(ME,WALL_ATTRIBUTES);
+
+ //Loop through the users wall data obtaining a json string from the resulting queries
+ // String user_wall_data = queryWallData(ME);
+
+ Gson friend_gson = new Gson();
+ Type friend_collectionType = new TypeToken<Collection<Friend>>(){}.getType();
+ Collection<Friend> friend_objs = friend_gson.fromJson(user_friend_data, friend_collectionType);
+
+ for (Friend f : friend_objs)
+ {
+ f.setConnectionsFrom(INITIAL_CONNECTIONS);
+ friends.put(f.getUid(), f);
+ }
+
+ // Lets loop over the messages and see who is writing to me :)
+ for (Message message : messages)
+ {
+ if (friends.containsKey(message.getActorId()))
+ {
+ Friend f = friends.get(message.getActorId());
+ f.setConnectionsFrom(1 + f.getConnectionsFrom());
+
+ //Update the friend object
+ friends.put(message.getActorId(), f);
+ }
+ else
+ {
+ int connections = 1;
+ if (unfriends.containsKey(message.getActorId()))
+ {
+ connections = unfriends.get(message.getActorId());
+ unfriends.put(message.getActorId(), ++connections);
+ }
+ else
+ {
+ unfriends.put(message.getActorId(), connections);
+ }
+ }
+ }
+ }
+
+ /**
+ * Build query string and return results from query results.
+ * @param uid to find friends from.
+ * @return
+ */
+ private String queryFriendData(final String uid, Collection<String> attributes)
+ {
+ StringBuilder str = new StringBuilder();
+ str.append(FQL_QUERY_STRING);
+ try
+ {
+ str.append(URLEncoder.encode("SELECT ", ENCODING));
+ Iterator<String> attribute_itr = attributes.iterator();
+
+ while (attribute_itr.hasNext())
+ {
+ String attribute = attribute_itr.next();
+ str.append(attribute);
+
+ //Cannot end with a comma
+ if (attribute_itr.hasNext())
+ {
+ str.append(URLEncoder.encode(",", ENCODING));
+ }
+ }
+ str.append(URLEncoder.encode(" FROM user WHERE uid IN ( SELECT uid2 FROM friend WHERE uid1=", ENCODING));
+ str.append(uid);
+ str.append(")");
+ str.append(ACCESS_TOKEN);
+ str.append(QUERY_FORMAT);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ }
+ return query(str.toString());
+ }
+
+ /**
+ * Generalized query method, pass a valid FQL string and get the results from the graph.
+ * @param query
+ * @return
+ */
+ private String query(final String query)
+ {
+ StringBuilder buf = new StringBuilder();
+ try
+ {
+ URL query_url = new URL(query);
+ BufferedReader in = new BufferedReader(new InputStreamReader(query_url.openStream()));
+
+ String inputLine;
+
+ while ((inputLine = in.readLine()) != null)
+ {
+ buf.append(inputLine);
+ }
+ in.close();
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Fetch all the posts from a users wall storing the results within the messages hashmap.
+ * @param uid
+ * @return
+ */
+ private void queryWallData(final String uid, final Collection<String> attributes)
+ {
+ StringBuilder query_str = new StringBuilder();
+ String created_time_query_piece = "";
+
+ Gson messages_gson = new Gson();
+ Type message_collectionType = new TypeToken<Collection<Message>>(){}.getType();
+
+ String results = "";
+ String created_time = "";
+ String old_created_time = "";
+
+ do
+ {
+ query_str.append(FQL_QUERY_STRING);
+ try
+ {
+ query_str.append(URLEncoder.encode("SELECT ", ENCODING));
+ Iterator<String> attribute_itr = attributes.iterator();
+
+ while (attribute_itr.hasNext())
+ {
+ String attribute = attribute_itr.next();
+ query_str.append(attribute);
+
+ //Cannot end with a comma
+ if (attribute_itr.hasNext())
+ {
+ query_str.append(URLEncoder.encode(",", ENCODING));
+ }
+ }
+ query_str.append(URLEncoder.encode(" FROM stream WHERE source_id=me() AND filter_key='others'",
+ ENCODING));
+ query_str.append(URLEncoder.encode(created_time_query_piece, ENCODING));
+ query_str.append(created_time);
+ query_str.append(URLEncoder.encode(" LIMIT 50", ENCODING));
+ query_str.append(ACCESS_TOKEN);
+ query_str.append(QUERY_FORMAT);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ }
+ results = query(query_str.toString());
+ if(results.trim() != "")
+ {
+ Collection<Message> message_objs = messages_gson.fromJson(results, message_collectionType);
+ messages.addAll(message_objs);
+
+ Collections.sort(messages, new MessageCreatedTimeComparator());
+ for(Message message : messages)
+ {
+ created_time = message.getCreatedTime();
+ created_time_query_piece = " AND created_time < ";
+ break;
+ }
+ }
+
+ if(created_time.equals(old_created_time))
+ {
+ created_time = "";
+ }
+
+
+ println("results=" + results);
+ println("created_time="+created_time);
+
+ old_created_time=created_time;
+
+ //Clean up the query string, we need to add the new created_time from the oldest received post.
+ query_str.delete(0, query_str.length());
+
+ } while(created_time != "");
+ }
+
+ public void draw()
+ {
+ background(0);
+
+ // Lets draw some squares for our friends
+ int squareSize = getTileSize(WIDTH - BORDER_OFFSET, HEIGHT - BORDER_OFFSET, friends.size() + unfriends.size());
+ Collection<Friend> friend_list = friends.values();
+
+ int x = 0;
+ int y = 0;
+
+ ArrayList<Friend> friends_sorted_by_wall_posts = new ArrayList<Friend>();
+ friends_sorted_by_wall_posts.addAll(friends.values());
+ Collections.sort(friends_sorted_by_wall_posts, new FriendWallPostCountComparator());
+
+ Iterator<Friend> friends_itr = friend_list.iterator();
+
+ outerloop: for (x = BORDER_OFFSET / 2; x + squareSize < HEIGHT - (BORDER_OFFSET / 2); x = x + squareSize)
+ {
+ for (y = BORDER_OFFSET / 2; y + squareSize < WIDTH - (BORDER_OFFSET / 2); y = y + squareSize)
+ {
+ // draw friend and increase the saturation as more connections
+ // are made.
+ if (friends_itr.hasNext())
+ {
+ Friend f = friends_itr.next();
+ if(f.getSex().equalsIgnoreCase("male"))
+ {
+ fill(MALE_FRIEND_COLOR, 20 * f.getConnectionsFrom(), 100);
+ }
+ else if(f.getSex().equalsIgnoreCase("female"))
+ {
+ fill(FEMALE_FRIEND_COLOR, 20 * f.getConnectionsFrom(), 100);
+ }
+ else
+ {
+ fill(OTHERSEX_FRIEND_COLOR, 0, Math.max(0,100 - (20 * f.getConnectionsFrom())));
+ }
+
+ rect(x, y, squareSize, squareSize);
+ }
+ else
+ {
+ break outerloop;
+ }
+ }
+ }
+
+ Set<String> unfriends_list = unfriends.keySet();
+ Iterator<String> unfriends_itr = unfriends_list.iterator();
+
+ // Draw rectangles for friends that are no longer friends
+ for (x = x + squareSize; x + squareSize < HEIGHT - (BORDER_OFFSET / 2); x = x + squareSize)
+ {
+ for (y = (BORDER_OFFSET / 2); y + squareSize < WIDTH - (BORDER_OFFSET / 2); y = y + squareSize)
+ {
+ // Draw unfriend and increase the saturation as more connections are made.
+ if (unfriends_itr.hasNext())
+ {
+ String unfriend_uid = unfriends_itr.next();
+ stroke(UNFRIEND_COLOR, 100, 100);
+ fill(UNFRIEND_COLOR, 20 * unfriends.get(unfriend_uid), 100);
+ rect(x, y, squareSize, squareSize);
+ }
+ }
+ }
+ }
+
+ public class FriendWallPostCountComparator implements Comparator<Friend>
+ {
+ @Override
+ public int compare(Friend o1, Friend o2)
+ {
+ return Integer.valueOf(o2.getWallCount()).compareTo(Integer.valueOf(o1.getWallCount()));
+ }
+ }
+
+ public class MessageCreatedTimeComparator implements Comparator<Message>
+ {
+ @Override
+ public int compare(Message o1, Message o2)
+ {
+ return o1.getCreatedTime().compareTo(o2.getCreatedTime());
+ }
+ }
+
+
+ int getTileSize(int width, int height, int tileCount)
+ {
+ // quick bailout for invalid input
+ if (width * height < tileCount)
+ {
+ return 0;
+ }
+
+ // come up with an initial guess
+ double aspect = (double) height / width;
+ double xf = Math.sqrt(tileCount / aspect);
+ double yf = xf * aspect;
+ int x = (int) Math.max(1.0, Math.floor(xf));
+ int y = (int) Math.max(1.0, Math.floor(yf));
+ int x_size = (int) Math.floor((double) width / x);
+ int y_size = (int) Math.floor((double) height / y);
+ int tileSize = (int) Math.min(x_size, y_size);
+
+ // test our guess:
+ x = (int) Math.floor((double) width / tileSize);
+ y = (int) Math.floor((double) height / tileSize);
+ if (x * y < tileCount) // we guessed too high
+ {
+ if (((x + 1) * y < tileCount) && (x * (y + 1) < tileCount))
+ {
+ // case 2: the upper bound is correct
+ // compute the tileSize that will
+ // result in (x+1)*(y+1) tiles
+ x_size = (int) Math.floor((double) width / (x + 1));
+ y_size = (int) Math.floor((double) height / (y + 1));
+ tileSize = (int) Math.min(x_size, y_size);
+ }
+ else
+ {
+ // case 3: solve an equation to determine
+ // the final x and y dimensions
+ // and then compute the tileSize
+ // that results in those dimensions
+ int test_x = (int) Math.ceil((double) tileCount / y);
+ int test_y = (int) Math.ceil((double) tileCount / x);
+ x_size = (int) Math.min(Math.floor((double) width / test_x), Math.floor((double) height / y));
+ y_size = (int) Math.min(Math.floor((double) width / x), Math.floor((double) height / test_y));
+ tileSize = (int) Math.max(x_size, y_size);
+ }
+ }
+
+ return tileSize;
+ }
+
+ /**
+ * Friend a container for Friend objects returned from FQL queries
+ */
+ public class Friend
+ {
+ private String name;
+
+ private String uid;
+
+ private String sex;
+
+ private String political;
+
+ private String relationship_status;
+
+ private String pic;
+
+ private String religion;
+
+ private int wall_count;
+
+ private int likes_count;
+
+ private int friend_count;
+
+ private int mutual_friend_count;
+
+ /*
+ * The total connections the user has made to me(), comment, like, tag, wall post etc.
+ */
+ private int connections_from;
+
+ @Override
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.append(uid);
+ str.append(" name=");
+ str.append(name);
+ str.append(",sex=");
+ str.append(sex);
+ return str.toString();
+ }
+
+ private ArrayList<String> friends;
+
+ public Friend()
+ {
+ connections_from = 0;
+ }
+
+ public void setConnectionsFrom(final int connections)
+ {
+ this.connections_from = connections;
+ }
+
+ public int getConnectionsFrom()
+ {
+ return connections_from;
+ }
+
+ public Friend(final String uid)
+ {
+ this.uid = uid;
+ }
+
+ public String getUid()
+ {
+ return this.uid;
+ }
+
+ public void setUid(final String uid)
+ {
+ this.uid = uid;
+ }
+
+ public String getRelationshipStatus()
+ {
+ return relationship_status;
+ }
+
+ public void setRelationshipStatus(String relationship_status)
+ {
+ this.relationship_status = relationship_status;
+ }
+
+ public String getPolitical()
+ {
+ return political;
+ }
+
+ public void setPolitical(String political)
+ {
+ this.political = political;
+ }
+
+ public String getSex()
+ {
+ return sex;
+ }
+
+ public void setSex(String sex)
+ {
+ this.sex = sex;
+ }
+
+ public ArrayList<String> getFriends()
+ {
+ return friends;
+ }
+
+ public void setFriends(ArrayList<String> friends)
+ {
+ this.friends = friends;
+ }
+
+ public String getPic()
+ {
+ return pic;
+ }
+
+ public void setPic(String pic)
+ {
+ this.pic = pic;
+ }
+
+ public String getReligion()
+ {
+ return religion;
+ }
+
+ public void setReligion(String religion)
+ {
+ this.religion = religion;
+ }
+
+ public int getWallCount()
+ {
+ return wall_count;
+ }
+
+ public void setWallCount(int wall_count)
+ {
+ this.wall_count = wall_count;
+ }
+
+ public int getLikesCount()
+ {
+ return likes_count;
+ }
+
+ public void setLikesCount(int likes_count)
+ {
+ this.likes_count = likes_count;
+ }
+
+ public int getFriendCount()
+ {
+ return friend_count;
+ }
+
+ public void setFriendCount(int friend_count)
+ {
+ this.friend_count = friend_count;
+ }
+
+ public int getMutualFriendCount()
+ {
+ return mutual_friend_count;
+ }
+
+ public void setMutualFriendCount(int mutual_friend_count)
+ {
+ this.mutual_friend_count = mutual_friend_count;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+ }
+
+ /*
+ xid string The external ID of the fb:comments being queried. You can specify more than one XID.
+ * object_id string The object_id of an object on Facebook. This can be a video, note, link, photo, or photo album. Note that for photos and albums, the object_id must be queried from the photo and album FQL tables. Note that in the photo and album tables, object_id is a different field from pid and aid. You must specify either an xid or an object_id.
+ * post_id string The ID of the post in the stream.
+ fromid int The user submitting a comment.
+ time int A Unix timestamp associated with the creation time of a comment.
+ text string The text of a comment.
+ id int A unique ID for a given XID for each comment.
+ username string The user name that a user entered when they posted a comment. In these cases, the fromid returned will be 0. Note that user names for valid users are not returned here.
+ reply_xid string The target XID for Feed stories generated by the user; applications can retrieve comments made to that story by calling this XID.
+ post_fbid string The object_id of this comment. This can be used for querying likes for this comment or replies to this comment if the comment came from the comments plugin.
+ app_id int The application id associated with this comment.
+ likes int The number of likes for this comment.
+ comments commentsThe replies to this comment.
+ can_like boolean If the current user is able to like this comment.
+ user_likes boolean If the current user liked this comment.
+ is_private boolean If this comment is private.
+ */
+ public class Comment
+ {
+ private String post_id;
+ private String time;
+ private int likes;
+ private String from_id;
+
+ public Comment(){}
+
+ public String getFromId()
+ {
+ return from_id;
+ }
+
+ public void setFromId(String from_id)
+ {
+ this.from_id = from_id;
+ }
+
+ public int getLikes()
+ {
+ return likes;
+ }
+
+ public void setLikes(int likes)
+ {
+ this.likes = likes;
+ }
+
+ public String getTime()
+ {
+ return time;
+ }
+
+ public void setTime(String time)
+ {
+ this.time = time;
+ }
+
+ public String getPostId()
+ {
+ return post_id;
+ }
+
+ public void setPostId(String post_id)
+ {
+ this.post_id = post_id;
+ }
+
+ }
+
+ /**
+ * Message a container for Message objects returned from FQL query
+ */
+ public class Message
+ {
+ private String post_id;
+
+ private String actor_id;
+
+ private String target_id;
+
+ private String message;
+
+ private String created_time;
+
+
+ public Message()
+ {
+ }
+
+ public Message(final String post_id, final String actor_id, final String target_id, final String message,
+ final String created_time)
+ {
+ this.post_id = post_id;
+ this.actor_id = actor_id;
+ this.target_id = target_id;
+ this.message = message;
+ this.created_time = created_time;
+ }
+
+ // Setters
+ public void setCreatedTime(final String ct)
+ {
+ this.created_time = ct;
+ }
+
+ public void setActorId(final String aid)
+ {
+ this.actor_id = aid;
+ }
+
+ public void setTargetId(final String tid)
+ {
+ this.target_id = tid;
+ }
+
+ public void setMessage(final String message)
+ {
+ this.message = message;
+ }
+
+ public void setPostId(final String pid)
+ {
+ this.post_id = pid;
+ }
+
+ // Getters
+ public String getPostId()
+ {
+ return this.post_id;
+ }
+
+ public String getCreatedTime()
+ {
+ return this.created_time;
+ }
+
+ public String getActorId()
+ {
+ return this.actor_id;
+ }
+
+ public String getTargetId()
+ {
+ return this.target_id;
+ }
+
+ public String getMessage()
+ {
+ return this.message;
+ }
+ }
+}

No commit comments for this range

Something went wrong with that request. Please try again.