Organize your scientific publications with BibTeX in Pelican. The package is based on Vlad's pelican-bibtex. The current version is backward compatible and can replace the pelican-bibtex
install of your current project.
pelican_bib
requires pybtex
.
$ pip install pybtex
You can either install Pelican Bib using pip (currently on version 0.2.7 ) or as a submodule:
$ pip install pelican-bib
Add the plugin to the PLUGINS
variable (in your Pelican config, e.g. pelicanconf.py
):
PLUGINS = ['pelican_bib', ...]
In your Pelican site:
$ mkdir plugins
$ git submodule add https://github.com/scheunemann/pelican-bib plugins/pelican-bib
Register the plugin folder and add the plugin to the PLUGINS
variable (in your Pelican config, e.g. pelicanconf.py
):
PLUGIN_PATHS = ['plugins/pelican-bib', ...]
PLUGINS = ['pelican_bib', ...]
This plugin reads a user-specified BibTeX file and populates the context with a list of publications, ready to be used in your Jinja2 template.
Configuration is simply: You can embed a list of publications via directive or a page template.
Use the bibliography
directive in your reST files and pass the path (or multiple paths)
to the bibliography file (relative to current document or absolute to Pelican content path).
.. bibliography:: pubs.bib
.. bibliography:: /pages/publications/pubs.bib
.. bibliography:: pubs1.bib pubs2.bib pubs3.bib
or provide BibTeX entries as content.
.. bibliography::
@inproceedings{doe_conf_2020,
author={Doe, Jane and Ordinary, Joe},
title={The Title of the Work},
booktitle={Proceedings of the Conference (CONF)},
year={2020}, pages={to appear}
}
Both input methods (path[s] and content) can be combined - entries will then be merged.
You will be able to use the variable publications
in your template.
By default, a template with the name "bibliography" is rendered.
Place the following template file as bibliography.html
in your Pelican template folder
(e.g. content/templates
). For extended templates see example templates.
<ul>
{% for publication in publications %}
<li id="{{ publication.key }}">{{ publication.text }}</li>
{% endfor %}
</ul>
Alternatively, you can pass a template name via :template:
parameter to use a specific template file (e.g. "publications-by-year.html"):
.. bibliography:: pubs.bib
:template: publications-by-year
If you set the parameter PUBLICATIONS_SRC
in your Pelican configuration file (e.g. pelicanconf.py
)
PUBLICATIONS_SRC = 'content/pubs.bib'
PUBLICATIONS_SRC = ['content/pubs1.bib', 'content/pubs2.bib', 'content/pubs3.bib']
you will be able to find the publications
variable in all your Jinja2 templates.
To generate a page displaying the publications with one of the methods below, you need to add a template file and a page.
1.) place the template file as publications.html
in your Pelican template folder
(e.g. content/templates
and add it as direct template to your webpage.
Add in your pelicanconf.py
:
THEME_TEMPLATES_OVERRIDES.append('templates')
2.) Create a page in your page folder, e.g., 'content/pages/publications.rst' with the following metadata in your content:
Publications
############
:template: publications
The publications
variable in your Jinja2 templates is a list of dictionaries with the following keys:
-
key
is the BibTeX key (identifier) of the entry. -
year
is the year when the entry was published. Useful for grouping by year in templates using Jinja'sgroupby
-
text
is the HTML formatted entry, generated bypybtex
. -
bibtex
is a string containing BibTeX code for the entry, useful to make it available to people who want to cite your work. -
pdf
,slides
,poster
: in your BibTeX file, you can add these special fields, for example:@article{ foo13 ... pdf = {/papers/foo13.pdf}, slides = {/slides/foo13.html} }
This plugin will take all defined fields and make them available in the template.
If a field mentioned above is not defined, the tuple field will be None
.
Other field types can only be accessed if they are also defined in the corresponding BibTeX entry.
With the help of the options
parameter of the bibliography
directive, you can pass additional values to the template.
For example
.. bibliography:: pubs.bib
:options: { 'groupby_attribute': 'year' }
would make the variable groupby_attribute
available in the template (see example templates).
If you set the configuration variable PUBLICATIONS_DECORATE_HTML
to true
, the parts of a HTML formatted entry generated by pybtex
(e.g. title, author list, volume & series) will be surrounded by span
tags with a corresponding class
attribute.
PUBLICATIONS_DECORATE_HTML = True
Instead of rendering the following HTML for a bibliography entry (default)
Jane Doe, and Joe Ordinary.
<span class="bibtex-protected">The Title of the Work</span>.
In <em>Proceedings of the Conference (CONF)</em>, to appear. 2020.
the rendered HTML would look like this:
<span class="bib-inproceedings">
<span class="bib-names">Jane Doe, and Joe Ordinary.</span>
<span class="bib-title"><span class="bibtex-protected">The Title of the Work</span>.</span>
In <span class="bib-btitle"><em>Proceedings of the Conference (CONF)</em></span>, to appear.
<span class="bib-address_organization_publisher_date">2020.</span>
</span>
Available CSS classes are (according to the format_*
and get_*_template
function names of
pybtex.style.formatting.unsrt):
bib-names, bib-article, bib-author_or_editor, bib-editor, bib-volume_and_series, bib-chapter_and_pages, bib-edition, bib-title, bib-btitle, bib-address_organization_publisher_date, bib-book, bib-booklet, bib-inbook, bib-incollection, bib-inproceedings, bib-manual, bib-mastersthesis, bib-misc, bib-phdthesis, bib-proceedings, bib-techreport, bib-unpublished, bib-web_refs, bib-url, bib-pubmed, bib-doi, bib-eprint.
Each bibliography is wrapped in a div
-container with the default classes "bibliography" and the bibliography file names. Use the class
option of the bibliography
directive to change the class attribute name:
.. bibliography:: pubs.bib
:class: my-custom-bib
You can modify arguments passed to the pybtex style that is used for rendering HTML.
Set the variable PUBLICATIONS_STYLE_ARGS
in your pelicanconf.py
to set default values
for the named arguments passed to the used
pybtex style
(available values).
PUBLICATIONS_STYLE_ARGS = {
'sorting_style': 'author_year_title',
'abbreviate_names': True,
'name_style': 'lastfirst' }
You can override the pybtex style arguments in a bibliography
directive as follows:
.. bibliography:: pubs.bib
:pybtex_style_args: { 'sorting_style': 'author_year_title', 'abbreviate_names': True, 'name_style': 'lastfirst' }
or just use the predifined options:
sorting_style
. values:author_year_title
(default) ornone
(sorting exactly as in the bib file)abbreviate_names
. values:True
orFalse
(default)name_style
. values:plain
(default) orlastfirst
.. bibliography:: pubs.bib
:sorting_style: author_year_title
:abbreviate_names: True
:name_style: lastfirst
You can add an extra field to each BibTeX entry. This value of that field is a comma separated list.
These values will become the keys of a list publications_lists
containing the associated BibTeX entries in your template.
For example, if you want to associate an entry with two different tags (foo-tag
, bar-tag
),
you add the following field to the bib entry:
@article{
...
tags = {foo-tag, bar-tag}
}
In your pelicanconf.py
you'll need to set:
PUBLICATIONS_SPLIT_BY = 'tags'
In your template you can then access these lists with the variables publications_lists['foo-tag']
and publications_lists['bar-tag']
.
You can use the filter_tag
option of the bibliography
directive to only render publications containing the given tag:
.. bibliography:: pubs.bib
:filter_tag: foo-tag
If you want to assign all untagged entries (i.e. entries without
the field defined in PUBLICATIONS_SPLIT_BY
) to a tag named others
, set:
PUBLICATIONS_UNTAGGED_TITLE = 'others'
By default, the pybtex.style.formatting.plain
style is applied to the list
of publications, but it is also possible to supply custom pybtex styles. Here
is a simple example that will highlight the name of the website's author. Add
the following to your Pelican config:
PUBLICATIONS_CUSTOM_STYLE = True
PUBLICATIONS_STYLE_ARGS = {'site_author': AUTHOR}
Then create the file plugins/pybtex_plugins.py
with the following content:
from pybtex.database import Person
from pybtex.style.formatting import unsrt
from pybtex.style.template import tag
class PelicanStyle(unsrt.Style):
def __init__(self, site_author='', **kwargs):
super().__init__(**kwargs)
self.site_author = Person(site_author)
# Allows to apply special formatting to a specific author.
def format(person, abbr=False):
if person == self.site_author:
return tag('strong') [ self.name_style.format(person, abbr) ]
else:
return self.name_style.format(person, abbr)
self.format_name = format
PelicanStyle
must be a subclass of pybtex.style.formatting.BaseStyle
. An
alternative path to the pybtex_plugins.py
file can be provided via
PUBLICATIONS_PLUGIN_PATH
in the Pelican config.
First, add the following content to your template file.
Variant A - Open BibTeX entry via JavaScript in new windows:
{% macro render_publication(publication) %}
<li id="{{ publication.key }}">
{{ publication.text }}
[ <a href="javascript:window.open().document.write('<pre>{{ publication.bibtex|replace('\n', '\\n')|escape|forceescape }}</pre>');">Bibtex</a> ]
{% for label, target in [
('PDF', publication.pdf),
('Slides', publication.slides),
('Poster', publication.poster)] %}
{{ "[ <a href=\"%s\">%s</a> ]" % (target, label) if target }}
{% endfor %}
</li>
{% endmacro %}
(Note: that we are escaping the BibTeX string twice in order to properly display it.
This can be achieved using forceescape
)
Variant B - Show/hide BibTeX entry in-place via CSS:
{% macro render_publication(publication) %}
<li id="{{ publication.key }}">
{{ publication.text }}
[
<a href="#{{ publication.key }}-bibtex">BibTeX</a>
{% for label, target in [
('PDF', publication.pdf),
('slides', publication.slides),
('poster', publication.poster)] %}
{% if target %}
| <a href="{{ target }}">{{ label }}</a>
{% endif %}
{% endfor %}
]
<div class="bib-fold" id="{{ publication.key }}-bibtex">
<a class="bib-close" href="#{{ publication.key }}">×</a>
<pre>{{
publication.bibtex
| trim
| escape
| replace('\n', '<br>')
}}</pre>
</div>
</li>
{% endmacro %}
<style>
.bib-fold { display: none; }
.bib-fold:target { display: block; }
.bib-close { display: block; position: absolute; right: .2em; padding: .2em; margin-top: -.2em; margin-right: .5em; color: inherit; text-decoration: none; font-size: 3em; font-weight: bold; background-color: #fff; }
</style>
Then, add the following content (to the same file).
Example content of the bibliography.html
template (Option 1: "bibliography" directive):
<ul>
{% for publication in publications %}
{{ render_publication(publication) }}
{% endfor %}
</ul>
Example content of the publications.html
template (Option 2: Page template):
{% extends "base.html" %}
{% block title %}Publications{% endblock %}
{% block content %}
<section id="content" class="body">
<h1 class="entry-title">Publications</h1>
<ul>
{{ render_publication(publication) }}
</ul>
</section>
{% endblock %}
The entries can be sorted by one of the attributes, for example, if you want to sort the entries by date, your unordered list would look like the following:
<ul>
{% for publication in publications|sort(True, attribute='year') %}
{{ render_publication(publication) }}
{% endfor %}
</ul>
The sort builtin filter was added in version 2.6 of jinja2.
To group entries by year,
<ul>
{% for grouper, publist in publications|groupby('year')|reverse %}
<li> {{grouper}}
<ul>
{% for publication in publist %}
{{ render_publication(publication) }}
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
As described above, lists of publications are stored in publications_lists
.
You can replace publications
from the previous example with publications_lists['foo-tag']
to only show the publications with tagged with foo-tag
.
You can also iterate over the map and present all bib entries of each list. The section of the previous example changes to:
{% for tag in publications_lists %}
{% if publications_lists|length > 1 %}
<h2>{{tag}}</h2>
{% endif %}
<ul>
{% for publication in publications_lists[tag] %}
{{ render_publication(publication) }}
{% endfor %}
</ul>
{% endfor %}
Group by year:
.. bibliography:: pubs.bib
:options: { 'groupby_attribute': 'year' }
No grouping:
.. bibliography:: pubs.bib
If the parameter groupby_attribute
is passed to the template, the list of publications will be grouped by this attribute.
Otherwise, the plain list will shown:
{% if groupby_attribute %}
{% for year_number, year_publications in publications|groupby(groupby_attribute)|reverse %}
<section id="{{ year_number }}">
<h2>
<a href="#{{ year_number }}">{{ year_number }}</a>
</h2>
<ul>
{% for publication in year_publications %}
{{ render_publication(publication) }}
{% endfor %}
</ul>
</section>
{% endfor %}
{% else %}
<ul>
{% for publication in publications %}
{{ render_publication(publication) }}
{% endfor %}
</ul>
{% endif %}