You've been tagged

This is a toy script that allows one to visualize how Twitter users view people they follow.

We extract terms from lists in which a given Twitter user is included, and create a tag cloud based on that information. Try it below!


Raw Data

Handy Links

Lemmatica Wordics -- this is what I use to generate the colored cloud

My Tweet Cloud -- A service that examines your tweets and constructs a cloud of your favorite hashtags

Wordle -- Way cool-looking clouds. Requires Java, though.


Some folks may be curious how this is done; it is pretty simple, really, just an hour of tinkering with Perl.

use strict;
use warnings;
use CGI;
use JSON;
use Data::Dumper;
use LWP::UserAgent::WithCache;
use Cache::FileCache;
use HTTP::Response;
use HTML::TagCloud;

my $cgi = CGI->new();
my $cache = new Cache::FileCache(
{ 'cache_root'=>File::Spec->catfile(File::HomeDir->my_home, '.cache'),
'namespace'=>'lwp-cache' } );
my $ua = LWP::UserAgent::WithCache->new({'namespace'=>'lwp-cache',
$ua->credentials("", "Twitter API", $uname, $pass);

my $stopwords = init_stopwords();
my $url = '<uname>/lists/memberships.json';
my $username = $cgi->param('uname');
$url =~ s/<uname>/$username/;
my %tag_cnts;

my ($cursor, $iter) = (0,0);
do {
my $cursor_url = $url.( $cursor ? "?cursor=$cursor" : "");

# WithCache is supposed to do this but it isn't. So doing it by hand.
my $cached = $cache->get($cursor_url);
my $resp;
if (defined $cached) {
$resp = HTTP::Response->parse($cached->{as_string});
} else {
$resp = $ua->get($cursor_url);

if (!$resp->is_success()) {
exit(write_cloud($cgi, {})) if ($resp->code == 404);
print STDERR "error on fetching $cursor_url\n".
$resp->status_line, "\n";
my $cont = from_json($resp->content);
my @tags;
push(@tags, get_tags($_->{name})) foreach @{$cont->{lists}};
$tag_cnts{$_} += 1 foreach @tags;
$cursor = $cont->{next_cursor};
} while ($cursor != 0 && ++$iter < 20);

write_cloud($cgi, \%tag_cnts);

sub get_tags {
return grep { !$stopwords->{$_} } split(/[_\+\-\s]/, lc($_[0])), lc($_[0]);

sub write_cloud {
my ($cgi, $tag_cnts) = @_;
my $fmt = $cgi->param('fmt') || 'html';
if ($fmt eq 'html') {
my $cloud = HTML::TagCloud->new();
$cloud->add($_, "".$_, $tag_cnts{$_}) foreach keys %$tag_cnts;
print $cgi->header(-type=>'text/html', -expires=>'+2d');
print $cloud->html_and_css(20);
} elsif ($fmt eq 'txt') {
print $cgi->header(-type=>'text/plan', -expires=>'+2d');
while (my ($tag, $cnt) = each %$tag_cnts) {
print $tag.' ' foreach (1..$cnt);
print "\n";
} elsif ($fmt eq 'json') {
print $cgi->header(-type=>'application/json', -expires=>'+2d');
print to_json($tag_cnts);

sub error {
print $cgi->header(-status=>"500 Internal Server Error");
return 1;

sub init_stopwords {
return { 'a'=>1,'the'=>1,'of'=>1,'an'=>1, 'and'=>1,
'in'=>1,'as'=>1,'conversationlist'=>1, 'twibes'=>1,