<?xml version="1.0" encoding="UTF-8"?>

<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     >
  <channel>
    <atom:link href="http://kitchingroup.cheme.cmu.edu/blog/feed/index.xml" rel="self" type="application/rss+xml" />
    <title>The Kitchin Research Group</title>
    <link>https://kitchingroup.cheme.cmu.edu/blog</link>
    <description>Chemical Engineering at Carnegie Mellon University</description>
    <pubDate>Sat, 01 Nov 2025 13:47:46 GMT</pubDate>
    <generator>Blogofile</generator>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    
    <item>
      <title>Automated bibtex entry tweeting</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2016/08/25/Automated-bibtex-entry-tweeting</link>
      <pubDate>Thu, 25 Aug 2016 12:14:31 EDT</pubDate>
      <category><![CDATA[bibtex]]></category>
      <category><![CDATA[twitter]]></category>
      <guid isPermaLink="false">R6USBJFutUqhJvSjdPHsX83Gtjo=</guid>
      <description>Automated bibtex entry tweeting</description>
      <content:encoded><![CDATA[


&lt;p&gt;
The goal in this post is to develop an elisp function that will tweet a bibtex entry. What I want is to be on a bibtex entry, and run a command that will generate a tweet and tweet it. Here is an example bibtex entry I will use in this post. Clearly, I couldn't simply tweet the entry, it is too long. What I want instead is to generate a picture of a formatted citation, to make a gist out of the bibtex entry so we can link to it, and then to provide links in the tweet to the doi, and the bibtex entry gist.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-emacs-lisp"&gt;(&lt;span style="color: #0000FF;"&gt;with-current-buffer&lt;/span&gt; (find-file-noselect &lt;span style="color: #008000;"&gt;"~/Dropbox/bibliography/references.bib"&lt;/span&gt;)
  (goto-char (point-min))
  (re-search-forward &lt;span style="color: #008000;"&gt;"kitchin-2016-autom-data,"&lt;/span&gt;)
  (bibtex-copy-entry-as-kill)
  (&lt;span style="color: #0000FF;"&gt;with-temp-buffer&lt;/span&gt;
    (bibtex-yank 1)
    (buffer-string)))
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
First, we tackle making an image. Emacs has some capability to generate svg, and we can readily convert that to png for the tweet. Here we just go to the entry, and then generate a png. I build off the citation capability of org-ref to generate a pretty reasonably formatted entry. It isn't perfect; the volume is missing in the entry, so there is a blank space between two commas, but this is good enough for me. Note we need a png for twitter. It appears you cannot upload svg yet.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-emacs-lisp"&gt;(&lt;span style="color: #0000FF;"&gt;let*&lt;/span&gt; ((entry (&lt;span style="color: #0000FF;"&gt;with-current-buffer&lt;/span&gt; (find-file-noselect &lt;span style="color: #008000;"&gt;"~/Dropbox/bibliography/references.bib"&lt;/span&gt;)
                (goto-char (point-min))
                (re-search-forward &lt;span style="color: #008000;"&gt;"kitchin-2016-autom-data,"&lt;/span&gt;)
                (bibtex-beginning-of-entry)
                (bibtex-parse-entry t)))
       (formatted-entry (orhc-formatted-citation entry))
       (lines (&lt;span style="color: #0000FF;"&gt;with-temp-buffer&lt;/span&gt;
                (insert formatted-entry)
                (fill-paragraph)
                (split-string  (buffer-string) &lt;span style="color: #008000;"&gt;"\n"&lt;/span&gt;)))
       (svg (svg-create 500 (* 20 (length lines)))))

  (&lt;span style="color: #0000FF;"&gt;loop&lt;/span&gt; for i from 0
        for line in lines
        do
        (svg-text svg line
                  &lt;span style="color: #006FE0;"&gt;:font-size&lt;/span&gt; &lt;span style="color: #008000;"&gt;"12"&lt;/span&gt;
                  &lt;span style="color: #006FE0;"&gt;:stroke&lt;/span&gt; &lt;span style="color: #008000;"&gt;"black"&lt;/span&gt;
                  &lt;span style="color: #006FE0;"&gt;:x&lt;/span&gt; 0
                  &lt;span style="color: #006FE0;"&gt;:y&lt;/span&gt; (+ 15 (* i 15))
                  &lt;span style="color: #006FE0;"&gt;:stroke-width&lt;/span&gt; 0.3))

  (&lt;span style="color: #0000FF;"&gt;with-temp-file&lt;/span&gt; &lt;span style="color: #008000;"&gt;"authoring.svg"&lt;/span&gt;
    (svg-print svg)))

(shell-command &lt;span style="color: #008000;"&gt;"convert authoring.svg authoring.png"&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;img src="/media/authoring.png"&gt;
&lt;/p&gt;

&lt;p&gt;
It is easy enough to get the doi, and generate the url to it.
&lt;/p&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-emacs-lisp"&gt;(&lt;span style="color: #0000FF;"&gt;let*&lt;/span&gt; ((entry (&lt;span style="color: #0000FF;"&gt;with-current-buffer&lt;/span&gt; (find-file-noselect &lt;span style="color: #008000;"&gt;"~/Dropbox/bibliography/references.bib"&lt;/span&gt;)
                (goto-char (point-min))
                (re-search-forward &lt;span style="color: #008000;"&gt;"kitchin-2016-autom-data,"&lt;/span&gt;)
                (bibtex-beginning-of-entry)
                (bibtex-parse-entry t))))
  (format &lt;span style="color: #008000;"&gt;"https://doi.org/%s"&lt;/span&gt; (cdr (assoc &lt;span style="color: #008000;"&gt;"doi"&lt;/span&gt; entry ))))
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Next, we will put the entry as a gist on Github, so we can provide a link to it. I use the gist.el package, and here just do some trickery to put the entry in a temp-file named by the key so that the gist has a nice name. This returns the url to the gist, which we would want to incorporate into a tweet.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-emacs-lisp"&gt;(&lt;span style="color: #0000FF;"&gt;with-current-buffer&lt;/span&gt; (find-file-noselect &lt;span style="color: #008000;"&gt;"~/Dropbox/bibliography/references.bib"&lt;/span&gt;)
  (goto-char (point-min))
  (re-search-forward &lt;span style="color: #008000;"&gt;"kitchin-2016-autom-data,"&lt;/span&gt;)
  (&lt;span style="color: #0000FF;"&gt;save-restriction&lt;/span&gt;
    (bibtex-narrow-to-entry)
    (bibtex-beginning-of-entry)
    (&lt;span style="color: #0000FF;"&gt;let*&lt;/span&gt; ((entry-string (buffer-string))
           (entry (bibtex-parse-entry))
           (key (cdr (assoc &lt;span style="color: #008000;"&gt;"=key="&lt;/span&gt; entry)))
           (tfile (expand-file-name (format &lt;span style="color: #008000;"&gt;"%s.bib"&lt;/span&gt; key) temporary-file-directory)))
      (&lt;span style="color: #0000FF;"&gt;with-temp-file&lt;/span&gt; tfile
        (insert entry-string))
      (&lt;span style="color: #0000FF;"&gt;with-current-buffer&lt;/span&gt; (find-file-noselect tfile)
        (gist-buffer)))
    (&lt;span style="color: #0000FF;"&gt;with-temp-buffer&lt;/span&gt;
      (yank)
      (buffer-string))))
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
Ok, All the pieces are in place. The only piece left is creating the tweet, and tweeting it. I couldn't see an obvious way to do this with twittering mode, since I didn't see where to add an image. There is a &lt;a href="https://pypi.python.org/pypi/TwitterAPI/2.4.2"&gt;Python library&lt;/a&gt; for this though, and it looks pretty easy to use. Here is an example usage.
&lt;/p&gt;


&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #0000FF;"&gt;from&lt;/span&gt; TwitterAPI &lt;span style="color: #0000FF;"&gt;import&lt;/span&gt; TwitterAPI
&lt;span style="color: #0000FF;"&gt;from&lt;/span&gt; twitter_secrets &lt;span style="color: #0000FF;"&gt;import&lt;/span&gt; CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET

&lt;span style="color: #BA36A5;"&gt;api&lt;/span&gt; = TwitterAPI(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET)
&lt;span style="color: #006FE0;"&gt;file&lt;/span&gt; = &lt;span style="color: #006FE0;"&gt;open&lt;/span&gt;(&lt;span style="color: #008000;"&gt;'authoring.png'&lt;/span&gt;, &lt;span style="color: #008000;"&gt;'rb'&lt;/span&gt;)
&lt;span style="color: #BA36A5;"&gt;data&lt;/span&gt; = &lt;span style="color: #006FE0;"&gt;file&lt;/span&gt;.read()
&lt;span style="color: #BA36A5;"&gt;r&lt;/span&gt; = api.request(&lt;span style="color: #008000;"&gt;'statuses/update_with_media'&lt;/span&gt;, {&lt;span style="color: #008000;"&gt;'status'&lt;/span&gt;:&lt;span style="color: #008000;"&gt;'A test tweet using the TwitterAPI with an image.'&lt;/span&gt;}, {&lt;span style="color: #008000;"&gt;'media[]'&lt;/span&gt;:data})
&lt;span style="color: #0000FF;"&gt;print&lt;/span&gt;(r.status_code)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
200
&lt;/p&gt;

&lt;p&gt;
It will be a tad hacky, but the script is so simple we can just make a template, and run it. We need to do these things: 1) make the image, 2) make the gist 3) format and send the tweet. Here is the elisp function to do that.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-emacs-lisp"&gt;(&lt;span style="color: #0000FF;"&gt;defun&lt;/span&gt; &lt;span style="color: #006699;"&gt;tweet-bibtex&lt;/span&gt; ()
  &lt;span style="color: #036A07;"&gt;"Tweet the bibtex entry at point."&lt;/span&gt;
  (&lt;span style="color: #0000FF;"&gt;interactive&lt;/span&gt;)
  (bibtex-beginning-of-entry)
  (bibtex-set-field &lt;span style="color: #008000;"&gt;"tweeted"&lt;/span&gt; (current-time-string))

  (&lt;span style="color: #0000FF;"&gt;let*&lt;/span&gt; ((entry-string (&lt;span style="color: #0000FF;"&gt;save-restriction&lt;/span&gt;
                         (bibtex-beginning-of-entry)
                         (bibtex-narrow-to-entry)
                         (buffer-substring-no-properties (point-min) (point-max))))
         (entry (bibtex-parse-entry t))
         (key (cdr (assoc &lt;span style="color: #008000;"&gt;"=key="&lt;/span&gt; entry)))
         (doi (cdr (assoc &lt;span style="color: #008000;"&gt;"doi"&lt;/span&gt; entry)))
         (svg-file (expand-file-name (format &lt;span style="color: #008000;"&gt;"%s.svg"&lt;/span&gt; key) temporary-file-directory))
         (png-file (expand-file-name (format &lt;span style="color: #008000;"&gt;"%s.png"&lt;/span&gt; key) temporary-file-directory))
         (bib-file (expand-file-name (format &lt;span style="color: #008000;"&gt;"%s.bib"&lt;/span&gt; key) temporary-file-directory))
         (py-file (expand-file-name (format &lt;span style="color: #008000;"&gt;"%s.py"&lt;/span&gt; key) temporary-file-directory))
         (formatted-entry (orhc-formatted-citation entry))
         (lines (&lt;span style="color: #0000FF;"&gt;with-temp-buffer&lt;/span&gt;
                  (insert formatted-entry)
                  (fill-paragraph)
                  (split-string  (buffer-string) &lt;span style="color: #008000;"&gt;"\n"&lt;/span&gt;)))
         (svg (svg-create 500 (* 20 (length lines))))
         (tweet (read-string &lt;span style="color: #008000;"&gt;"Tweet: "&lt;/span&gt;))
         gist-url
         full-tweet)

    &lt;span style="color: #8D8D84;"&gt;;; &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;delete buffers and files&lt;/span&gt;
    (&lt;span style="color: #0000FF;"&gt;loop&lt;/span&gt; for buf in (list (concat key &lt;span style="color: #008000;"&gt;".bib"&lt;/span&gt;)
                           (concat key &lt;span style="color: #008000;"&gt;".png"&lt;/span&gt;)
                           (concat key &lt;span style="color: #008000;"&gt;".svg"&lt;/span&gt;)
                           (concat key &lt;span style="color: #008000;"&gt;".py"&lt;/span&gt;))
          do
          (&lt;span style="color: #0000FF;"&gt;when&lt;/span&gt; (get-buffer buf)
            (kill-buffer (get-buffer buf))))

    &lt;span style="color: #8D8D84;"&gt;;; &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;Step 1 make the image&lt;/span&gt;
    (&lt;span style="color: #0000FF;"&gt;loop&lt;/span&gt; for i from 0
          for line in lines
          do
          (svg-text svg line
                    &lt;span style="color: #006FE0;"&gt;:font-size&lt;/span&gt; &lt;span style="color: #008000;"&gt;"12"&lt;/span&gt;
                    &lt;span style="color: #006FE0;"&gt;:stroke&lt;/span&gt; &lt;span style="color: #008000;"&gt;"black"&lt;/span&gt;
                    &lt;span style="color: #006FE0;"&gt;:x&lt;/span&gt; 0
                    &lt;span style="color: #006FE0;"&gt;:y&lt;/span&gt; (+ 15 (* i 15))
                    &lt;span style="color: #006FE0;"&gt;:stroke-width&lt;/span&gt; 0.3))

    (&lt;span style="color: #0000FF;"&gt;with-temp-file&lt;/span&gt; svg-file
      (svg-print svg))

    (shell-command (format &lt;span style="color: #008000;"&gt;"convert %s %s"&lt;/span&gt; svg-file png-file))

    &lt;span style="color: #8D8D84;"&gt;;; &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;Step 2, make the gist. Make a temp-file so the gist has a reasonable name&lt;/span&gt;
    (&lt;span style="color: #0000FF;"&gt;with-temp-file&lt;/span&gt; bib-file
      (insert entry-string))

    (&lt;span style="color: #0000FF;"&gt;let&lt;/span&gt; ((bib-buffer (find-file-noselect bib-file)))
      (&lt;span style="color: #0000FF;"&gt;with-current-buffer&lt;/span&gt; bib-buffer
        (gist-buffer))
      (kill-buffer bib-buffer))

    &lt;span style="color: #8D8D84;"&gt;;; &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;get url off clipboard&lt;/span&gt;
    (&lt;span style="color: #0000FF;"&gt;setq&lt;/span&gt; gist-url (&lt;span style="color: #0000FF;"&gt;with-temp-buffer&lt;/span&gt;
                     (yank)
                     (buffer-string)))

    &lt;span style="color: #8D8D84;"&gt;;; &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;Format and send the tweet:&lt;/span&gt;
    (&lt;span style="color: #0000FF;"&gt;setq&lt;/span&gt; full-tweet (format &lt;span style="color: #008000;"&gt;"#publication %s\nhttps://doi.org/%s\nbibtex: %s"&lt;/span&gt; tweet doi gist-url))

    (&lt;span style="color: #0000FF;"&gt;with-temp-file&lt;/span&gt; py-file
      (insert (format &lt;span style="color: #008000;"&gt;"from TwitterAPI import TwitterAPI&lt;/span&gt;
&lt;span style="color: #008000;"&gt;from twitter_secrets import CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET&lt;/span&gt;

&lt;span style="color: #008000;"&gt;api = TwitterAPI(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET)&lt;/span&gt;
&lt;span style="color: #008000;"&gt;file = open('%s', 'rb')&lt;/span&gt;
&lt;span style="color: #008000;"&gt;data = file.read()&lt;/span&gt;
&lt;span style="color: #008000;"&gt;r = api.request('statuses/update_with_media', {'status':'''%s'''}, {'media[]':data})"&lt;/span&gt;
                      png-file
                      full-tweet)))

    (&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt; (= 0 (shell-command (format &lt;span style="color: #008000;"&gt;"python %s"&lt;/span&gt; py-file)))
        (message &lt;span style="color: #008000;"&gt;"%s"&lt;/span&gt; full-tweet)
      (message &lt;span style="color: #008000;"&gt;"tweet failed ;("&lt;/span&gt;))))

&lt;span style="color: #8D8D84;"&gt;;; &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;Now, try it out.&lt;/span&gt;
(&lt;span style="color: #0000FF;"&gt;with-current-buffer&lt;/span&gt; (find-file-noselect &lt;span style="color: #008000;"&gt;"~/Dropbox/bibliography/references.bib"&lt;/span&gt;)
  (goto-char (point-min))
  (re-search-forward &lt;span style="color: #008000;"&gt;"kitchin-2016-autom-data,"&lt;/span&gt;)
  (tweet-bibtex))
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You can see what this tweet looks like here:
&lt;/p&gt;

&lt;blockquote class="twitter-tweet" data-lang="en"&gt;&lt;p lang="en" dir="ltr"&gt;&lt;a href="https://twitter.com/hashtag/publication?src=hash"&gt;#publication&lt;/a&gt; I tweeted this from a bibtex file.&lt;a href="https://t.co/NGVlRGqKSJ"&gt;https://t.co/NGVlRGqKSJ&lt;/a&gt;&lt;br&gt;bibtex: &lt;a href="https://t.co/0UEkvyBKAM"&gt;https://t.co/0UEkvyBKAM&lt;/a&gt; &lt;a href="https://t.co/OpbAt1h3OP"&gt;pic.twitter.com/OpbAt1h3OP&lt;/a&gt;&lt;/p&gt;&amp;mdash; John Kitchin (@johnkitchin) &lt;a href="https://twitter.com/johnkitchin/status/768838551140261894"&gt;August 25, 2016&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;p&gt;
That seems pretty reasonable. Now I only need to use it about 48,000 times to benefit from the time-savings M-x tweet-bibtex offers compared to manually making all those tweets ;)
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2016 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;
&lt;p&gt;&lt;a href="/org/2016/08/25/Automated-bibtex-entry-tweeting.org"&gt;org-mode source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Org-mode version = 8.3.4&lt;/p&gt;
]]></content:encoded>
    </item>
  </channel>
</rss>
