

{"id":7803,"date":"2018-01-15T15:08:38","date_gmt":"2018-01-15T20:08:38","guid":{"rendered":"https:\/\/rud.is\/b\/?p=7803"},"modified":"2018-03-10T07:54:16","modified_gmt":"2018-03-10T12:54:16","slug":"cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads","status":"publish","type":"post","link":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/","title":{"rendered":"Can&#8217;t Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads"},"content":{"rendered":"<p>NOTE: The likelihood of this recipe being added to the recent <a href=\"https:\/\/rud.is\/books\/21-recipes\/\">practice <code>bookdown<\/code> book<\/a> is slim, but I&#8217;ll try to keep the same format for the blog post.<\/p>\n<h3>Problem<\/h3>\n<p>You want to collect all the tweets in a Twitter tweet thread<\/p>\n<h3>Solution<\/h3>\n<p>Use a few key functions in <code>rtweet<\/code> to piece the thread elements back together.<\/p>\n<h3>Discussion<\/h3>\n<p>In Twitterland, a &#8220;thread&#8221; is a series of tweets by an author that are in a reply chain to each other which enables them to be displayed sequentially to form a larger &amp; (ostensibly) more cohesive message. Even with the recent 280 character tweet-length increase, threads are still popular and used daily. They&#8217;re very easy to distinguish on Twitter but there is no Twitter API call to collect up all the pieces of these threads.<\/p>\n<p>Let&#8217;s build a function &#8212; <code>get_thread()<\/code> &#8212; that will take as input a starting thread URL or status id and return a data frame of all the tweets in the thread (in order). As a bonus, we&#8217;ll also include a way to include all first-level retweets and replies to each threaded tweet (that, too, happens quite a bit).<\/p>\n<p>There are documentation snippets in the code block (below), but the essence of the function is:<\/p>\n<ul>\n<li>first, finding the tweet that belongs to the status id to get some metadata<\/li>\n<li>then doing a search for tweets from the author that occurred after that tweet (we do this to save on API calls and we grab a bunch of them)<\/li>\n<li>rather than do a bunch of things by hand, we make from\/to pairs to feed in as vertex edges into <code>igraph<\/code><\/li>\n<li>once that&#8217;s done, separate out the graph into unique subgraphs and find the one containing the starting status id<\/li>\n<li>since that subgraph is just a set of status ids, rebuild the data frame from it and put it in order.<\/li>\n<\/ul>\n<p>There may be occasions where we want to grab the replies or RTs of any of the original thread tweets. They aren&#8217;t always useful, but when they are it&#8217;d be good to have this context. So, we&#8217;ll add an option that &#8212; if <code>TRUE<\/code> &#8212; will cause the function to go down the list of threaded tweets and pull the first-level replies and RTs (excluding the ones from the author). We&#8217;ll do this using the Twitter search API as it&#8217;ll ultimately save on API calls and it puts the filtering closer to the data (I&#8217;m generally &#8220;a fan&#8221; of putting computation as close to the data as possible for any given task). If there were any, they&#8217;ll be in a <code>replies<\/code> column which can be unnested at-will.<\/p>\n<p>Here&#8217;s the complete function:<\/p>\n<pre id=\"2018-tweet-thread-01\"><code class=\"language-r\">get_thread &lt;- function(first_status, include_replies=FALSE, .timeline_history=3000) {\r\n\r\n  require(rtweet, quietly=TRUE, warn.conflicts=FALSE)\r\n  require(igraph, quietly=TRUE, warn.conflicts=FALSE)\r\n  require(tidyverse, quietly=TRUE, warn.conflicts=FALSE)\r\n\r\n  first_status &lt;- if (str_detect(first_status[1], &quot;^http[s]:\/\/&quot;)) basename(first_status[1]) else first_status[1]\r\n\r\n  # get first status\r\n  orig &lt;- rtweet::lookup_tweets(first_status)\r\n\r\n  # grab the author&#039;s timeline to search\r\n  author_timeline &lt;- rtweet::get_timeline(orig$screen_name, n=.timeline_history, since_id=first_status)\r\n\r\n  # build a data frame containing from\/to pairs (anything the author\r\n  # replied to) that also includes the `first_status` id.\r\n  suppressWarnings(\r\n    dplyr::filter(\r\n      author_timeline,\r\n      (status_id == first_status) | (reply_to_screen_name == orig$screen_name)\r\n    ) %&gt;%\r\n      dplyr::select(status_id, reply_to_status_id) %&gt;%\r\n      igraph::graph_from_data_frame() -&gt; g\r\n  ) # build a graph from this\r\n\r\n  # decompose the graph into unique subgraphs and return them to data frames\r\n  igraph::decompose(g) %&gt;%\r\n    purrr::map(igraph::as_data_frame) -&gt; threads_dfs\r\n\r\n  # find the thread with our `first_status` ids\r\n\r\n  thread_df &lt;- purrr::keep(threads_dfs, ~any(which(unique(unlist(.x, use.names=FALSE)) == first_status)))\r\n\r\n  # BONUS: we get them in the order we need!\r\n  thread_order &lt;- purrr::discard(rev(unique(unlist(thread_df))), str_detect, &quot;NA&quot;)\r\n\r\n  # filter out the thread from the timeline corpus &amp; sort it\r\n  dplyr::filter(author_timeline, status_id %in% pull(thread_df[[1]], from)) %&gt;%\r\n    dplyr::mutate(status_id = factor(status_id, levels=thread_order)) %&gt;%\r\n    dplyr::arrange(status_id) -&gt; tweet_thread\r\n\r\n  if (include_replies) {\r\n    # for each status, lookup 1st-level references to it, excluding ones from the original author\r\n    mutate(\r\n      tweet_thread,\r\n      replies = purrr::map(\r\n        as.character(status_id),\r\n        ~rtweet::search_tweets(sprintf(&quot;%s -from:%s&quot;, .x, orig$screen_name[1]))\r\n      )\r\n    ) -&gt; tweet_thread\r\n  }\r\n\r\n  class(tweet_thread) &lt;-  c(&quot;tweet_thread&quot;, class(tweet_thread))\r\n\r\n  return(tweet_thread)\r\n\r\n}<\/code><\/pre>\n<p>Now, if we grab <a href=\"https:\/\/mobile.twitter.com\/petersagal\/status\/952910499825451009\">this thread<\/a>, the function will return the following:<\/p>\n<pre id=\"2018-tweet-thread-02\"><code class=\"language-r\">xdf &lt;- get_thread(&quot;https:\/\/twitter.com\/petersagal\/status\/952910499825451009&quot;)\r\n\r\nglimpse(select(xdf, 1:5))\r\n## Observations: 10\r\n## Variables: 5\r\n## $ status_id   &lt;fctr&gt; 952910499825451009, 952910695804305408, 952911012990193664, 952911632077852679, 9529121...\r\n## $ created_at  &lt;dttm&gt; 2018-01-15 14:29:02, 2018-01-15 14:29:48, 2018-01-15 14:31:04, 2018-01-15 14:33:31, 201...\r\n## $ user_id     &lt;chr&gt; &quot;14985228&quot;, &quot;14985228&quot;, &quot;14985228&quot;, &quot;14985228&quot;, &quot;14985228&quot;, &quot;14985228&quot;, &quot;14985228&quot;, &quot;149...\r\n## $ screen_name &lt;chr&gt; &quot;petersagal&quot;, &quot;petersagal&quot;, &quot;petersagal&quot;, &quot;petersagal&quot;, &quot;petersagal&quot;, &quot;petersagal&quot;, &quot;pet...\r\n## $ text        &lt;chr&gt; &quot;Funny you mention that. I talked to Minniejean (Brown) Trickey, one of the Little Rock ...\r\n\r\npurrr::map(xdf$text, strwrap) %&gt;% \r\n  purrr::map_chr(paste0, collapse=&quot;\\n&quot;) %&gt;% \r\n  cat(sep=&quot;\\n\\n&quot;)\r\n## Funny you mention that. I talked to Minniejean (Brown) Trickey, one of the Little Rock Nine, about\r\n## that very day in front of CHS for my documentary, &quot;Constitution USA.&quot; https:\/\/t.co\/MRwtlfZtvp\r\n## \r\n## You would think that of all people, she would be satisfied with the government&#039;s response to racism\r\n## and hate. Ike sent the 101st Airborne to escort her to class!\r\n## \r\n## But what I didn&#039;t know is that after the 101st left, CHS expelled her on a trumped up charge of\r\n## assault after she spilled some chili on a white student.\r\n## \r\n## She spilled some chili. After being tripped by another white kid. &quot;We got rid of one of them!&quot; the\r\n## teachers bragged.\r\n## \r\n## Then, of course, rather than continue to allow black students to attend CHS, the governor of Alabama\r\n## closed the schools. https:\/\/t.co\/2DfBEI0OTL&quot;The_Lost_Year&quot;\r\n## \r\n## Ms Brown looked around the country post high school. She saw Jim Crow, firehoses turned on Blacks,\r\n## the murder of the Birmingham Four and the Mississippi Three. She moved to Canada.\r\n## \r\n## As of 2012, she found herself coming back to Little Rock, a place she told me she never wanted to\r\n## see again. But she had family. And the National Historic Site center was there. She liked to drop\r\n## by, talk to the kids about what happened.\r\n## \r\n## Now she lives in Little Rock full time. She doesn&#039;t care that her name is inscribed on a bench in\r\n## front of the school. She doesn&#039;t care that your dad welcomed her back in &#039;99.  She spends time at\r\n## the Center, telling people what really happened. You should go talk to her.\r\n## \r\n## (Sorry: Arkansas, obviously. Typing too quickly.)\r\n## \r\n## Here&#039;s me, talking to Ms Trickey and Marty Sammon, who served with the 101st at Little Rock. Buddy\r\n## Squiers on camera. CHS is off to the left. https:\/\/t.co\/ft4LUBf3sr\r\n## \r\n## https:\/\/t.co\/EHLbe1finj<\/code><\/pre>\n<p>The <code>replies<\/code> data frame looks much the same as the thread data frame &#8212; it&#8217;s essentially just another <code>rtweet<\/code> data frame, so we won&#8217;t waste electrons showing it.<\/p>\n<p>While that <code>map<\/code>\/<code>map<\/code>\/<code>cat<\/code> sequence isn&#8217;t bad to type, it&#8217;d be more convenient if we had a <code>print()<\/code> method for this structure (this is one reason we added a class to it). It&#8217;d be even spiffier if this <code>print()<\/code> method made it easier to distinguish the main thread from the RT&#8217;s\/replies &#8212; but still show those extra bits of info. We&#8217;ll use the <code>crayon<\/code> package for added emphasis:<\/p>\n<pre id=\"2018-tweet-thread-03\"><code class=\"language-r\">print.tweet_thread &lt;- function(x, ...) {\r\n  \r\n  cat(crayon::cyan(sprintf(&quot;@%s - %s\\n\\n&quot;, x$screen_name[1], x$created_at[1])))\r\n  \r\n  if (!(&quot;replies&quot; %in% colnames(x))) x$replies &lt;- purrr::map(1:nrow(x), ~list())\r\n  \r\n  purrr::walk2(x$text, x$replies, ~{\r\n    \r\n    cat(crayon::green(paste0(strwrap(.x), collapse=&quot;\\n&quot;)), &quot;\\n\\n&quot;, sep=&quot;&quot;)\r\n    \r\n    if (length(.y) &gt; 0) {\r\n      purrr::walk2(.y$screen_name, .y$text, ~{\r\n        sprintf(&quot;@%s\\n%s&quot;, .x, .y) %&gt;%\r\n          strwrap(indent=8, exdent=8) %&gt;%\r\n          paste0(collapse=&quot;\\n&quot;) %&gt;%\r\n          crayon::silver$italic() %&gt;%\r\n          cat(&quot;\\n\\n&quot;, sep=&quot;&quot;)\r\n      })\r\n    }\r\n    \r\n  })\r\n  \r\n}<\/code><\/pre>\n<p>Let&#8217;s re-capture the tweet thread but also include replies this time and print it out:<\/p>\n<pre id=\"2018-tweet-thread-04\"><code class=\"language-r\">ydf &lt;- get_thread(&quot;https:\/\/twitter.com\/petersagal\/status\/952910499825451009&quot;, include_replies=TRUE)\r\n\r\nydf<\/code><\/pre>\n<p><a href=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"7806\" data-permalink=\"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/screen-shot-2018-01-15-at-3-01-13-pm\/\" data-orig-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&amp;ssl=1\" data-orig-size=\"1620,2020\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Screen Shot 2018-01-15 at 3.01.13 PM\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=510%2C636&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?resize=510%2C636&#038;ssl=1\" alt=\"\" width=\"510\" height=\"636\" class=\"aligncenter size-full wp-image-7806\" \/><\/a><\/p>\n<h3>See Also<\/h3>\n<p>I&#8217;ve git-chatted with Sir Kearney to see where to best put this function. I mention that as there are some upcoming posts that kick the aforeblogged <a href=\"https:\/\/rud.is\/b\/2017\/12\/30\/r%E2%81%B6-capture-tweets-with-tweet_shot\/\"><code>tweet_shot()<\/code><\/a> up a notch or two and all of this may work better in a <code>tweetview<\/code> package.<\/p>\n<p>Regardless, drop a note in the comments if there are other bits of functionality or function options you think belong in <code>get_thread()<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>NOTE: The likelihood of this recipe being added to the recent practice bookdown book is slim, but I&#8217;ll try to keep the same format for the blog post. Problem You want to collect all the tweets in a Twitter tweet thread Solution Use a few key functions in rtweet to piece the thread elements back [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":7806,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":3,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[91,655],"tags":[810],"class_list":["post-7803","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-r","category-twitter-2","tag-post"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Can&#039;t Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads - rud.is<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Can&#039;t Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads - rud.is\" \/>\n<meta property=\"og:description\" content=\"NOTE: The likelihood of this recipe being added to the recent practice bookdown book is slim, but I&#8217;ll try to keep the same format for the blog post. Problem You want to collect all the tweets in a Twitter tweet thread Solution Use a few key functions in rtweet to piece the thread elements back [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/\" \/>\n<meta property=\"og:site_name\" content=\"rud.is\" \/>\n<meta property=\"article:published_time\" content=\"2018-01-15T20:08:38+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-03-10T12:54:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"1620\" \/>\n\t<meta property=\"og:image:height\" content=\"2020\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"hrbrmstr\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"hrbrmstr\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/\"},\"author\":{\"name\":\"hrbrmstr\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#\\\/schema\\\/person\\\/d7cb7487ab0527447f7fda5c423ff886\"},\"headline\":\"Can&#8217;t Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads\",\"datePublished\":\"2018-01-15T20:08:38+00:00\",\"dateModified\":\"2018-03-10T12:54:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/\"},\"wordCount\":668,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#\\\/schema\\\/person\\\/d7cb7487ab0527447f7fda5c423ff886\"},\"image\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2018\\\/01\\\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1\",\"keywords\":[\"post\"],\"articleSection\":[\"R\",\"twitter\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/\",\"url\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/\",\"name\":\"Can't Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads - rud.is\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2018\\\/01\\\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1\",\"datePublished\":\"2018-01-15T20:08:38+00:00\",\"dateModified\":\"2018-03-10T12:54:16+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/#primaryimage\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2018\\\/01\\\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2018\\\/01\\\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1\",\"width\":1620,\"height\":2020},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2018\\\/01\\\/15\\\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/rud.is\\\/b\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Can&#8217;t Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#website\",\"url\":\"https:\\\/\\\/rud.is\\\/b\\\/\",\"name\":\"rud.is\",\"description\":\"&quot;In God we trust. All others must bring data&quot;\",\"publisher\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#\\\/schema\\\/person\\\/d7cb7487ab0527447f7fda5c423ff886\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/rud.is\\\/b\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#\\\/schema\\\/person\\\/d7cb7487ab0527447f7fda5c423ff886\",\"name\":\"hrbrmstr\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/ukr-shield.png?fit=460%2C460&ssl=1\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/ukr-shield.png?fit=460%2C460&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/ukr-shield.png?fit=460%2C460&ssl=1\",\"width\":460,\"height\":460,\"caption\":\"hrbrmstr\"},\"logo\":{\"@id\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/ukr-shield.png?fit=460%2C460&ssl=1\"},\"description\":\"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7\",\"sameAs\":[\"http:\\\/\\\/rud.is\"],\"url\":\"https:\\\/\\\/rud.is\\\/b\\\/author\\\/hrbrmstr\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Can't Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads - rud.is","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/","og_locale":"en_US","og_type":"article","og_title":"Can't Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads - rud.is","og_description":"NOTE: The likelihood of this recipe being added to the recent practice bookdown book is slim, but I&#8217;ll try to keep the same format for the blog post. Problem You want to collect all the tweets in a Twitter tweet thread Solution Use a few key functions in rtweet to piece the thread elements back [&hellip;]","og_url":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/","og_site_name":"rud.is","article_published_time":"2018-01-15T20:08:38+00:00","article_modified_time":"2018-03-10T12:54:16+00:00","og_image":[{"width":1620,"height":2020,"url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1","type":"image\/png"}],"author":"hrbrmstr","twitter_card":"summary_large_image","twitter_misc":{"Written by":"hrbrmstr","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/#article","isPartOf":{"@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/"},"author":{"name":"hrbrmstr","@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"headline":"Can&#8217;t Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads","datePublished":"2018-01-15T20:08:38+00:00","dateModified":"2018-03-10T12:54:16+00:00","mainEntityOfPage":{"@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/"},"wordCount":668,"commentCount":2,"publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"image":{"@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1","keywords":["post"],"articleSection":["R","twitter"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/","url":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/","name":"Can't Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads - rud.is","isPartOf":{"@id":"https:\/\/rud.is\/b\/#website"},"primaryImageOfPage":{"@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/#primaryimage"},"image":{"@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1","datePublished":"2018-01-15T20:08:38+00:00","dateModified":"2018-03-10T12:54:16+00:00","breadcrumb":{"@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/#primaryimage","url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1","contentUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1","width":1620,"height":2020},{"@type":"BreadcrumbList","@id":"https:\/\/rud.is\/b\/2018\/01\/15\/cant-stop-at-21-twitter-recipe-22-tying-up-loose-threads\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/rud.is\/b\/"},{"@type":"ListItem","position":2,"name":"Can&#8217;t Stop at 21: Twitter Recipe #22 \u2014 Tying Up Loose Threads"}]},{"@type":"WebSite","@id":"https:\/\/rud.is\/b\/#website","url":"https:\/\/rud.is\/b\/","name":"rud.is","description":"&quot;In God we trust. All others must bring data&quot;","publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/rud.is\/b\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886","name":"hrbrmstr","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","contentUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","width":460,"height":460,"caption":"hrbrmstr"},"logo":{"@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1"},"description":"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7","sameAs":["http:\/\/rud.is"],"url":"https:\/\/rud.is\/b\/author\/hrbrmstr\/"}]}},"jetpack_featured_media_url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-15-at-3.01.13-PM.png?fit=1620%2C2020&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p23idr-21R","jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":7733,"url":"https:\/\/rud.is\/b\/2017\/12\/30\/r%e2%81%b6-capture-tweets-with-tweet_shot\/","url_meta":{"origin":7803,"position":0},"title":"R\u2076 \u2014 Capture Tweets with tweet_shot()","author":"hrbrmstr","date":"2017-12-30","format":false,"excerpt":"(You can find all R\u2076 posts here) UPDATE 2018-01-01 --- this has been added to rtweet (GH version). A Twitter discussion: I'm going to keep my eyes out for this one! Would love to have an easy way to embed tweets in Rmd talks!\u2014 Jeff Hollister (@jhollist) December 30, 2017\u2026","rel":"","context":"In &quot;R&quot;","block_context":{"text":"R","link":"https:\/\/rud.is\/b\/category\/r\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2017\/12\/preview.png?fit=517%2C899&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":7108,"url":"https:\/\/rud.is\/b\/2017\/11\/13\/twitter-outer-limits-seeing-how-far-have-folks-fallen-down-the-slippery-slope-to-280-with-rtweet\/","url_meta":{"origin":7803,"position":1},"title":"Twitter Outer Limits : Seeing How Far Have Folks Fallen Down The Slippery Slope to &#8220;280&#8221; with rtweet","author":"hrbrmstr","date":"2017-11-13","format":false,"excerpt":"By now, virtually every major media outlet has covered the \"280 Apocalypse\"\u2122. For those still not \"in the know\", Twitter recently moved the tweet character cap to 280 after a \"successful\" beta test (some of us have different ideas of what \"success\" looks like). I had been on a hiatus\u2026","rel":"","context":"In &quot;R&quot;","block_context":{"text":"R","link":"https:\/\/rud.is\/b\/category\/r\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2017\/11\/plot_zoom_png-2.png?fit=1200%2C1061&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2017\/11\/plot_zoom_png-2.png?fit=1200%2C1061&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2017\/11\/plot_zoom_png-2.png?fit=1200%2C1061&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2017\/11\/plot_zoom_png-2.png?fit=1200%2C1061&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2017\/11\/plot_zoom_png-2.png?fit=1200%2C1061&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":6788,"url":"https:\/\/rud.is\/b\/2017\/10\/22\/a-call-to-tweets-blog-posts\/","url_meta":{"origin":7803,"position":2},"title":"A Call to Tweets (&#038; Blog Posts)!","author":"hrbrmstr","date":"2017-10-22","format":false,"excerpt":"Way back in July of 2009, the first version of the twitteR package was published by Geoff Jentry in CRAN. Since then it has seen 28 updates, finally breaking the 0.x.y barrier into 1.x.y territory in March of 2013 and receiving it's last update in July of 2015. For a\u2026","rel":"","context":"In &quot;R&quot;","block_context":{"text":"R","link":"https:\/\/rud.is\/b\/category\/r\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":6917,"url":"https:\/\/rud.is\/b\/2017\/10\/30\/gg_tweeting-power-outages\/","url_meta":{"origin":7803,"position":3},"title":"gg_tweet&#8217;ing Power Outages","author":"hrbrmstr","date":"2017-10-30","format":false,"excerpt":"As many folks know, I live in semi-rural Maine and we were hit pretty hard with a wind+rain storm Sunday to Monday. The hrbrmstr compound had no power (besides a generator) and no stable\/high-bandwidth internet (Verizon LTE was heavily congested) since 0500 Monday and still does not as I write\u2026","rel":"","context":"In &quot;ggplot&quot;","block_context":{"text":"ggplot","link":"https:\/\/rud.is\/b\/category\/ggplot\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":12920,"url":"https:\/\/rud.is\/b\/2021\/01\/30\/parler-whack-a-mole\/","url_meta":{"origin":7803,"position":4},"title":"Parler Whack-a-Mole","author":"hrbrmstr","date":"2021-01-30","format":false,"excerpt":"(this is an unrolled Twitter thread converted to the blog since one never knows how long content will be preserved anywhere anymore) It looks like @StackPath (NetCDN[.]com redirects to them) is enabling insurrection-mongers. They're fronting news[.]parler[.]com . It seems they (Parler) have a second domain dicecrm[.]com with the actual content,\u2026","rel":"","context":"In &quot;Commentary&quot;","block_context":{"text":"Commentary","link":"https:\/\/rud.is\/b\/category\/commentary\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/pbs.twimg.com\/media\/Es4z5Z0W4AI7cGJ.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":12297,"url":"https:\/\/rud.is\/b\/2019\/06\/09\/wrapping-up-exploration-of-john-deeres-mowerplus-database\/","url_meta":{"origin":7803,"position":5},"title":"Wrapping Up Exploration of John Deere&#8217;s MowerPlus Database","author":"hrbrmstr","date":"2019-06-09","format":false,"excerpt":"I did another twitter thread on the aforeblogged MowerPlus database as I explored the tables after a second mow to determine what identified a unique mowing \"session\" (using John Deere's terms). This is the thread: As forewarned, today was the second mow with the new @JohnDeere mower. I'll thread the\u2026","rel":"","context":"In &quot;R&quot;","block_context":{"text":"R","link":"https:\/\/rud.is\/b\/category\/r\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2019\/06\/mow-speed.png?fit=1200%2C720&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2019\/06\/mow-speed.png?fit=1200%2C720&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2019\/06\/mow-speed.png?fit=1200%2C720&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2019\/06\/mow-speed.png?fit=1200%2C720&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2019\/06\/mow-speed.png?fit=1200%2C720&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/7803","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/comments?post=7803"}],"version-history":[{"count":0,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/7803\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/media\/7806"}],"wp:attachment":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/media?parent=7803"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/categories?post=7803"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/tags?post=7803"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}