七、Facebook

Facebook 是社交媒体世界里重达 900 磅(408.233 公斤)的大猩猩。 Facebook 是在大学宿舍里创建的,现在已经拥有 11 亿活跃用户。 这相当于地球上每七个人中就有一个。 至少可以说,它具有令人印象深刻的影响力。 任何一本关于使用社交媒体 API 的书,如果不调查如何使用 Facebook 的 API,都是不完整的。

创建应用

正如你可能期望的那样,这么大的站点,有许多 api 可用来构建与 Facebook 相关的应用。 最简单的方法是在网站或手机应用中集成“发布到 Facebook”按钮,而最复杂的方法是让你作为应用在 Facebook 的服务器上运行代码。

Graph API 提供了一种基于 http 的信息访问方法,Facebook 称之为社交图谱。 这个图表实际上只是不同用户和他们的数据之间的关系。 它是一个图,是节点和边的集合,而不是柱状图样式的图。

首先,我们将在 Facebook 上注册一个应用,就像我们在 Twitter 上所做的那样,如果我们想要使用身份验证,就必须使用 Stack Overflow。 为了做到这一点,我们将前往http://developers.facebook.com,并点击顶部菜单栏中的Apps链接。 点击创建新应用。 你会看到Create New App对话框,如下图所示:

Creating an app

应用名称可以是任何你喜欢的,应用名称空间用于给你的应用在 Facebook 上的位置,如apps.facebook.com/NiftyVisualization。 对于我们的目的来说,这在很大程度上是不必要的。 应用类别完全由你决定,应该根据你要可视化的内容来确定。 Heroku是与 Facebook 合作的云托管提供商,为 Facebook 应用提供托管空间。 如果你还没有托管服务,Heroku 是一个合理的选择,它支持 node.js; 然而,使用它超出了本书的范围。

一旦你填写了申请的详细信息,你将被要求通过解决一个验证码谜题来确认你是人类。 现在,您将被带到编辑页面,在这里您可以在测试对 API 的访问之前填写最后几个细节。 它看起来像以下截图:

Creating an app

在这里,您需要填写至少一个应用域。 当你登录时,API 会检查这个值,以确保你的应用是从一个授权域使用的。 不幸的是,你不能从一个非来自域名的文件访问 Facebook 的 Graph API。 这意味着仅仅进入file://c:/code/visualization.html将不允许你访问 Facebook 的 API。 幸运的是,并不是所有的都丢失了,使用localhost是允许的,但这意味着我们必须运行一个 HTTP 服务器。 我们可以使用前面章节中使用的相同的Node.js安装。

网站 URL 在的网站与 Facebook 登录应该设置为您的 OAuth 密钥交换的返回 URL。 我们可以把它设为任何值因为我们要用 AJAX 进行身份验证,用户永远不会离开初始页面。

使用 API

完全有可能手动执行 OAuth 验证和授权您的可视化与 Facebook。 然而,Facebook 已经提供了一个非常有用的 JavaScript SDK。 API 将登录过程抽象为一个函数调用。 为了使用 API,我们首先需要在可视化中包含它。 要做到这一点,只需在你的script标签中包含以下脚本:

(function(d){
  var js;
  var id = 'facebook-jssdk';
  var ref = d.getElementsByTagName('script')[0];
  if (d.getElementById(id)) {return;}
  js = d.createElement('script'); js.id = id; js.async = true;
  js.src = "//connect.facebook.net/en_US/all.js";
  ref.parentNode.insertBefore(js, ref);
}(document));

这段代码将在您的文档中创建一个新的script标签,并将其源代码设置为 Facebook 网站上的一个文件。 添加这样的script标签将导致浏览器加载脚本文件的内容并执行它。 因为我们是以异步方式加载脚本的,所以在使用它之前,我们需要等待它被加载。 一旦初始化,SDK 就会调用一个钩子fbAsyncInit。 我们只需要将一个函数绑定到该钩子上,如下面的代码所示:

window.fbAsyncInit = function() {
  FB.init({
  appId      : '525498574499442', 
  channelUrl : '//localhost:8080/channel', 
  status     : true, 
  cookie     : true, 
  xfbml      : true  // parse XFBML
  });
};

这将为 SDK 提供可从开发者网页获得的 App ID。 此外,我在这里提供了channelUrl,用于解决一些浏览器上出现的跨域问题。 设置状态时,init方法将获取status的值。 cookie将启用 cookie 支持。 最后xfbml支持 Facebook 标记语言。 那是什么? 它是一个特殊格式的 HTML 元素的集合,由 Facebook SDK 控制。

例如,如果我们想显示一个登录按钮(多么方便,我们确实想显示一个登录按钮),那么我们可以简单地添加以下代码:

<fb:login-button show-faces="true" width="200" max-rows="1"scope="user_birthday,email,friends_birthday">
</fb:login-button>

当未经身份验证的用户打开页面时,将显示一个登录按钮。 当经过身份验证的用户到达该页面时,将显示他们自己的登录信息。 你会注意到scope属性; 这是用来给 Facebook 一个权限列表,你正在请求。 这里我们询问了登录用户的生日、电子邮件 ID 和他们朋友的生日。 当用户登录时,Facebook 会提示用户允许可视化访问该权限。 Facebook 有大约 30 种不同的权限可以请求,这些权限控制着从检索登录用户的信息到他们的朋友、事件和回复。 在这里很值得探索,以发现有趣的方面来形象化。

认证难题的最后一部分是提供一个函数,让登录按钮在用户登录后调用:

FB.Event.subscribe('auth.authResponseChange', function(response) {
  if (response.status === 'connected') {
    //use SDK here
  } else if (response.status === 'not_authorized') {//not authorized
    FB.login({scope: "user_birthday,email,friends_birthday"});
  } else { //not logged in
    FB.login({scope: "user_birthday,email,friends_birthday"});
  }
});

每当授权响应发生更改时,例如当我们从登录按钮获得身份验证时,就会触发此事件。

数据检索

在我们开始检索数据之前,我们可能应该决定我们希望可视化哪些数据。 关于登录用户的数据量并不是那么多(至少对我来说不是,但我很少使用 Facebook)。 那就只能看我们的朋友了。 我发现我朋友用来访问 Facebook 的设备非常有趣。 他们是 Android 用户还是 iOS 用户? 这些信息是朋友收集的一部分。 为了检索这些信息,我们可以使用FB.api()方法:

FB.api('/me?fields=friends.fields(devices)', function(response){
  for(i = 0; len = response.friends.data.length; i< len; i++){
    var friend = response.friends.data[i];
    if(friend.devices)
      for(j = 0; j< friend.devices.length; j++)
    if(friend.devices[j].hardware != "iPad")
      operatingSystems[friend.devices[j].os]++;
  }
});

api()方法中,我们传递一个要检索的 URL。 在这种情况下,我们请求特殊的 URL/me,这是指当前登录的用户。 我们还提供了一个过滤器,以便只检索朋友的集合,实际上,每个朋友只检索设备的集合。 在回调中,我们只是在计算 Android 设备和 iOS 设备的数量。 ipad 和 iphone 是 Facebook 的独立设备,但我们不想把 iOS 算作两次访问方法,所以我们忽略了任何 ipad。 一旦执行这段代码,我们就会得到一个设备计数的集合。 对于我的朋友们,我得到了以下几点:

{Android: 28, iOS: 36}

可视化

更有效的可视化技术之一是通过显示缩放图像来显示不同类别的相对优势。 我们在 Twitter 一章中用了气泡技术。 我们可以通过使用图像而不仅仅是圆圈来进行下一步。

第一步是定位已经是 svg 的 Android 和 iOS logo。 事实证明,维基百科是一个很好的资源,他们的图片都是在知识共享协议下许可的,这意味着我们可以在可视化中使用它们。 SVG 的一个真正伟大的特性是,您可以通过使用定义轻松地将两个图像合并在一起。 如果你在http://upload.wikimedia.org/wikipedia/commons/e/e1/Android_dance.svg上打开一个 SVG 图标,你可以复制<defs>标签下的所有标记到另一个图像中。 我把安卓和苹果的标志移到原始标记中。 如果我想显示它们,我可以使用<use> 标签并根据 ID 引用定义。 它看起来像下面的代码:

<defs>
  <g id="appleLogo">
    <!--various shapes needed to build the Apple logo-->
  </g>
  <g id="androidLogo">
    <!--various shapes needed to build the Android logo-->
  </g>

</defs>
<use x="0" y="10" xlink:href="#appleLogo"/>
<use x="512" y="10" xlink:href="#androidLogo" />

这将在 SVG 中创建一个 Android logo 旁边的苹果 logo。 我们知道我们可以利用d3来创建和缩放 logo,我们很幸运,因为我们拥有的两个 svg 都是 256 像素的正方形,所以在我们翻译它们之前,它们看起来几乎是相同的大小。 d3比较简单,代码如下:

var visualization = d3.select("#visualization");
visualization.selectAll(".logo").data(operatingSystems)
.enter().append("use")
.attr("xlink:href", function(item){ return "#" + item.os + "Logo";})
.attr("transform", function(item, index){
  return "translate("  + 300 * index + " 0),scale(" + (item.users / operatingSystems[0].users) + ")";
});

我们首先选择 SVG,然后使用语句而不是附加形状。 xlink:href属性接受要包含的定义的值。 接下来,我们缩放和翻译的标志,使他们彼此相邻和适当的大小。 我们将第一个 logo 设置为基线大小,然后绘制每个后续 logo 的百分比。 这只是因为我们的数字相当接近。 对于高度分化的数字,需要一种更稳健的策略。 加上一些附加的文本元素,结果如下图所示:

Visualizing

小结

现在您应该已经掌握了如何使用 Facebook API 来检索数据。 然后可以使用任何技术将这些数据可视化。 在下一章中,我们将着眼于新兴的 Google+社交网络,并看看我们如何利用那里的数据进行可视化。