<?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>Scoring elfeed articles</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2017/01/05/Scoring-elfeed-articles</link>
      <pubDate>Thu, 05 Jan 2017 11:18:29 EST</pubDate>
      <category><![CDATA[elfeed]]></category>
      <category><![CDATA[emacs]]></category>
      <guid isPermaLink="false">NBZRWOsJw4yDOAn4_m_OYu7AMz8=</guid>
      <description>Scoring elfeed articles</description>
      <content:encoded><![CDATA[


&lt;p&gt;
I use &lt;a href="https://github.com/skeeto/elfeed"&gt;elfeed&lt;/a&gt; to read RSS feeds of scientific journals, python, emacs, and lisp blogs, and the emacs stackexchange feed. Here are the current feeds I follow.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-emacs-lisp"&gt;(mapcar 'list elfeed-feeds)
&lt;/pre&gt;
&lt;/div&gt;

&lt;table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides"&gt;


&lt;colgroup&gt;
&lt;col  class="org-left" /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class="org-left"&gt;(&lt;a href="http://syndic8.scopus.com/getMessage?registrationId=ADEJAEEKHFESCDEOCDFOAHGSCDHSAKHREFMSADHNJA"&gt;http://syndic8.scopus.com/getMessage?registrationId=ADEJAEEKHFESCDEOCDFOAHGSCDHSAKHREFMSADHNJA&lt;/a&gt; cmu)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/accacs"&gt;http://feeds.feedburner.com/acs/accacs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/enfuem"&gt;http://feeds.feedburner.com/acs/enfuem&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/esthag"&gt;http://feeds.feedburner.com/acs/esthag&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/jacsat"&gt;http://feeds.feedburner.com/acs/jacsat&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/jpcbfk"&gt;http://feeds.feedburner.com/acs/jpcbfk&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/jpccck"&gt;http://feeds.feedburner.com/acs/jpccck&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/jpclcd"&gt;http://feeds.feedburner.com/acs/jpclcd&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/cmatex"&gt;http://feeds.feedburner.com/acs/cmatex&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/jctcce"&gt;http://feeds.feedburner.com/acs/jctcce&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/jcisd8"&gt;http://feeds.feedburner.com/acs/jcisd8&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.feedburner.com/acs/iecred"&gt;http://feeds.feedburner.com/acs/iecred&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.aps.org/rss/recent/prl.xml"&gt;http://feeds.aps.org/rss/recent/prl.xml&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.aps.org/rss/recent/prb.xml"&gt;http://feeds.aps.org/rss/recent/prb.xml&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://www.sciencemag.org/rss/current.xml"&gt;http://www.sciencemag.org/rss/current.xml&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.nature.com/nature/rss/current"&gt;http://feeds.nature.com/nature/rss/current&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.nature.com/nmat/rss/current"&gt;http://feeds.nature.com/nmat/rss/current&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://feeds.nature.com/nchem/rss/current"&gt;http://feeds.nature.com/nchem/rss/current&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://rss.sciencedirect.com/publication/science/09270256"&gt;http://rss.sciencedirect.com/publication/science/09270256&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://onlinelibrary.wiley.com/rss/journal/10.1002/(ISSN)"&gt;http://onlinelibrary.wiley.com/rss/journal/10.1002/(ISSN)&lt;/a&gt;1521-3773&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://scitation.aip.org/rss/content/aip/journal/jcp/latestarticles;jsessionid=6k76xb11z253.x-aip-live-06?fmt=rss"&gt;http://scitation.aip.org/rss/content/aip/journal/jcp/latestarticles;jsessionid=6k76xb11z253.x-aip-live-06?fmt=rss&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;(&lt;a href="http://planetpython.org/rss20.xml"&gt;http://planetpython.org/rss20.xml&lt;/a&gt; python)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;(&lt;a href="http://planet.scipy.org/rss20.xml"&gt;http://planet.scipy.org/rss20.xml&lt;/a&gt; python)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;(&lt;a href="http://planet.emacsen.org/atom.xml"&gt;http://planet.emacsen.org/atom.xml&lt;/a&gt; emacs)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://planet.lisp.org/rss20.xml"&gt;http://planet.lisp.org/rss20.xml&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="http://catalysis-preprint-archive.github.io/updates.rss"&gt;http://catalysis-preprint-archive.github.io/updates.rss&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;&lt;a href="https://www.cmu.edu/policies/news/rss-feed.rss"&gt;https://www.cmu.edu/policies/news/rss-feed.rss&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class="org-left"&gt;(&lt;a href="http://emacs.stackexchange.com/feeds"&gt;http://emacs.stackexchange.com/feeds&lt;/a&gt; emacs)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
I get a lot of articles this way. The current size of the database is:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-emacs-lisp"&gt;(elfeed-db-size)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
79721
&lt;/pre&gt;

&lt;p&gt;
Elfeed tells me I have over 300 unread entries to review at the moment.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-emacs-lisp"&gt;(elfeed-search--count-unread)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
341/363:24
&lt;/pre&gt;

&lt;p&gt;
To deal with this deluge, I have done a couple of things. I set up some new key-bindings so I can alternate marking entries as read if the titles do not look interesting. These keybindings let me alternate fingers, so they do not get too tired (that really happens some days!).
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-emacs-lisp"&gt;&lt;span style="color: #8D8D84;"&gt;;; &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;help me alternate fingers in marking entries as read&lt;/span&gt;
(define-key elfeed-search-mode-map (kbd &lt;span style="color: #008000;"&gt;"f"&lt;/span&gt;) 'elfeed-search-untag-all-unread)
(define-key elfeed-search-mode-map (kbd &lt;span style="color: #008000;"&gt;"j"&lt;/span&gt;) 'elfeed-search-untag-all-unread)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
I also set up some auto-tagging of the emacs and python feeds, and setup some custom faces so these tags are highlighted so they are easy to see. Anything highlighted in blue is related to emacs, green is related to python, and pink is related to my department, and I can type s, then the tag to see only those entries.  Here is what my feed looks like:
&lt;/p&gt;

&lt;p&gt;
&lt;img src="/media/date-05-01-2017-time-08-42-33.png"&gt; 
&lt;/p&gt;



&lt;p&gt;
Today I want to explore adding tags to entries to further prioritize them. There is a way to tag entries that is described here: &lt;a href="https://github.com/skeeto/elfeed#tag-hooks"&gt;https://github.com/skeeto/elfeed#tag-hooks&lt;/a&gt; where you can create patterns to match an entry feed title, url, title or link. Basically, you create a function that takes an entry, amd have it add or remove a tag conditionally.
&lt;/p&gt;

&lt;p&gt;
I want to tag entries that meet certain criteria, for example keywords, and set a tag based on the number of matches. Ideally, one day this would be integrated with machine learning so it could rank entries by other entries I have liked, but today we setup code that will create a score for an entry based on the number of matches, and then tag it so that it will get highlighted for me.  First, we define two custom faces and setup elfeed to use them. I will use two tags: important and relevant. relevant will be for entries that get a score of at least 1, and important for entries that get a score greater than 1.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-emacs-lisp"&gt;(&lt;span style="color: #0000FF;"&gt;defface&lt;/span&gt; &lt;span style="color: #BA36A5;"&gt;relevant-elfeed-entry&lt;/span&gt;
  `((t &lt;span style="color: #006FE0;"&gt;:background&lt;/span&gt; ,(color-lighten-name &lt;span style="color: #008000;"&gt;"orange1"&lt;/span&gt; 40)))
  &lt;span style="color: #036A07;"&gt;"Marks a relevant Elfeed entry."&lt;/span&gt;)

(&lt;span style="color: #0000FF;"&gt;defface&lt;/span&gt; &lt;span style="color: #BA36A5;"&gt;important-elfeed-entry&lt;/span&gt;
  `((t &lt;span style="color: #006FE0;"&gt;:background&lt;/span&gt; ,(color-lighten-name &lt;span style="color: #008000;"&gt;"OrangeRed2"&lt;/span&gt; 40)))
  &lt;span style="color: #036A07;"&gt;"Marks an important Elfeed entry."&lt;/span&gt;)

(&lt;span style="color: #0000FF;"&gt;push&lt;/span&gt; '(relevant relevant-elfeed-entry)
      elfeed-search-face-alist)

(&lt;span style="color: #0000FF;"&gt;push&lt;/span&gt; '(important important-elfeed-entry)
      elfeed-search-face-alist)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
In elfeed, each entry is a structure, and we can access the title and content for matching. Here is an example of a simple scoring function. The idea is just to match patterns, and then add to the score if it matches. This is not as advanced as &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/gnus/Scoring.html#Scoring"&gt;gnus scoring&lt;/a&gt;, but it is a good starting point.
&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;score-elfeed-entry&lt;/span&gt; (entry)
  (&lt;span style="color: #0000FF;"&gt;let&lt;/span&gt; ((title (elfeed-entry-title entry))
        (content (elfeed-deref (elfeed-entry-content entry)))
        (score 0))
    (&lt;span style="color: #0000FF;"&gt;loop&lt;/span&gt; for (pattern n) in '((&lt;span style="color: #008000;"&gt;"alloy"&lt;/span&gt; 1)
                               (&lt;span style="color: #008000;"&gt;"machine learning&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;\\&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #008000;"&gt;neural"&lt;/span&gt; 1)
                               (&lt;span style="color: #008000;"&gt;"database"&lt;/span&gt; 1)
                               (&lt;span style="color: #008000;"&gt;"reproducible"&lt;/span&gt; 1)
                               (&lt;span style="color: #008000;"&gt;"carbon dioxide&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;\\&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #008000;"&gt;CO2"&lt;/span&gt; 1)
                               (&lt;span style="color: #008000;"&gt;"oxygen evolution&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;\\&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #008000;"&gt;OER&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;\\&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #008000;"&gt;electrolysis"&lt;/span&gt; 1)
                               (&lt;span style="color: #008000;"&gt;"perovskite&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;\\&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #008000;"&gt;polymorph&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;\\&lt;/span&gt;&lt;span style="color: #008000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #008000;"&gt;epitax"&lt;/span&gt; 1)
                               (&lt;span style="color: #008000;"&gt;"kitchin"&lt;/span&gt; 2))
          if (string-match pattern title)
          do (&lt;span style="color: #0000FF;"&gt;incf&lt;/span&gt; score n)
          if (string-match pattern content)
          do (&lt;span style="color: #0000FF;"&gt;incf&lt;/span&gt; score n))
    (message &lt;span style="color: #008000;"&gt;"%s - %s"&lt;/span&gt; title score)

    &lt;span style="color: #8D8D84;"&gt;;; &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;store score for later in case I ever integrate machine learning&lt;/span&gt;
    (&lt;span style="color: #0000FF;"&gt;setf&lt;/span&gt; (elfeed-meta entry &lt;span style="color: #006FE0;"&gt;:my/score&lt;/span&gt;) score)

    (&lt;span style="color: #0000FF;"&gt;cond&lt;/span&gt;
     ((= score 1)
      (elfeed-tag entry 'relevant))
     ((&amp;gt; score 1)
      (elfeed-tag entry 'important)))
    entry))

(add-hook 'elfeed-new-entry-hook 'score-elfeed-entry)
&lt;/pre&gt;
&lt;/div&gt;

&lt;table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides"&gt;


&lt;colgroup&gt;
&lt;col  class="org-left" /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class="org-left"&gt;score-elfeed-entry&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
Now, new entries automatically get tagged with relevant or important, depending on the score that function gives them, and they get color-coded. Now, the feed looks like this:
&lt;/p&gt;

&lt;p&gt;
&lt;img src="/media/date-05-01-2017-time-11-10-42.png"&gt; 
&lt;/p&gt;


&lt;p&gt;
I saved some bookmarks to see just the important or relevant ones (&lt;a href="http://nullprogram.com/blog/2015/12/03/"&gt;http://nullprogram.com/blog/2015/12/03/&lt;/a&gt;) so I can see new relevant entries with C-x r b and selecting the relevant bookmark. These work from anywhere in Emacs.
&lt;/p&gt;

&lt;pre class="example"&gt;
  @6-months-ago +unread +relev  @6-months-ago +unread +relevant
  elfeed @6-months-ago +unread  @6-months-ago +unread +important
&lt;/pre&gt;

&lt;p&gt;
I usually access elfeed from a command that shows me everything. Here, I define key-bindings to show me just the important or relevant ones. I could not see a way to get an or in there to show me both of them. These keys make it a one key press to show only these entries, and then get back to the full list.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-emacs-lisp"&gt;(define-key elfeed-search-mode-map (kbd &lt;span style="color: #008000;"&gt;"i"&lt;/span&gt;)
  (&lt;span style="color: #0000FF;"&gt;lambda&lt;/span&gt; () (&lt;span style="color: #0000FF;"&gt;interactive&lt;/span&gt;)
    (elfeed-search-set-filter &lt;span style="color: #008000;"&gt;"@6-months-ago +unread +important"&lt;/span&gt;)))

(define-key elfeed-search-mode-map (kbd &lt;span style="color: #008000;"&gt;"v"&lt;/span&gt;)
  (&lt;span style="color: #0000FF;"&gt;lambda&lt;/span&gt; () (&lt;span style="color: #0000FF;"&gt;interactive&lt;/span&gt;)
    (elfeed-search-set-filter &lt;span style="color: #008000;"&gt;"@6-months-ago +unread +relevant"&lt;/span&gt;)))

(define-key elfeed-search-mode-map (kbd &lt;span style="color: #008000;"&gt;"c"&lt;/span&gt;)
  (&lt;span style="color: #0000FF;"&gt;lambda&lt;/span&gt; () (&lt;span style="color: #0000FF;"&gt;interactive&lt;/span&gt;)
    (elfeed-search-set-filter &lt;span style="color: #008000;"&gt;"@6-months-ago +unread"&lt;/span&gt;)))
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
That summarizes the experiment of the day. There is clearly some room for improvement on the scoring function, e.g. moving the patterns out of the function and into a customizable variable, making the patterns be specific to either the title or content, etc. I am going to try this for a few days and see if it is actually helpful first though.
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2017 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/2017/01/05/Scoring-elfeed-articles.org"&gt;org-mode source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Org-mode version = 9.0.3&lt;/p&gt;]]></content:encoded>
    </item>
  </channel>
</rss>
