5

I would like to define a \DeclareSortingScheme for biblatex such that \printbibliography sorts the citations according to the citecounter: Reference which is cited most in the document on top.

Is there a way to do this. Everything I tried does not work.

  • What about something like \DeclareSortingScheme{my_counter}{\sort{\value{citecounter}}}? – luchonacho Apr 5 '17 at 18:57
4

There is a way to get round the problem moewe's answer explains, but it requires an extra file and multiple runs.

Basically the plan is: write a separate file (which I've given the extension .smp) containing a sourcemapping, written during the printing of the bibliography, with citations counts which are then available. Then on a later run read it in, and use that to allow biber to include that information into the .bib data and then sort using it.

It requires multiple runs to stabilise: LaTeX, biber, LaTeX, LaTeX, LaTeX, biber, LaTeX. So many because it is necessary for the data to "propagate" forward through successive processing: into the .smp file, back into LaTeX, thence to the .bcf file which biber reads, then to biber, and finally back into LaTeX.

Obviously for proper use in a style this would need various bits of clean-up. Can TeXperts please forgive my entirely trial-and-error approach to getting things to expand properly!

\documentclass{article}
\usepackage[citecounter]{biblatex}

\makeatletter
% This command (1) sets up an .smp file to receive the relevant
% sourcemaps that will be later written out, and (2) reads that
% file in if it is available so that the sourcemap directives
% are implemented. It needs to be executed **inside the preamble**
% because that is where sourcemaps must be.
\newcommand{\preparecitationsfile}{%
  \IfFileExists{\jobname.smp}
    {\@@input \jobname.smp}
    {\typeout{No sourcemap file found. Citations will not be sorted properly.}}
  \newwrite\autosourcemaps
  \immediate\openout\autosourcemaps=\jobname.smp
  \immediate\write\autosourcemaps{\writesmppreamble}%
}
% These commands are simply a convenient way to write the necessary preamble
% and ending part of the sortmaps file
\edef\writesmppreamble{%
  \string\DeclareSourcemap\string{%
    \string\maps[datatype=bibtex]\string{%}}
  }
\edef\writesmppostamble{%{{
  \string}\string}}   

% This is the command that gets executed at each bibitem, to write
% an appropriate entry into the sourcemap file. I daresay a
% person who understood expansion rather than simply banging it
% with a number of hammers until it seems to work could make
% this a lot more elegant
\newcommand{\writeautomap}[1]{%
  \def\@tempkey{#1}
  \edef\@tempcounter{\the\c@citecounter}
  \edef\@tempa{%
    \noexpand\map[overwrite=true]\string{
      \noexpand\step [fieldsource=entrykey, match=\string{\@tempkey\string}, final]%
      \noexpand\step [fieldset=usera,fieldvalue=\string{\@tempcounter\string}]\string}%
    }%
  \immediate\write\autosourcemaps{%
    \@tempa}}

% Because (I think) these commands are only defined by biblatex during the preamble
% but we use them in writeautomap, it is necessary to do this in order to prevent
% spurious errors.
\let\map\relax
\let\step\relax
\let\maps\relax

% We can automate the closing of the file, first writing the postamble
\AtEndDocument{%
  \immediate\write\autosourcemaps{\writesmppostamble}
  \immediate\closeout\autosourcemaps}

% This ensures that an appropriate mapping is written to the source file at each bibitem
\AtEveryBibitem{%
  \writeautomap{\thefield{entrykey}}
}

% And finally we need a sorting scheme which puts the number of citations first. We are
% storing them in the usera field
\DeclareSortingScheme{custom}{%
  \sort[
  direction=descending]{
    \field{usera}}
   \sort{
    \field{sortname}    
    \field{author}
    \field{editor}
    \field{translator}}
  \sort{
    \field{sorttitle}
    \field{title}
  }
  \sort{
    \field{year}}
  }
\makeatother

\addbibresource{biblatex-examples.bib}
\preparecitationsfile
\begin{document}

\cite{worman}

\cite{worman}

\cite{worman}

\cite{worman}

\cite{worman}

\cite{cotton}

\cite{cotton}

\cite{cotton}

\cite{cotton}

\cite{aristotle:anima}

\newrefcontext[sorting=custom]
\printbibliography


\end{document}

It may help to visualise this by seeing the .smp file containing the sourcemapping command that has been written out during bibliography generation:

\DeclareSourcemap{\maps[datatype=bibtex]{
\map [overwrite=true]{ \step [fieldsource=entrykey, match={aristotle:anima}, final]\step [fieldset=usera,fieldvalue={1}]}
\map [overwrite=true]{ \step [fieldsource=entrykey, match={cotton}, final]\step [fieldset=usera,fieldvalue={4}]}
\map [overwrite=true]{ \step [fieldsource=entrykey, match={worman}, final]\step [fieldset=usera,fieldvalue={5}]}
}}
  • Oh, fancy! I didn't think someone would actually go through the ordeals of creating auxiliary files here. But that seems to be a good solution. Instead of usera you could use the presort field, which is included in all standard sortings, so you don't even need to define your own sorting scheme! I'm not sure, but maybe it would be safer to match against match=\regexp{\Aworman\Z} to avoid worman matching awormane. – moewe Apr 10 '17 at 6:08
3

Currently there is no easy way to sort by citecount, even though almost all pieces of the puzzle are there.

biblatex provides the option citecount that counts the number of occurrences of each citation and stores it in the counter citecounter.

We cannot, however, configure a sort scheme to sort by value of a (LaTeX) counter. This is simply because Biber (or BibTeX) does the sorting, and the backend cannot access TeX counters. (Note that this is not an expansion issue here, in your case the counter takes different values for different entries, so it would have to be evaluated by the backend.)

We would have to pass the available information between LaTeX and Biber by means of an auxiliary file or such.

The backend itself could also count the number of occurrences, but there is currently no interface to access that information in a sort scheme.

If you really, really need this, you can submit a feature request to the biblatex bug tracker (https://github.com/plk/biblatex/issues).

  • Thanks for the hint. But I got the error ! Missing number, treated as zero. <to be read again> \edef l.21 ...me{my_counter}{\sort{\value{citecounter}}} when compiling with \usepackage[citecounter=true,backend=biber,sorting=my_counter]{biblatex} \DeclareSortingScheme{my_counter}{\sort{\value{citecounter}}} – Thorsten O. Apr 5 '17 at 21:01
  • @ThorstenO. I suspect this comment was moved here from your earlier answer? As I explained, the code can't work, and at the moment there is no way to make it work. – moewe Apr 7 '17 at 7:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.