<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>OUseful.Info, the blog... &#187; Visualising Twitter User Timeline Activity in R</title>
	<atom:link href="http://blog.ouseful.info/2012/02/17/visualising-twitter-user-timeline-activity-in-r/feed/?withoutcomments=1" rel="self" type="application/rss+xml" />
	<link>http://blog.ouseful.info</link>
	<description>Trying to find useful things to do with emerging technologies in open education</description>
	<lastBuildDate>Tue, 21 May 2013 02:48:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='blog.ouseful.info' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>OUseful.Info, the blog... &#187; Visualising Twitter User Timeline Activity in R</title>
		<link>http://blog.ouseful.info</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.ouseful.info/osd.xml" title="OUseful.Info, the blog..." />
	<atom:link rel='hub' href='http://blog.ouseful.info/?pushpress=hub'/>
		<item>
		<title>Visualising Twitter User Timeline Activity in R</title>
		<link>http://blog.ouseful.info/2012/02/17/visualising-twitter-user-timeline-activity-in-r/</link>
		<comments>http://blog.ouseful.info/2012/02/17/visualising-twitter-user-timeline-activity-in-r/#comments</comments>
		<pubDate>Fri, 17 Feb 2012 15:26:15 +0000</pubDate>
		<dc:creator>Tony Hirst</dc:creator>
				<category><![CDATA[Rstats]]></category>

		<guid isPermaLink="false">http://blog.ouseful.info/?p=7098</guid>
		<description><![CDATA[I&#8217;ve largely avoided &#8220;time&#8221; in R to date, but following a chat with @mhawksey at #dev8d yesterday, I went down a rathole last night exploring a few ways of visualising a Twitter user timeline. As a result, I also had a quick initial play with some time handling features of R, such as timeseries objects, [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.ouseful.info&#038;blog=325417&#038;post=7098&#038;subd=ouseful&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve largely avoided &#8220;time&#8221; in R to date, but following a chat with @mhawksey at #dev8d yesterday, I went down a rathole last night exploring a few ways of visualising a Twitter user timeline. As a result, I also had a quick initial play with some time handling features of R, such as timeseries objects, as well as a go at generating daily, weekly and monthly summary counts of data values.</p>
<p>To start, let&#8217;s grab a user timeline. As Martin started it (?!), we&#8217;ll use his&#8230;;-)</p>
<pre class="brush: r; title: ; notranslate">require(twitteR)
username='TWITTERUSERNAME'
#the most tweets we can bring back from a user timeline is the most recent 3600...
mht=userTimeline(username,n=3200)
tw.df=twListToDF(mht)

#As I've done in previous scripts, pull out the names of folk who have been &quot;old-fashioned RTd&quot;...
require(stringr)
trim &lt;- function (x) sub('@','',x)

tw.df$rt=sapply(tw.df$text,function(tweet) trim(str_match(tweet,&quot;^RT (@[[:alnum:]_]*)&quot;)[2]))
tw.df$rtt=sapply(tw.df$rt,function(rt) if (is.na(rt)) 'T' else 'RT')
</pre>
<p>The returned data includes a <em>created</em> attribute (of the form &#8220;2012-02-17 11:40:25&#8243;) and a <em>replyToSN</em> attribute that includes the username of a user Martin was replying to via a particular tweet.</p>
<p>The simplest way I can think of displaying the data is to just display the <em>screenName</em> atrribute of the sender (which in this case is always <em>mhawskey</em>) against time:</p>
<pre class="brush: r; title: ; notranslate">require(ggplot2)
ggplot(tw.df)+geom_point(aes(x=created,y=screenName))</pre>
<p><a href="http://ouseful.files.wordpress.com/2012/02/simpleusertimeline.png"><img src="http://ouseful.files.wordpress.com/2012/02/simpleusertimeline.png?w=700" alt="" title="simpleUserTimeline"   class="alignnone size-full wp-image-7099" /></a></p>
<p>As ever, things are never that simple&#8230; some tweets with old dates appear to have crept in somehow&#8230; A couple of things I tried realting to time based filtering caused R to have all sorts of malloc errors, so here&#8217;s a fudge I found to just display tweets that were created within the last 8,000 hours&#8230;</p>
<pre class="brush: r; title: ; notranslate">tw.dfs=subset(tw.df,subset=((Sys.time()-created)&lt;8000))
ggplot(tw.dfs)+geom_point(aes(x=created,y=screenName))</pre>
<p><a href="http://ouseful.files.wordpress.com/2012/02/twusertimelinelimited.png"><img src="http://ouseful.files.wordpress.com/2012/02/twusertimelinelimited.png?w=700" alt="" title="twUserTimelineLimited"   class="alignnone size-full wp-image-7100" /></a></p>
<p>Okay, so not very interesting&#8230; It shows that Martin tweets&#8230;</p>
<p>Picking up on views of the style doodled in <a href="http://blog.ouseful.info/2012/02/06/visualising-activity-round-a-twitter-hashtag-or-search-term-using-r/">Visualising Activity Around a Twitter Hashtag or Search Term Using R</a>, where we look at when new users appear in a hashtag stream, we can plot when Martin replies to another twitter user, arranging the user names in the order in which they were first publicly replied to:</p>
<pre class="brush: r; title: ; notranslate">require(plyr)
#Order the replyToSN factor levels in the order in which they were first created
tw.dfx=ddply(tw.dfs, .var = &quot;replyToSN&quot;, .fun = function(x) {return(subset(x, created %in% min(created),select=c(replyToSN,created)))})
tw.dfxa=arrange(tw.dfx,-desc(created))
tw.dfs$replyToSN=factor(tw.dfs$replyToSN, levels = tw.dfxa$replyToSN)

#and plot the result
ggplot(tw.dfs)+geom_point(aes(x=created,y=replyToSN))</pre>
<p><a href="http://ouseful.files.wordpress.com/2012/02/usertimelinereplies.png"><img src="http://ouseful.files.wordpress.com/2012/02/usertimelinereplies.png?w=700" alt="" title="userTimelineReplies"   class="alignnone size-full wp-image-7101" /></a></p>
<p>The line at the top are tweets where the replyToSN value was NA (not available).</p>
<p>We can then go a little further and plot when folk are replied to or retweeted, as well as tweets that are neither a reply nor an old-style retweet:</p>
<pre class="brush: r; title: ; notranslate">ggplot()+geom_point(data=subset(tw.dfs,subset=(!is.na(replyToSN))),aes(x=created,y=replyToSN),col='red') + geom_point(data=subset(tw.dfs,subset=(!is.na(rt))),aes(x=created,y=rt),col='blue') + geom_point(data=subset(tw.dfs,subset=(is.na(replyToSN) &amp; is.na(rt))),aes(x=created,y=screenName),col='green')</pre>
<p><a href="http://ouseful.files.wordpress.com/2012/02/usertimelinertandreply.png"><img src="http://ouseful.files.wordpress.com/2012/02/usertimelinertandreply.png?w=700" alt="" title="userTimeLineRTandReply"   class="alignnone size-full wp-image-7102" /></a></p>
<p>Here, the blue dots are old-style retweets, the red dots are replies, and the green dots are tweets that are neither replies nor old-style retweets. If a blue dot appears on a row before a red dot, it shows Martin RT&#8217;d them before ever replying to them. If blue dots are on a row that contains no red dot, then it shows Martin has RT&#8217;d but not replied to that person. A heavily populated row shows Martin has repeated interactions with that user.</p>
<p>We can generate an ordered bar chart showing who is most heavily replied to:</p>
<pre class="brush: r; title: ; notranslate">#First we need to count how many replies a user gets...
#http://stackoverflow.com/a/3255448/454773
r_table &lt;- table(tw.dfs$replyToSN)
#..rank them...
r_levels &lt;- names(r_table)[order(-r_table)]
#..and use this ordering to order the factor levels...
tw.dfs$replyToSN &lt;- factor(tw.dfs$replyToSN, levels = r_levels) 

#Then we can plot the chart...
ggplot(subset(tw.dfs,subset=(!is.na(replyToSN))),aes(x=replyToSN)) + geom_bar(aes(y = (..count..)))+opts(axis.text.x=theme_text(angle=-90,size=6))
</pre>
<p><a href="http://ouseful.files.wordpress.com/2012/02/repliesbarplot.png"><img src="http://ouseful.files.wordpress.com/2012/02/repliesbarplot.png?w=700" alt="" title="repliesBarplot"   class="alignnone size-full wp-image-7104" /></a></p>
<p>(Hmmm&#8230; how would I filter this to only show folk replied to more than 50 times, for example? [UPDATE: here's a partial, related recipe: ****BUT IT SEEMS TO BE BROKEN AND I CAN"T SEE HOW TO FIX IT ATM...<br />
<tt>require(gdata)<br />
tt=as.data.frame(table(tw.dfs$replyToSN))<br />
#Filter to retain users with Freq above some threshold, then drop spare levels<br />
tts=drop.levels(subset(tt,subset=(Freq&gt;5)))<br />
ggplot(tts)+geom_bar(stat='identity',aes(x=Var1,y=Freq))</tt><br />
Note that the order of the factors needs rearranging. Something like this maybe?</p>
<pre>orderLevels=function(dfc.name,dfc.val){
  factor(dfc.name, levels = reorder(dfc.name,dfc.val))
}</pre>
<p>then:<br />
<tt>tts$Var1=orderLevels(tts$Var1,tts$Freq)<br />
ggplot(tts)+geom_bar(stat='identity',aes(x=Var1,y=Freq))</tt><br />
Taking the simplification (?!) further:</p>
<pre>orderedSubset=function(dfc,min=5){
  require(gdata)
  tmp1=as.data.frame(table(dfc))
  tmp2=drop.levels(subset(tmp1,subset=(Freq&gt;=min)))
  tmp2$Var1=factor(tmp2$Var1, levels = reorder(tmp2$Var1,tmp2$Freq))
  tmp2
}
ggplot(orderedSubset(tw.dfs$replyToSN))+geom_bar(stat='identity',aes(x=Var1,y=Freq))
ggplot(orderedSubset(tw.dfs$replyToSN,50))+geom_bar(stat='identity',aes(x=Var1,y=Freq))
</pre>
<p>..or even further...</p>
<pre>plotOrderedSubset=function(dfc,min=5){
  ggplot(orderedSubset(dfc,min))+geom_bar(stat='identity',aes(x=Var1,y=Freq))
}
plotOrderedSubset(tw.dfs$replyToSN)
plotOrderedSubset(tw.dfs$replyToSN,20)</pre>
<p>])</p>
<p>Sometimes, a text view is easier&#8230; </p>
<pre class="brush: r; title: ; notranslate">head(table(tw.dfs$replyToSN))
#eg returns:
#psychemedia        wilm     ambrouk    sheilmcn  dajbelshaw  manmalik 
        394          66          59          53          48        43     
#Hmm..can we generalise this?
topTastic=function(dfc,num=5){
  r_table &lt;- table(dfc)
  r_levels &lt;- names(r_table)[order(-r_table)]
  head(table(factor(dfc, levels = r_levels)),num)
}
#so now, for example, I should be able to display the most old-style retweeted folk?
topTastic(tw.dfs$rt)
#or the 10 most replied to...
topTastic(tw.dfs$replyToSN,10)</pre>
<p>Let&#8217;s try some time stuff now&#8230; From the <a href="http://www.amazon.co.uk/Cookbook-OReilly-Cookbooks-Paul-Teetor/dp/0596809158/?tag=ouseful-21">R Cookbook</a>, I find I can do this:</p>
<pre class="brush: r; title: ; notranslate">#label a tweet with the month number
tw.dfs$month=sapply(tw.dfs$created, function(x) {p=as.POSIXlt(x);p$mon})
#label a tweet with the hour
tw.dfs$hour=sapply(tw.dfs$created, function(x) {p=as.POSIXlt(x);p$hour})
#label a tweet with a number corresponding to the day of the week
tw.dfs$wday=sapply(tw.dfs$created, function(x) {p=as.POSIXlt(x);p$wday})</pre>
<p>What this means is we can now chart a count of the number of tweets by day, week, or hour&#8230; For example, here&#8217;s hour vs. day of the week:</p>
<pre class="brush: r; title: ; notranslate">ggplot(tw.dfs)+geom_jitter(aes(x=wday,y=hour))</pre>
<p><a href="http://ouseful.files.wordpress.com/2012/02/tweetdistro_hourvweek.png"><img src="http://ouseful.files.wordpress.com/2012/02/tweetdistro_hourvweek.png?w=700" alt="" title="tweetDistro_hourVweek"   class="alignnone size-full wp-image-7108" /></a></p>
<p>Note that this jittered scattergraph, where each dot is a tweet, only approximates the time each tweet occurred &#8211; the jitter applied is a random quantity designed to separate out tweets posted within the same hour-and-day-of-the-week bin.</p>
<p>What about Martin&#8217;s tweeting behaviour over time?</p>
<pre class="brush: r; title: ; notranslate">#We can also generate barplots showing the distribution of tweet count over time:
ggplot(tw.dfs,aes(x=created))+geom_bar(aes(y = (..count..)))
#Hmm... I'm not sure how to manually set binwidth= sensibly, though?!
</pre>
<p>Here&#8217;s a plot of the number of counts per&#8230; <em>I&#8217;m not sure</em>: the bin width was calculated automatically&#8230;</p>
<p><a href="http://ouseful.files.wordpress.com/2012/02/twovertime.png"><img src="http://ouseful.files.wordpress.com/2012/02/twovertime.png?w=700" alt="" title="twOverTime"   class="alignnone size-full wp-image-7109" /></a></p>
<p>How about using the number of tweets in a particular day or hour bin to see what times of day or days of week Martin is tweeting?</p>
<pre class="brush: r; title: ; notranslate">#We can also plot the number of tweets within particular hour or time bins...
ggplot(tw.dfs,aes(x=wday))+geom_bar(aes(y = (..count..)),binwidth=1)
ggplot(tw.dfs,aes(x=hour))+geom_bar(aes(y = (..count..)),binwidth=1)
</pre>
<p>This chart shows activity (in terms of count&#8230;) per hour of day.</p>
<p><a href="http://ouseful.files.wordpress.com/2012/02/twperhourofday.png"><img src="http://ouseful.files.wordpress.com/2012/02/twperhourofday.png?w=700" alt="" title="twPerHourOfDay"   class="alignnone size-full wp-image-7110" /></a></p>
<p>As well as doing the count of tweets per hour, for example, via a ggplot statistical graphical function, we can also get day, week, month, quarter and year counts from a set of functions associated with a particular sort of timeseries object&#8230;</p>
<p>Each element in a time series typically has two elements &#8211; a timestamp, and a numeric value. We can generate a time series of a sort around a twitter usertimeline by creating a dummy quantity &#8211; such as the unit value, 1 &#8211; and associate it with each timestamp:</p>
<pre class="brush: r; title: ; notranslate">require(xts)
#The xts function creates a timeline from a vector of values and a vector of timestamps.
#If we know how many tweets we have, we can just create a simple list or vector containing that number of 1s
ts=xts(rep(1,times=nrow(tw.dfs)),tw.dfs$created)

#We can now do some handy number crunching on the timeseries, such as applying a formula to values contained with day, week, month, quarter or year time bins.
#So for example, if we sum the unit values in daily bin, we can get a count of the number of tweets per day
ts.sum=apply.daily(ts,sum) 
#also apply. weekly, monthly, quarterly, yearly

#If for any resason we need to turn the timeseries into a dataframe, we can:
#http://stackoverflow.com/a/3387259/454773
ts.sum.df=data.frame(date=index(ts.sum), coredata(ts.sum))

colnames(ts.sum.df)=c('date','sum')

#We can then use ggplot to plot the timeseries...
ggplot(ts.sum.df)+geom_line(aes(x=date,y=sum))</pre>
<p><a href="http://ouseful.files.wordpress.com/2012/02/twtimeseries.png"><img src="http://ouseful.files.wordpress.com/2012/02/twtimeseries.png?w=700" alt="" title="twTimeSeries"   class="alignnone size-full wp-image-7112" /></a></p>
<pre class="brush: r; title: ; notranslate">#Having got the data in a timeseries form, we can do timeseries based things to it... such as checking the autocorrelation:
acf(ts.sum)</pre>
<p><a href="http://ouseful.files.wordpress.com/2012/02/twautocorrelation.png"><img src="http://ouseful.files.wordpress.com/2012/02/twautocorrelation.png?w=700" alt="" title="twAutocorrelation"   class="alignnone size-full wp-image-7113" /></a></p>
<p>Hmmm.. so, one day is much the same as another, but there also appears to be a weekly (7 day periodicity) pattern&#8230;</p>
<p>Finally, here&#8217;s a handy script I found on the Revolution Analytics site for <a href="http://blog.revolutionanalytics.com/2009/11/charting-time-series-as-calendar-heat-maps-in-r.html">Charting time series as calendar heat maps in R</a>:</p>
<pre class="brush: r; title: ; notranslate">##############################################################################
 #                        Calendar Heatmap                                    #
 #                                by                                          #
 #                         Paul Bleicher                                      #
 # an R version of a graphic from:                                            #
 # http://stat-computing.org/dataexpo/2009/posters/wicklin-allison.pdf        #
 #  requires lattice, chron, grid packages                                    #
 ############################################################################## 

## calendarHeat: An R function to display time-series data as a calendar heatmap 
## Copyright 2009 Humedica. All rights reserved.

## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.

## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.

## You can find a copy of the GNU General Public License, Version 2 at:
## http://www.gnu.org/licenses/gpl-2.0.html

calendarHeat &lt;- function(dates, 
                         values, 
                         ncolors=99, 
                         color=&quot;r2g&quot;, 
                         varname=&quot;Values&quot;,
                         date.form = &quot;%Y-%m-%d&quot;, ...) {
require(lattice)
require(grid)
require(chron)
if (class(dates) == &quot;character&quot; | class(dates) == &quot;factor&quot; ) {
  dates &lt;- strptime(dates, date.form)
        }
caldat &lt;- data.frame(value = values, dates = dates)
min.date &lt;- as.Date(paste(format(min(dates), &quot;%Y&quot;),
                    &quot;-1-1&quot;,sep = &quot;&quot;))
max.date &lt;- as.Date(paste(format(max(dates), &quot;%Y&quot;),
                     &quot;-12-31&quot;, sep = &quot;&quot;))
dates.f &lt;- data.frame(date.seq = seq(min.date, max.date, by=&quot;days&quot;))

# Merge moves data by one day, avoid
caldat &lt;- data.frame(date.seq = seq(min.date, max.date, by=&quot;days&quot;), value = NA)
dates &lt;- as.Date(dates) 
caldat$value[match(dates, caldat$date.seq)] &lt;- values

caldat$dotw &lt;- as.numeric(format(caldat$date.seq, &quot;%w&quot;))
caldat$woty &lt;- as.numeric(format(caldat$date.seq, &quot;%U&quot;)) + 1
caldat$yr &lt;- as.factor(format(caldat$date.seq, &quot;%Y&quot;))
caldat$month &lt;- as.numeric(format(caldat$date.seq, &quot;%m&quot;))
yrs &lt;- as.character(unique(caldat$yr))
d.loc &lt;- as.numeric()                        
for (m in min(yrs):max(yrs)) {
  d.subset &lt;- which(caldat$yr == m)  
  sub.seq &lt;- seq(1,length(d.subset))
  d.loc &lt;- c(d.loc, sub.seq)
  }  
caldat &lt;- cbind(caldat, seq=d.loc)

#color styles
r2b &lt;- c(&quot;#0571B0&quot;, &quot;#92C5DE&quot;, &quot;#F7F7F7&quot;, &quot;#F4A582&quot;, &quot;#CA0020&quot;) #red to blue                                                                               
r2g &lt;- c(&quot;#D61818&quot;, &quot;#FFAE63&quot;, &quot;#FFFFBD&quot;, &quot;#B5E384&quot;)   #red to green
w2b &lt;- c(&quot;#045A8D&quot;, &quot;#2B8CBE&quot;, &quot;#74A9CF&quot;, &quot;#BDC9E1&quot;, &quot;#F1EEF6&quot;)   #white to blue
            
assign(&quot;col.sty&quot;, get(color))
calendar.pal &lt;- colorRampPalette((col.sty), space = &quot;Lab&quot;)
def.theme &lt;- lattice.getOption(&quot;default.theme&quot;)
cal.theme &lt;-
   function() {  
  theme &lt;-
  list(
    strip.background = list(col = &quot;transparent&quot;),
    strip.border = list(col = &quot;transparent&quot;),
    axis.line = list(col=&quot;transparent&quot;),
    par.strip.text=list(cex=0.8))
    }
lattice.options(default.theme = cal.theme)
yrs &lt;- (unique(caldat$yr))
nyr &lt;- length(yrs)
print(cal.plot &lt;- levelplot(value~woty*dotw | yr, data=caldat,
   as.table=TRUE,
   aspect=.12,
 layout = c(1, nyr%%7),
   between = list(x=0, y=c(1,1)),
   strip=TRUE,
   main = paste(&quot;Calendar Heat Map of &quot;, varname, sep = &quot;&quot;),
   scales = list(
     x = list(
               at= c(seq(2.9, 52, by=4.42)),
               labels = month.abb,
               alternating = c(1, rep(0, (nyr-1))),
               tck=0,
               cex = 0.7),
     y=list(
          at = c(0, 1, 2, 3, 4, 5, 6),
          labels = c(&quot;Sunday&quot;, &quot;Monday&quot;, &quot;Tuesday&quot;, &quot;Wednesday&quot;, &quot;Thursday&quot;,
                      &quot;Friday&quot;, &quot;Saturday&quot;),
          alternating = 1,
          cex = 0.6,
          tck=0)),
   xlim =c(0.4, 54.6),
   ylim=c(6.6,-0.6),
   cuts= ncolors - 1,
   col.regions = (calendar.pal(ncolors)),
   xlab=&quot;&quot; ,
   ylab=&quot;&quot;,
   colorkey= list(col = calendar.pal(ncolors), width = 0.6, height = 0.5),
   subscripts=TRUE
    ) )
panel.locs &lt;- trellis.currentLayout()
for (row in 1:nrow(panel.locs)) {
    for (column in 1:ncol(panel.locs))  {
    if (panel.locs[row, column] &gt; 0)
{
    trellis.focus(&quot;panel&quot;, row = row, column = column,
                  highlight = FALSE)
xyetc &lt;- trellis.panelArgs()
subs &lt;- caldat[xyetc$subscripts,]
dates.fsubs &lt;- caldat[caldat$yr == unique(subs$yr),]
y.start &lt;- dates.fsubs$dotw[1]
y.end   &lt;- dates.fsubs$dotw[nrow(dates.fsubs)]
dates.len &lt;- nrow(dates.fsubs)
adj.start &lt;- dates.fsubs$woty[1]

for (k in 0:6) {
 if (k &lt; y.start) {
    x.start &lt;- adj.start + 0.5
    } else {
    x.start &lt;- adj.start - 0.5
      }
  if (k &gt; y.end) {
     x.finis &lt;- dates.fsubs$woty[nrow(dates.fsubs)] - 0.5
    } else {
     x.finis &lt;- dates.fsubs$woty[nrow(dates.fsubs)] + 0.5
      }
    grid.lines(x = c(x.start, x.finis), y = c(k -0.5, k - 0.5), 
     default.units = &quot;native&quot;, gp=gpar(col = &quot;grey&quot;, lwd = 1))
     }
if (adj.start &lt;  2) {
 grid.lines(x = c( 0.5,  0.5), y = c(6.5, y.start-0.5), 
      default.units = &quot;native&quot;, gp=gpar(col = &quot;grey&quot;, lwd = 1))
 grid.lines(x = c(1.5, 1.5), y = c(6.5, -0.5), default.units = &quot;native&quot;,
      gp=gpar(col = &quot;grey&quot;, lwd = 1))
 grid.lines(x = c(x.finis, x.finis), 
      y = c(dates.fsubs$dotw[dates.len] -0.5, -0.5), default.units = &quot;native&quot;,
      gp=gpar(col = &quot;grey&quot;, lwd = 1))
 if (dates.fsubs$dotw[dates.len] != 6) {
 grid.lines(x = c(x.finis + 1, x.finis + 1), 
      y = c(dates.fsubs$dotw[dates.len] -0.5, -0.5), default.units = &quot;native&quot;,
      gp=gpar(col = &quot;grey&quot;, lwd = 1))
      }
 grid.lines(x = c(x.finis, x.finis), 
      y = c(dates.fsubs$dotw[dates.len] -0.5, -0.5), default.units = &quot;native&quot;,
      gp=gpar(col = &quot;grey&quot;, lwd = 1))
      }
for (n in 1:51) {
  grid.lines(x = c(n + 1.5, n + 1.5), 
    y = c(-0.5, 6.5), default.units = &quot;native&quot;, gp=gpar(col = &quot;grey&quot;, lwd = 1))
        }
x.start &lt;- adj.start - 0.5

if (y.start &gt; 0) {
  grid.lines(x = c(x.start, x.start + 1),
    y = c(y.start - 0.5, y.start -  0.5), default.units = &quot;native&quot;,
    gp=gpar(col = &quot;black&quot;, lwd = 1.75))
  grid.lines(x = c(x.start + 1, x.start + 1),
    y = c(y.start - 0.5 , -0.5), default.units = &quot;native&quot;,
    gp=gpar(col = &quot;black&quot;, lwd = 1.75))
  grid.lines(x = c(x.start, x.start),
    y = c(y.start - 0.5, 6.5), default.units = &quot;native&quot;,
    gp=gpar(col = &quot;black&quot;, lwd = 1.75))
 if (y.end &lt; 6  ) {
  grid.lines(x = c(x.start + 1, x.finis + 1),
   y = c(-0.5, -0.5), default.units = &quot;native&quot;,
   gp=gpar(col = &quot;black&quot;, lwd = 1.75))
  grid.lines(x = c(x.start, x.finis),
   y = c(6.5, 6.5), default.units = &quot;native&quot;,
   gp=gpar(col = &quot;black&quot;, lwd = 1.75))
   } else {
      grid.lines(x = c(x.start + 1, x.finis),
       y = c(-0.5, -0.5), default.units = &quot;native&quot;,
       gp=gpar(col = &quot;black&quot;, lwd = 1.75))
      grid.lines(x = c(x.start, x.finis),
       y = c(6.5, 6.5), default.units = &quot;native&quot;,
       gp=gpar(col = &quot;black&quot;, lwd = 1.75))
       }
       } else {
           grid.lines(x = c(x.start, x.start),
            y = c( - 0.5, 6.5), default.units = &quot;native&quot;,
            gp=gpar(col = &quot;black&quot;, lwd = 1.75))
           }

 if (y.start == 0 ) {
  if (y.end &lt; 6  ) {
  grid.lines(x = c(x.start, x.finis + 1),
   y = c(-0.5, -0.5), default.units = &quot;native&quot;,
   gp=gpar(col = &quot;black&quot;, lwd = 1.75))
  grid.lines(x = c(x.start, x.finis),
   y = c(6.5, 6.5), default.units = &quot;native&quot;,
   gp=gpar(col = &quot;black&quot;, lwd = 1.75))
   } else {
      grid.lines(x = c(x.start + 1, x.finis),
       y = c(-0.5, -0.5), default.units = &quot;native&quot;,
       gp=gpar(col = &quot;black&quot;, lwd = 1.75))
      grid.lines(x = c(x.start, x.finis),
       y = c(6.5, 6.5), default.units = &quot;native&quot;,
       gp=gpar(col = &quot;black&quot;, lwd = 1.75))
       }
       }
for (j in 1:12)  {
   last.month &lt;- max(dates.fsubs$seq[dates.fsubs$month == j])
   x.last.m &lt;- dates.fsubs$woty[last.month] + 0.5
   y.last.m &lt;- dates.fsubs$dotw[last.month] + 0.5
   grid.lines(x = c(x.last.m, x.last.m), y = c(-0.5, y.last.m),
     default.units = &quot;native&quot;, gp=gpar(col = &quot;black&quot;, lwd = 1.75))
   if ((y.last.m) &lt; 6) {
      grid.lines(x = c(x.last.m, x.last.m - 1), y = c(y.last.m, y.last.m),
       default.units = &quot;native&quot;, gp=gpar(col = &quot;black&quot;, lwd = 1.75))
     grid.lines(x = c(x.last.m - 1, x.last.m - 1), y = c(y.last.m, 6.5),
       default.units = &quot;native&quot;, gp=gpar(col = &quot;black&quot;, lwd = 1.75))
   } else {
      grid.lines(x = c(x.last.m, x.last.m), y = c(- 0.5, 6.5),
       default.units = &quot;native&quot;, gp=gpar(col = &quot;black&quot;, lwd = 1.75))
    }
 }
 }
 }
trellis.unfocus()
} 
lattice.options(default.theme = def.theme)
}
</pre>
<p>If we pass the dataframed time series data counting the sum (count) of tweets per day, we can get a calendar heatmap view of Martin&#8217;s twitter activity:</p>
<pre class="brush: r; title: ; notranslate">calendarHeat(ts.sum.df$date, ts.sum.df$sum, varname=&quot;@mhawksey Twitter activity&quot;)
</pre>
<p><a href="http://ouseful.files.wordpress.com/2012/02/twcalendarheatmap.png"><img src="http://ouseful.files.wordpress.com/2012/02/twcalendarheatmap.png?w=700" alt="" title="twCalendarHeatmap"   class="alignnone size-full wp-image-7114" /></a></p>
<p>I&#8217;m not sure if this is even interesting, let alone useful, but I do think now I&#8217;ve found out a little bit about working with time in R, <em>that</em> could be handy&#8230;</p>
<p>Still to do: extract hashtags and visualise them; extend the twitteR library so it exposes things like retweet counts. But that&#8217;s for another day&#8230;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ouseful.wordpress.com/7098/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ouseful.wordpress.com/7098/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.ouseful.info&#038;blog=325417&#038;post=7098&#038;subd=ouseful&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.ouseful.info/2012/02/17/visualising-twitter-user-timeline-activity-in-r/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/abbd9f90565ce9ae4d065d93a81d8c03?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Tony Hirst</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/simpleusertimeline.png" medium="image">
			<media:title type="html">simpleUserTimeline</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/twusertimelinelimited.png" medium="image">
			<media:title type="html">twUserTimelineLimited</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/usertimelinereplies.png" medium="image">
			<media:title type="html">userTimelineReplies</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/usertimelinertandreply.png" medium="image">
			<media:title type="html">userTimeLineRTandReply</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/repliesbarplot.png" medium="image">
			<media:title type="html">repliesBarplot</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/tweetdistro_hourvweek.png" medium="image">
			<media:title type="html">tweetDistro_hourVweek</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/twovertime.png" medium="image">
			<media:title type="html">twOverTime</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/twperhourofday.png" medium="image">
			<media:title type="html">twPerHourOfDay</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/twtimeseries.png" medium="image">
			<media:title type="html">twTimeSeries</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/twautocorrelation.png" medium="image">
			<media:title type="html">twAutocorrelation</media:title>
		</media:content>

		<media:content url="http://ouseful.files.wordpress.com/2012/02/twcalendarheatmap.png" medium="image">
			<media:title type="html">twCalendarHeatmap</media:title>
		</media:content>
	</item>
	</channel>
</rss>
