New publication in ACS Catalysis on composition dependent alloy electronic structure

| categories: publication, news | tags:

In this collaborative paper we map out the electronic structure of a Cu-Pd alloy across composition space, and then correlate that electronic structure with the reactivity of the alloy. We experimentally measure the average energy of the filled valence band, and show it is similar to the calculated d-band center. We then show how those measured electronic structure properties correlate with the H2\D2 exchange kinetics. The combination of experiments on composition spread alloy films (CSAF) and theory provides an integrated understanding of alloy reactivity in this system.

@article{gumuslu-2015-correl-elect,
  author =       {G. Gumuslu and P. Kondratyuk and J. R. Boes and B. Morreale
                  and J. B. Miller and J. R. Kitchin and A. J. Gellman},
  title =        {Correlation of Electronic Structure With Catalytic Activity:
                  \ce{H2}-\ce{D2} Exchange Across \ce{Cu_{x}Pd_{1-x} Composition
                  Space},
  journal =      {ACS Catalysis},
  volume =       {5},
  pages =        {3137-3147},
  year =         2015,
  doi =          {10.1021/cs501586t},
  url =          {https://doi.org/10.1021/cs501586t},
  date_added =   {Fri Apr 24 14:47:29 2015},
}

Copyright (C) 2015 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter

Commenting in org-files

| categories: org | tags:

There was an interesting discussion on the org-mode mail list about putting comments in org files. Eric Fraga suggested using inline tasks, and customizing the export of them so they make a footnote, or use the todonotes package (suggested by Marcin Borkowski). Here is Eric's export. A big advantage of this is integration with the Agenda, so you can see what there is todo in your document.

  (setq org-inlinetask-export-templates
        '((latex "%s\\footnote{%s\\\\ %s}\\marginpar{\\fbox{\\thefootnote}}"
                 '((unless
                       (eq todo "")
                     (format "\\fbox{\\textsc{%s%s}}" todo priority))
                   heading content))))

Eric Abrahamsen suggested an idea to use a link syntax. I like the idea a lot, so here we develop some ideas. A link has two parts, the path, and description. A simple comment would just be a simple link, probably in double square brackets so you can have spaces in your comment. COMMENT It might be feasible to use COMMENT the description to "mark text" that the comment refers to. The remaining question is what functionality should our link have when you click on it, and how to export it. For functionality, a click will show the comment in the minibuffer and offer to delete it. For export, for now we will make it export with todonotes in LaTeX, and as a red COMMENT with a tooltip in html. To use this, you need to have the LaTeX package todonotes included in your org file.

Here is our comment link.

(org-add-link-type
 "comment"
 (lambda (linkstring)
   (let ((elm (org-element-context))
         (use-dialog-box nil))
     (when (y-or-n-p "Delete comment? ")
       (setf (buffer-substring
              (org-element-property :begin elm)
              (org-element-property :end elm))
             (cond
              ((org-element-property :contents-begin elm)
               (buffer-substring
                (org-element-property :contents-begin elm)
                (org-element-property :contents-end elm)))
              (t
               ""))))))
 (lambda (keyword desc format)
   (cond
    ((eq format 'html)
     (format "<font color=\"red\"><abbr title=\"%s\" color=\"red\">COMMENT</abbr></font> %s" keyword (or desc "")))
    ((eq format 'latex)
     (format "\\todo{%s}{%s}" keyword (or desc ""))))))

It would be convenient to have a quick function for adding a comment to some highlighted text.

(defun add-comment (begin end)
  (interactive "r")
  (if (region-active-p)
      (let ((selected-text (buffer-substring begin end)))
        (setf (buffer-substring begin end)
              (format "[[comment:%s][%s]]"
                      (read-input "Comment: ") selected-text)))
  (insert (format  "[[comment:%s]]" (read-input "Comment: ")))))

Test 1: COMMENT

COMMENT Test 2

That is it. I could see a few other enhancements that might be very useful, e.g. a command to list all the comments, remove all the comments, etc… I am pretty satisfied with this for now though.

1 An updated approach to comments.

Rainer asked about making some comments inline. It would be nice if a single link syntax could accommodate both styles of comments. I previously developed an approach to extend links with attributes (http://kitchingroup.cheme.cmu.edu/blog/2015/02/05/Extending-the-org-mode-link-syntax-with-attributes/ ), which I will reuse here for that purpose. The idea is to add an ":inline" attribute to change the export behavior. We only modify the LaTeX export here.

(org-add-link-type
 "comment"
 ;;  follow function
(lambda (linkstring)
   (let ((elm (org-element-context))
         (use-dialog-box nil))
     (when (y-or-n-p "Delete comment? ")
       (setf (buffer-substring
              (org-element-property :begin elm)
              (org-element-property :end elm))
             (cond
              ((org-element-property :contents-begin elm)
               (buffer-substring
                (org-element-property :contents-begin elm)
                (org-element-property :contents-end elm)))
              (t
               ""))))))
 ;; format function
 (lambda (path description format)
   (let* ((data (read (concat "(" path ")")))
          (head (car data))
          (plist (cdr data)))
     (cond
      ((eq format 'html)
       (format "<font color=\"red\"><abbr title=\"%s\" color=\"red\">COMMENT</abbr></font> %s" path (or description "")))
      ((eq format 'latex)
       (format "\\todo%s{%s}%s"
               (if (-contains? data :inline) "[inline]" "")
               (mapconcat (lambda (s)
                            (format "%s" s))
                          (-remove-item :inline data) " ")
               (if description (format "{%s}" description) "")))))))

Here are some examples of the syntax:

[[comment: :inline the rest of your text]]

[[comment:Some text you want to highlight]]

[[comment:Some text you want to highlight :inline]]

It doesn't matter where the :inline attribute is added. This seems to work pretty well.

We can modify our convenience function to allow us to use a prefix arg to make the comment inline. Here is one way to do it.

(defun add-comment (begin end &optional arg)
  "Comment the region. With a prefix ARG, make the comment inline."
  (interactive (list (region-beginning)
                     (region-end)
                     current-prefix-arg))
  (let ((inline (if arg ":inline " "")))
        (if (region-active-p)
            (let ((selected-text (buffer-substring begin end)))
              (setf (buffer-substring begin end)
                    (format
                     "[[comment:%s%s][%s]]"
                     inline
                     (read-input "Comment: ") selected-text)))
          (insert (format
                   "[[comment:%s%s]]"
                   inline
                   (read-input "Comment: "))))))
add-comment

Test COMMENT text to COMMENT comment on.

Copyright (C) 2015 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter

New publication in J. Chem. Physics on calculating oxide properties with DFT+U

| categories: publication, news | tags:

In this paper we demonstrate a novel method to use linear response DFT+U in a thermodynamic cycle to more accurately calculate metal oxide properties such as band gaps and reaction energies. This was a collaborative paper with ExxonMobil. Congratulations Zhongnan!

@article{xu-2015-accur-u,
  author =       "Xu, Zhongnan and Joshi, Yogesh V. and Raman, Sumathy and
                  Kitchin, John R.",
  title =        {Accurate Electronic and Chemical Properties of 3d Transition
                  Metal Oxides Using a Calculated Linear Response U and a DFT +
                  U(V) Method},
  journal =      "The Journal of Chemical Physics",
  volume =       142,
  number =       14,
  pages =        144701,
  year =         2015,
  doi =          {10.1063/1.4916823},
  url =
                  "http://scitation.aip.org/content/aip/journal/jcp/142/14/10.1063/1.4916823",
  eid =          144701,
}

Copyright (C) 2015 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter

Using the Scopus api with xml output

| categories: scopus, xml, python | tags:

According to http://api.elsevier.com/documentation/AbstractRetrievalAPI.wadl , the native form of the Scopus abstract document is xml, and the full abstract cannot always be represented as json. So… I am going to just bite the bullet and learn to deal with the xml. This is a companion post to http://kitchingroup.cheme.cmu.edu/blog/2015/04/04/Making-highly-linked-bibliographies-from-the-Scopus-API/ . Most of the code in this post gets tangled out to scopus_xml.py. I know it is not totally robust yet, but I have been using it for a lot of analysis, and it works pretty well so far.

This is another long post, with code that probably runs off screen. You can see the end result of what we do in this post here: http://kitchingroup.cheme.cmu.edu/publications.html .

We start with a general function to return an xml elementtree. We build in some caching to avoid downloading things we already have; this is slow, and there are limits on how many times you can download.

import requests
import os
import xml.etree.ElementTree as ET

from my_scopus import MY_API_KEY

def get_abstract_info(EID, refresh=False):
    'Get and save the json data for EID.'
    base = 'scopus-xml/get_abstract_info'
    if not os.path.exists(base):
        os.makedirs(base)

    fname = '{0}/{1}'.format(base, EID)
    if os.path.exists(fname) and not refresh:
        with open(fname) as f:
            return ET.fromstring(f.read())

    # Otherwise retrieve and save results
    url = ("http://api.elsevier.com/content/abstract/eid/" + EID + '?view=META_ABS')
    resp = requests.get(url,
                    headers={'Accept':'application/xml',
                             'X-ELS-APIKey': MY_API_KEY})
    with open(fname, 'w') as f:
        f.write(resp.text.encode('utf-8'))

    results = ET.fromstring(resp.text.encode('utf-8'))

    return results

Next, we do some introspection to see what we have.

from scopus_xml import *
#results = get_abstract_info('2-s2.0-84896759135')
#results = get_abstract_info('2-s2.0-84924911828')
results = get_abstract_info('2-s2.0-84901638552')
for el in results:
    print el.tag
    for el1 in el:
        print '  -->',el1.tag
    print
{http://www.elsevier.com/xml/svapi/abstract/dtd}coredata --> {http://prismstandard.org/namespaces/basic/2.0/}url --> {http://purl.org/dc/elements/1.1/}identifier --> {http://www.elsevier.com/xml/svapi/abstract/dtd}eid --> {http://prismstandard.org/namespaces/basic/2.0/}doi --> {http://purl.org/dc/elements/1.1/}title --> {http://prismstandard.org/namespaces/basic/2.0/}aggregationType --> {http://www.elsevier.com/xml/svapi/abstract/dtd}srctype --> {http://www.elsevier.com/xml/svapi/abstract/dtd}citedby-count --> {http://prismstandard.org/namespaces/basic/2.0/}publicationName --> {http://purl.org/dc/elements/1.1/}publisher --> {http://www.elsevier.com/xml/svapi/abstract/dtd}source-id --> {http://prismstandard.org/namespaces/basic/2.0/}issn --> {http://prismstandard.org/namespaces/basic/2.0/}volume --> {http://prismstandard.org/namespaces/basic/2.0/}startingPage --> {http://prismstandard.org/namespaces/basic/2.0/}endingPage --> {http://prismstandard.org/namespaces/basic/2.0/}pageRange --> {http://prismstandard.org/namespaces/basic/2.0/}coverDate --> {http://purl.org/dc/elements/1.1/}creator --> {http://purl.org/dc/elements/1.1/}description --> {http://www.elsevier.com/xml/svapi/abstract/dtd}link --> {http://www.elsevier.com/xml/svapi/abstract/dtd}link --> {http://www.elsevier.com/xml/svapi/abstract/dtd}link {http://www.elsevier.com/xml/svapi/abstract/dtd}affiliation --> {http://www.elsevier.com/xml/svapi/abstract/dtd}affilname {http://www.elsevier.com/xml/svapi/abstract/dtd}authors --> {http://www.elsevier.com/xml/svapi/abstract/dtd}author --> {http://www.elsevier.com/xml/svapi/abstract/dtd}author

Now, some examples for myself to see how to get things.

from scopus_xml import *

results = get_abstract_info('2-s2.0-84901638552')

coredata = results.find('./{http://www.elsevier.com/xml/svapi/abstract/dtd}coredata')

print coredata.find('{http://www.elsevier.com/xml/svapi/abstract/dtd}srctype').text
print coredata.find('{http://www.elsevier.com/xml/svapi/abstract/dtd}source-id').text

#authors = results.find('./{http://www.elsevier.com/xml/svapi/abstract/dtd}authors')
#for author in results.find('./{http://www.elsevier.com/xml/svapi/abstract/dtd}authors'):
#    print author.find('{http://www.elsevier.com/xml/ani/common}indexed-name').text

for creator in coredata.find('{http://purl.org/dc/elements/1.1/}creator'):
    print creator.attrib

print coredata.find('{http://purl.org/dc/elements/1.1/}title').text
print coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}publicationName').text
print coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}volume').text
print coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}pageRange').text
print coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}coverDate').text
print coredata.find('{http://www.elsevier.com/xml/svapi/abstract/dtd}citedby-count').text
print coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}doi').text

for link in coredata.findall('{http://www.elsevier.com/xml/svapi/abstract/dtd}link'):
    if link.attrib['rel'] == 'scopus':
        print link.attrib['href']
    else:
        print link.attrib['href']

# alternative xpath to get the link
print coredata.find("./{http://www.elsevier.com/xml/svapi/abstract/dtd}link/[@rel='scopus']").attrib['href']
j 22746 {'auid': '55569461200', 'seq': '1'} Relating the electronic structure and reactivity of the 3d transition metal monoxide surfaces Catalysis Communications 52 60-64 2014-07-05 2 10.1016/j.catcom.2013.10.028 http://api.elsevier.com/content/abstract/scopus_id/84901638552 http://www.scopus.com/inward/record.url?partnerID=HzOxMe3b&scp=84901638552&origin=inward http://api.elsevier.com/content/search/scopus?query=refeid%282-s2.0-84901638552%29 http://www.scopus.com/inward/record.url?partnerID=HzOxMe3b&scp=84901638552&origin=inward

That is basically it. In the next sections, we basically recreate the previous functions from scopus.py using the xml data.

1 Authors

def get_author_link(EID):
    results = get_abstract_info(EID)
    authors = results.find('./{http://www.elsevier.com/xml/svapi/abstract/dtd}authors')
    if authors is None:
        return 'No authors found'
    s = []

    for author in authors:
        name = author.find('{http://www.elsevier.com/xml/ani/common}indexed-name').text
        auid = author.attrib['auid']
        s += ['<a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId={0}">{1}</a>'.format(auid, name)]

    return ', '.join(s)
from scopus_xml import *
print get_author_link('2-s2.0-84896759135')
print get_author_link('2-s2.0-84901638552')
<a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=8724572500">Thompson R.L.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=22981503200">Shi W.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=6506329719">Albenze E.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=23004637900">Kusuma V.A.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=55676869000">Hopkinson D.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=7003584159">Damodaran K.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=55005205100">Lee A.S.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=7004212771">Kitchin J.R.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=6701399651">Luebke D.R.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=24081524800">Nulwala H.</a>
<a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=55569461200">Xu Z.</a>, <a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=7004212771">Kitchin J.R.</a>

2 Journal

def get_journal_link(EID):
    results = get_abstract_info(EID)
    coredata = results.find('./{http://www.elsevier.com/xml/svapi/abstract/dtd}coredata')

    journal = coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}publicationName').text
    sid = coredata.find('{http://www.elsevier.com/xml/svapi/abstract/dtd}source-id').text
    s = '<a href="http://www.scopus.com/source/sourceInfo.url?sourceId={sid}">{journal}</a>'

    return s.format(sid=sid, journal=journal)
from scopus_xml import *
print get_journal_link('2-s2.0-84901638552')
<a href="http://www.scopus.com/source/sourceInfo.url?sourceId=22746">Catalysis Communications</a>

3 DOI link

def get_doi_link(EID):
    results = get_abstract_info(EID)
    coredata = results.find('./{http://www.elsevier.com/xml/svapi/abstract/dtd}coredata')
    doi = coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}doi')
    if doi is not None: doi = doi.text
    s = '<a href="https://doi.org/{doi}">doi:{doi}</a>'
    return s.format(doi=doi)
from scopus_xml import *
print get_doi_link('2-s2.0-84901638552')
doi:10.1016/j.catcom.2013.10.028

4 Abstract link

def get_abstract_link(EID):
    results = get_abstract_info(EID)
    coredata = results.find('./{http://www.elsevier.com/xml/svapi/abstract/dtd}coredata')

    data = get_abstract_info(EID)

    title = coredata.find('{http://purl.org/dc/elements/1.1/}title').text.encode('utf-8')
    link = coredata.find("./{http://www.elsevier.com/xml/svapi/abstract/dtd}link/[@rel='scopus']").attrib['href'].encode('utf-8')
    s = '<a href="{link}">{title}</a>'
    return s.format(link=link, title=title)
from scopus_xml import *
print get_abstract_link('2-s2.0-84901638552')
Relating the electronic structure and reactivity of the 3d transition metal monoxide surfaces

5 Citation image

def get_cite_img_link(EID):
    results = get_abstract_info(EID)
    coredata = results.find('./{http://www.elsevier.com/xml/svapi/abstract/dtd}coredata')
    doi = coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}doi')
    if doi is not None: doi = doi.text
    s = '<img src="http://api.elsevier.com/content/abstract/citation-count?doi={doi}&httpAccept=image/jpeg&apiKey={apikey}"></img>'

    return s.format(doi=doi, apikey=MY_API_KEY, cite_link=None)
from scopus_xml import *
print get_cite_img_link('2-s2.0-84901638552')

6 Getting it all together

def get_html_citation(EID):
    results = get_abstract_info(EID)
    coredata = results.find('./{http://www.elsevier.com/xml/svapi/abstract/dtd}coredata')
    s = '{authors}, <i>{title}</i>, {journal}, <b>{volume}{issue}</b>, {pages}, ({year}), {doi}, {cites}.'

    issue = ''
    if coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}issueIdentifier') is not None:
        issue = '({})'.format(    coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}issueIdentifier').text)

    volume = coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}volume')
    if volume is not None:
        volume = coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}volume').text
    else:
        volume = 'None'

    pages = ''
    if coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}pageRange') is not None:
        pages = 'p. ' + coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}pageRange').text
    elif coredata.find('{http://www.elsevier.com/xml/svapi/abstract/dtd}article-number') is not None:
        pages = coredata.find('{http://www.elsevier.com/xml/svapi/abstract/dtd}article-number').text
    else:
        pages = 'no pages found'


    year = coredata.find('{http://prismstandard.org/namespaces/basic/2.0/}coverDate').text

    return s.format(authors=get_author_link(EID),
                    title=get_abstract_link(EID),
                    journal=get_journal_link(EID),
                    volume=volume,
                    issue=issue,
                    pages=pages,
                    year=year,
                    doi=get_doi_link(EID),
                    cites=get_cite_img_link(EID))
from scopus_xml import *
print '<ol>'
print '<li>',get_html_citation('2-s2.0-84896759135'),'</li>'
print
print '<li>',get_html_citation('2-s2.0-84924911828'),'</li>'
print
print '<li>',get_html_citation('2-s2.0-84901638552'),'</li>'
print '</ol>'
  1. Thompson R.L., Shi W., Albenze E., Kusuma V.A., Hopkinson D., Damodaran K., Lee A.S., Kitchin J.R., Luebke D.R., Nulwala H., Probing the effect of electron donation on CO2 absorbing 1,2,3-triazolide ionic liquids, RSC Advances, 4(25), p. 12748-12755, (2014-03-17), doi:10.1039/c3ra47097k, .
  2. Xu Z., Kitchin J.R., Relationships between the surface electronic and chemical properties of doped 4d and 5d late transition metal dioxides, Journal of Chemical Physics, 142(10), 104703, (2015-03-14), doi:10.1063/1.4914093, .
  3. Xu Z., Kitchin J.R., Relating the electronic structure and reactivity of the 3d transition metal monoxide surfaces, Catalysis Communications, 52, p. 60-64, (2014-07-05), doi:10.1016/j.catcom.2013.10.028, .

7 Finally getting my documents

Here we get the EIDs from a search query. We use these in the next section to get a new bibliography.

import requests
import json
from my_scopus import MY_API_KEY
resp = requests.get("http://api.elsevier.com/content/search/scopus?query=AU-ID(7004212771)&field=eid,aggregationType&count=100",
                    headers={'Accept':'application/json',
                             'X-ELS-APIKey': MY_API_KEY})

results = resp.json()

return [[str(r['eid']), str(r['prism:aggregationType'])] for r in results['search-results']["entry"] if str(r['prism:aggregationType']) == 'Journal']
2-s2.0-84924911828 Journal
2-s2.0-84923164062 Journal
2-s2.0-84924778427 Journal
2-s2.0-84924130725 Journal
2-s2.0-84901638552 Journal
2-s2.0-84898934670 Journal
2-s2.0-84896759135 Journal
2-s2.0-84896380535 Journal
2-s2.0-84896585411 Journal
2-s2.0-84916613197 Journal
2-s2.0-84908637059 Journal
2-s2.0-84880986072 Journal
2-s2.0-84881394200 Journal
2-s2.0-84873706643 Journal
2-s2.0-84876703352 Journal
2-s2.0-84867809683 Journal
2-s2.0-84864914806 Journal
2-s2.0-84865730756 Journal
2-s2.0-84864592302 Journal
2-s2.0-84863684845 Journal
2-s2.0-84866142469 Journal
2-s2.0-84861127526 Journal
2-s2.0-80052944171 Journal
2-s2.0-80051809046 Journal
2-s2.0-79953651013 Journal
2-s2.0-79952860396 Journal
2-s2.0-77956568341 Journal
2-s2.0-77954747189 Journal
2-s2.0-77956693843 Journal
2-s2.0-77949916234 Journal
2-s2.0-77955464573 Journal
2-s2.0-72049114200 Journal
2-s2.0-73149124752 Journal
2-s2.0-73149109096 Journal
2-s2.0-67449106405 Journal
2-s2.0-63649114440 Journal
2-s2.0-60849113132 Journal
2-s2.0-58649114498 Journal
2-s2.0-40949100780 Journal
2-s2.0-33750804660 Journal
2-s2.0-20544467859 Journal
2-s2.0-15744396507 Journal
2-s2.0-9744261716 Journal
2-s2.0-13444307808 Journal
2-s2.0-3042820285 Journal
2-s2.0-2942640180 Journal
2-s2.0-0142023762 Journal
2-s2.0-0141924604 Journal
2-s2.0-0037368024 Journal
2-s2.0-0037197884 Journal

8 And my html bibliography

This generates my blog bibliography page..

from scopus_xml import *

import requests
import json
from my_scopus import MY_API_KEY
resp = requests.get("http://api.elsevier.com/content/search/scopus?query=AU-ID(7004212771)&field=eid,aggregationType&count=100",
                    headers={'Accept':'application/json',
                             'X-ELS-APIKey': MY_API_KEY})

results = resp.json()

data = [[str(r['eid']), str(r['prism:aggregationType'])] for r in
        results['search-results']["entry"] if str(r['prism:aggregationType']) == 'Journal']


with open('../publications.html.mako', 'w') as f:
    f.write('''<%inherit file="_templates/site.mako" />
<article class="page_box">
<%self:filter chain="markdown">

<h1>Online collections of our work</h1>
Pick your favorite:
<ul>
<li><a href="http://orcid.org/0000-0003-2625-9232">orcid:0000-0003-2625-9232</a></li>

<li><a href="http://www.researcherid.com/rid/A-2363-2010">researcherid:A-2363-2010</a></li>

<li><a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=7004212771">scopusid:7004212771</a></li>

<li><a href="https://scholar.google.com/citations?user=jD_4h7sAAAAJ">Google Scholar</a></li>

<li><a href="https://www.researchgate.net/profile/John_Kitchin">Research Gate</a></li>

<li><a href="https://www.growkudos.com/profiles/40205">Kudos</a></li>
</ul>

<h1>Publications</h1>
The authors are linked to their Scopus page, the title linked to the Scopus abstract, the journal linked to the Scopus journal page, and the DOI is linked to https://doi.org which normally redirects you to the journal page.

<ol reversed="reversed">
''')

    for eid,type in data:
        f.write('<li>{}</li>'.format(get_html_citation(eid)))
    f.write('''</ol>

</%self:filter>
</article>
''')

9 Summary

The XML format is not that intuitive to me. It takes some practice writing robust code, e.g. sometimes the find command does not find anything, and then there is not text attribute to get, so you should check for success on finding things. Also, some text is unicode, and you have to take care to encode it, which my library does not do uniformly. Finally, not all journals have things like volume or issue. My formatting code is not super flexible, so these bibliography entries show None in them occasionally. Still, it is not too bad, and this enables a lot of analysis of your publications, as well as displaying them in different ways. See the result of this page here: http://kitchingroup.cheme.cmu.edu/publications.html

Copyright (C) 2015 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter

Making highly linked bibliographies from the Scopus API

| categories: scopus, python | tags:

A given article entry in a bibliography might have the following kinds of links in it. I think we can generate these from a Scopus query.

We are going to look at the document above, with eid=2-s2.0-84901638552. This is another long post, so here is a teaser of what we are doing. For this eid, we want to generate an html entry where each part of the entry is clickable. Here is what we will be able to do by the end of this post:

from scopus import *

print '<ol>', get_html('2-s2.0-84901638552'), '</ol>'
  1. Xu Z.,Kitchin J.R., Relating the electronic structure and reactivity of the 3d transition metal monoxide surfaces, Catalysis Communications, 52, p. 60-64, (2014-07-05), doi:10.1016/j.catcom.2013.10.028, .

In this post, we work out code that works for this document. This code in the form shown here might not work on all entries, e.g. for ones that are in press and are missing data, or for APS journals that have no page range. Later, I will fix those so this is more robust. To minimize repeating the code below, I create a python module here called scopus.py . Tangle it out with org-babel-tangle. As in the last post , I am not sharing my API key here, since it is not clear if that key is private or not.

I like json, so we use that data format here. XML would be more robust, as the Scopus site admits not all of the data can be turned into the json format, but for now we stick to json for its simplicity.

import requests
import json, os
from my_scopus import MY_API_KEY

def get_abstract_info(EID, refresh=False):
    'Get and save the json data for EID.'
    base = 'scopus-data/get_abstract_info'
    if not os.path.exists(base):
        os.makedirs(base)

    fname = '{0}/{1}'.format(base, EID)
    if os.path.exists(fname) and not refresh:
        with open(fname) as f:
            return json.loads(f.read())

    # Otherwise retrieve and save results
    url = ("http://api.elsevier.com/content/abstract/eid/" + EID)
    resp = requests.get(url,
                    headers={'Accept':'application/json',
                             'X-ELS-APIKey': MY_API_KEY})
    results = json.loads(resp.text.encode('utf-8'))
    with open(fname, 'w') as f:
        f.write(json.dumps(results))

    return results

1 Author pages

Here, we generate the html that will make each author a clickable link that goes to their Scopus ID author page.

def get_author_link(EID):
    data = get_abstract_info(EID)
    result = data['abstracts-retrieval-response']
    html = '<a href="http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId={0}">{1}</a>'
    authors = [html.format(auid, name) for auid, name in
               zip([x['@auid'] for x in result['authors']['author']],
                   [x['ce:indexed-name'] for x in result['authors']['author']])]

    return ','.join(authors)
from scopus import *
print get_author_link('2-s2.0-84901638552')
Xu Z.,Kitchin J.R.

2 Journal link

The most important pieces of information we need is the journal name and the source-id from the coredata.

from scopus import *
EID = '2-s2.0-84901638552'
data = get_abstract_info(EID)
result = data['abstracts-retrieval-response']
print result['coredata']['source-id']
print result['coredata']['prism:publicationName']
22746
Catalysis Communications
def get_journal_link(EID):
    data = get_abstract_info(EID)
    result = data['abstracts-retrieval-response']
    sid = result['coredata']['source-id']
    journal = result['coredata']['prism:publicationName']
    s = '<a href="http://www.scopus.com/source/sourceInfo.url?sourceId={sid}">{journal}</a>'

    return s.format(sid=sid, journal=journal)
from scopus import *
print get_journal_link('2-s2.0-84901638552')
Catalysis Communications

3 DOI link

It would be helpful to have a doi link, which is actually independent of Scopus so people without Scopus access can still access information.

from scopus import *
EID = '2-s2.0-84901638552'
data = get_abstract_info(EID)
result = data['abstracts-retrieval-response']
print result['coredata']['prism:doi']
10.1016/j.catcom.2013.10.028
def get_doi_link(EID):
    data = get_abstract_info(EID)
    result = data['abstracts-retrieval-response']
    s = '<a href="https://doi.org/{doi}">doi:{doi}</a>'
    return s.format(doi=result['coredata']['prism:doi'])
from scopus import *
print get_doi_link('2-s2.0-84901638552')
doi:10.1016/j.catcom.2013.10.028

4 Citation count image

It is nice to show impact of a paper by showing the citations. These change with time, so a static view is not ideal. Scopus provides a way to get an image they generate that should update when viewed. We need the doi to get that.

def get_cite_img_link(EID):
    data = get_abstract_info(EID)
    result = data['abstracts-retrieval-response']
    s = '<img src="http://api.elsevier.com/content/abstract/citation-count?doi={doi}&httpAccept=image/jpeg&apiKey={apikey}"></img>'
    return s.format(doi=result['coredata']['prism:doi'].strip(), apikey=MY_API_KEY)
from scopus import *
print get_cite_img_link('2-s2.0-84901638552')

5 The document link

The document link is sort of buried in the coredata. It seems like & has been replaced by &amp; in the json data so we have to do a clunky fix here.

from scopus import *
EID = '2-s2.0-84901638552'
data = get_abstract_info(EID)
result = data['abstracts-retrieval-response']

print result['coredata']['dc:title']
for ref in result['coredata']['link']:
    if ref['@rel'] == 'scopus':
        print ref['@href'].replace('&amp;', '&')
        break
Relating the electronic structure and reactivity of the 3d transition metal monoxide surfaces
http://www.scopus.com/inward/record.url?partnerID=HzOxMe3b&scp=84901638552&origin=inward
def get_abstract_link(EID):
    data = get_abstract_info(EID)
    result = data['abstracts-retrieval-response']
    title = result['coredata']['dc:title']
    for ref in result['coredata']['link']:
        if ref['@rel'] == 'scopus':
            link = ref['@href'].replace('&amp;', '&')

    s = '<a href="{link}">{title}</a>'
    return s.format(link=link, title=title)
from scopus import *
print get_abstract_link('2-s2.0-84901638552')
Relating the electronic structure and reactivity of the 3d transition metal monoxide surfaces

6 Putting it all together

Our goal is ultimately an html formatted citation where nearly every piece is a hyperlink to additional information, e.g. each author is linked to their page, the title is linked to the scopus document page, the journal is linked to the scopus journal page, a DOI link, and an image of the number of citations. Here it is.

def get_html(EID):
    data = get_abstract_info(EID)
    result = data['abstracts-retrieval-response']

    s = '<li>{authors}, <i>{title}</i>, {journal}, <b>{volume}{issue}</b>, p. {pages}, ({year}), {doi}, {cites}.</li>'

    issue = ''
    if result['coredata'].get('prism:issue'):
        issue = '({})'.format(result['coredata'].get('prism:issue'))
    return s.format(authors=get_author_link(EID),
                    title=get_abstract_link(EID),
                    journal=get_journal_link(EID),
                    volume=result['coredata'].get('prism:volume'),
                    issue=issue,
                    pages=result['coredata'].get('prism:pageRange'),
                    year=result['coredata'].get('prism:coverDate'),
                    doi=get_doi_link(EID),
                    cites=get_cite_img_link(EID))
from scopus import *
print get_html('2-s2.0-84901638552')
  • Xu Z.,Kitchin J.R., Relating the electronic structure and reactivity of the 3d transition metal monoxide surfaces, Catalysis Communications, 52, p. 60-64, (2014-07-05), doi:10.1016/j.catcom.2013.10.028, .
  • Well, that is the end for now. We have a reusable function that generates a nice HTML formatted citation that links out to many different resources. Why aren't all citations on the web this helpful?

    Copyright (C) 2015 by John Kitchin. See the License for information about copying.

    org-mode source

    Org-mode version = 8.2.10

    Discuss on Twitter
    « Previous Page -- Next Page »