Follow by Email

Friday, March 23, 2018

Why TeX Live?

I am sometimes asked why I recommend that people install TeX Live, even on the Windows platform, to people installing a TeX distribution.

Of course, on Windows people could choose the MiKTeX  distribution.  There is no doubt about it: lots of people around the world use this system and it does great for them. 

The two have essentially the same software (MiKTeX is somewhat more relaxed about license requirements and so carries a few packages that TeX Live does not).  So what is it about TeX Live that tips the scale for me?   I see two differences.

1) The first is that MiKTeX can do the on-the-fly installation of packages. That is, if you get a LaTeX source file from someone that uses a package that your MiKTeX does not already have it installed then it goes out on the interwebs and gets it (from the MiKTeX repository, not just from any old place).  That's neat.

(MiKTeX can do this but TeX Live cannot because MiKTeX is a one-platform system.  So it knows what supporting software, and what version of that software, is installed.)

But, although on-the-fly is neat, I personally don't find that I need it. My practice is to install the full version of TeX Live and I almost never need anything else.

Sometimes people respond that TeX Live full is very big.  It is, in 1995 terms. But today is today.  My kids download whole movies and think nothing of it. I use TeX during perhaps 20% of my waking day, so the size seems to me to be not much. (And, frankly, my TeX Live installation is a couple of years old. My work buys me a new computer every three years and I install then and forget about it.)

So doing on-the-fly, while cool, is just not relevant to the great majority of my work. I suspect that it is not relevant to the overwhelming majority of the people who ask me which distribution they should install.  If you need it, well then of course I'm sure it is important to you.

2) The second difference is that TeX Live is an example of a good project in Free stuff.  There is an understanding that handing people bits, even bits that are Free, does not suffice.

MiKTeX is really a one man show. A very admirable project, for sure, and I don't know how he does it, but a person worries about errant busses. 

Said in a less flippant way, the TeX Live project is connected to others.  There are core people, but there is an understanding that connections bring real benefits.  For example, it is coupled to the TeX User Group and other such organizations. These are folks who provide a forum such as the annual TUG meeting and next year's Pratical TeX for interested parties to get together, provide a journal, and provide financial development support to the extent that they can. In my experience all this stuff matters, a great deal, in ensuring that TeX and friends continue to be there, and to be relevant, for years to come.

It is reason number 2 that persuades me.

Sunday, October 16, 2016

Curated list of LaTeX packages

I have been asked what are the core packages that a LaTeX user should know.  Not often, but it has happened.  

Here is my list. These are personal choices so folks may disagree, but what can you do with opinions besides spread them around? In any event, I think these are popular and reliable packages.

  • To change margins, page size, orientation, etc., use geometry
  • To make headers a person reaches for fancyhdr
  • Tables of contents, lists of figures, etc. tocloft
  • To make titles, think of titlesec
  • Make an index with makeindex
  • To get arbitrary fonts use XeLaTeX and fontspec 
  • Personally, more than BibTeX I like BibLaTeX but I know next to nothing about it
  • Math amsmath (I load this by instead loading mathtools which makes some improvements), and amsfonts, as well as theorem environments with amsthm
  • To make lists use enumitem
  • Make captions with caption and control float placement with float (I may be wrong about this last; I don't typically use floats.)
  • Make cross-references with the one-r-ed cleveref
  • Links with hyperref (but load it last of all the package you load)
  • URL's and filenames and file paths with url.sty (but hyperref makes some improvements, so if you are using hyperref just go with that)
  • For colors use xcolor
  • Load graphics with graphicx
  • Code listings and verbatim text with listings. (Make single quotes come out right in verbatim with upquote)
  • Many people draw in-place graphics with TikZ (Personally I use Asymptote)
  • Make presentations with beamer
  • Make PDF file do copy and paste, and search with cmap
  • If you are making a PDF, you can toss in microtype for improvements that I am too thick to see, but I put it in because what the heck?
  • I like footnotes at the page bottom so I use footmisc (but I hack to change the spacing, which is not doable otherwise)
  • Make an index with makeindex
  • Write answers to exercises to external file with answers

Friday, August 17, 2012

Administering TeX Live on Ubuntu

The TeX that comes in the Ubuntu package manager is a couple of years old (I have Ubuntu 12.04 LTS here in 2012 and the package manager has TeX Live 2009).  For many people that won't matter but for my text Linear Algebra I needed some more recent packages, which needed a more recent LaTeX kernel ... . So on the urging of a number of smart folks I installed TeX Live 2012 from  Here is my experience.

I kept the package manager's packages installed.  One reason is that I know from past experience that if I drop those packages then when I want to install related materials from the package manager, such as AUCtex or Asymptote, then the package manager will complain about unmet dependencies, and I'll try a --force install  and later there will be an update ... and anyway at some point so that chaos sets in.  (Lars Madsen posted a way to avoid this with his knowledge of the package system but of the choices available I went another way, partly because I didn't entirely understand his process and so would have trouble adjusting it if I needed to.)

A first go

I downloaded TeX Live.  It put things in the default of /usr/local/texlive.   My local files go in /usr/local/texlive/texmf-local.  I changed the PATH variable in /etc/profile (maybe I should have used /etc/environment instead, or in addition?) and logged out and back in again.

To check  my setup I copied some personal styles and classes.

    ftpmaint@millstone:~$ ls /usr/local/texlive/texmf-local/tex/latex/local
    charis.sty  gentium.sty  memo.cls  present.sty
    conc.sty    jh.sty       mins.cls  pyweb.cls

I tried to remake the file database

    ftpmaint at millstone:~$ sudo texhash
    [sudo] password for ftpmaint: 
    texhash: Updating /usr/local/share/texmf/ls-R... 
    texhash: Updating /var/lib/texmf/ls-R-TEXMFMAIN... 
    texhash: Updating /var/lib/texmf/ls-R-TEXLIVE... 
    texhash: Updating /var/lib/texmf/ls-R... 
    texhash: Done. 
but after then issuing kpsewhich conc.sty failed.  Why?

Turns out (I am skipping over a great deal of head-scratching and googling here), on Ubuntu the sudo command was using the Ubuntu tex's texhash
    ftpmaint at millstone:~$ which texhash
    ftpmaint at millstone:~$ sudo which texhash

rather than's because it has its own PATH.

    ftpmaint at millstone:~$ echo $PATH
    ftpmaint at millstone:~$ echo 'echo $PATH' | sudo sh


I got around it by calling the program with its full path.

    ftpmaint at millstone:~$ sudo /usr/local/texlive/2012/bin/i386-linux/texhash
    texhash: Updating /usr/local/texlive/2012/texmf/ls-R... 
    texhash: Updating /usr/local/texlive/2012/texmf-config/ls-R... 
    texhash: Updating /usr/local/texlive/2012/texmf-dist/ls-R... 
    texhash: Updating /usr/local/texlive/2012/../texmf-local/ls-R... 
    texhash: Updating /usr/local/texlive/2012/texmf-var/ls-R... 
    texhash: Done.

The answer

The above was an answer, but it obviously wasn't the answer.  Lars commented, "On my systems I have a specific LaTeX user who owns the LaTeX installation, thus I do not have to run anything as root."  This seemed right.

I created a new user texlive to own the material in /usr/local/texlive.

    ftpmaint at millstone:~$ cd /usr/local    
    ftpmaint at millstone:~$ sudo chown -R ftpmaint:ftpmaint texlive

A comment about this user: I don't want texlive to appear on the choices on the login screen so I gave this account a user id below 500: sudo usermod -u 499 texlive (I got the parameter 500 from /etc/lightdm/users.conf).

Several people cautioned me to watch the umask of this user but because the system sets the default at 022 I was OK. 

 Lars mentioned that he may have multiple TeX Live trees under /usr/local/texlive, say /usr/local/texlive/2011 and /usr/local/texlive2012.  He has a soft link that points to the current one.

    texlive at millstone:~$ ln -s 2012 current

I often have trouble remembering what command options to run, etc., so I like to put that stuff in .sh files.  Here the soft link does its magic; no need to change the script when I add another tree.

     ftpmaint@millstone:/usr/local/texlive$ ls -l
    total 12
    drwxr-xr-x 10 texlive texlive 4096 Aug 17 07:05 2012
    lrwxrwxrwx  1 root    root       4 Aug 16 17:47 current -> 2012
    drwxr-xr-x 10 texlive texlive 4096 Aug 17 07:05 texmf-local
    -rwxr--r--  1 texlive texlive  181 Aug 16 17:48
    ftpmaint@millstone:/usr/local/texlive$ cat
    # Update the current TeX Live installation
    # 2012-Aug-16 Jim Hefferon
    tlmgr update --all --self

The only remaining hiccup is to remember the password for texlive.  This is the kind of account that a person only uses every couple of months where I could easily forget.  But I use a password keeper program KeePassX to store my passwords so I put this user's information in there.


Wednesday, March 21, 2012

Looking for a new Linux dist

Too bad.  Ubuntu was good for a couple of years.  Now, I just spent an hour online trying to spelunk how to disable the bootup sound.  No one on the interwebs knows.  It clearly should be in a menu.  It was in a menu.  But now it is not.

I often get up at 4:30 and turn on the ham set, and the computer.  My wife doesn't have to hear the bootup sound at that hour.  But there appears to be no reasonable way to turn it off.

This is not the first time I have spent a frustrating hour on such a task.  I must have spent twenty of them in the last couple of months. Ubuntu was good, but now it is not.

Ah well.  Gotta get a new distro.

Thursday, September 8, 2011

Installing MicroPress's Computer Concrete fonts onto TeX Live under Linux

 I own the Computer Concrete fonts from MicroPress. These are outline fonts so they look nice at any magnification. Because I use a concrete font in my Beamer presentations, the characters get blown up to a good size and I'd like them to show well, so I wanted to install these.

I have Ubuntu 11.04 with a current TeX Live that I installed off the web.  I looked in my local TeX directory /usr/local/share/texmf/fonts (I used this location instead of /usr/share/texmf because it will survive if I install a later version of TeX Live.)

I loaded the vendor's CD into the machine, where it showed up as /media/CFonts/CFONTS.dir.  I see directories for afm, inf, pfb, pfm, setup, and tfm.  There are also some .zip files containing LaTeX styles that I don't think I need as they come with TeX Live.

1) As sudo, I copied the files from /media/CFonts/CFONTS.dir/afm and /media/CFonts/CFONTS.dir/inf into /usr/local/share/texmf/fonts/afm/public/cfonts after making that directory. I was told to put the inf stuff in there also by the TeX Directory Standard document. I made the file permissions rw for the owner root, r for the group, and r for others.

2) I copied the files from the CD's pfb and pfm directories into /usr/local/share/texmf/fonts/type1/public/cfonts after making that directory. As above, I combined the file types in the one directory on the advice of the TDS document, and changed the permissions as above.

3) I copied the files from the CD's tfm directory into /usr/local/share/texmf/fonts/tfm/public/cfonts after making the directory, and I changed the file permissions as above.

4) I copied the CD's /media/CFonts/CFONTS.dir/setup/dvips/CONCRETE.MAP into /usr/local/share/texmf/fonts/map/dvips/cfonts/ after making that directory.  I changed its file permissions.

5) On the advice of TUG's font installation page, from the directory /usr/local/share/texmf/fonts/map/dvips/cfonts I ran "sudo texhash" and also "sudo updmap-sys --enable"

It worked. The next time I compiled my .tex to a .pdf I could see in the File > Properties > Fonts tab that the cc fonts were included as Type 1.

By the way, I use this LaTeX style to get the concrete fonts.

% From Walter Schmidt post on ctt Jan 10 2005
\linespread{1.04} % approximately
% \usepackage{mathdots}

Put it in /usr/local/share/texmf/tex/latex/local/conc.sty and run "sudo texhash" to have it be available as a normal LaTeX style.

Thursday, September 24, 2009

Suckerfish menus in Django

I have some data that I keep in a tree, and I wanted to see if people could browse it in a tree-like interface. All in Django, of course.

(Let me apologize for any errors in transcription below; this is my first time using blogger.)

I'm very wary of cross-browser incompatibilities. So any solution with a lot of Javascript, etc., leaves me worried that a year from now Safari will become incompatible and I'll be left racing to catch up. That'd be bad.

But suckerfish menus are based on CSS which is at least a fairly wide standard. I used a number of web sites as guides, but one that was especially handy was A List Apart.

Let me first cover what the data is. CTAN has perhaps four thousand packages. People should be able to browse them by some reasonable characterization: for instance, maybe "Document Styles > Books > Publisher Styles" would pop up a bunch of packages in that category.

I'd like to allow a number of different characterizations. For instance, Juergen Fenn has a good one that he uses in the TeX Catalogue and I have another. (Actually, my idea is to give each package a primary characterization and then a number of secondary characterizations, where the tree of primary characterizations is the same as the tree of secondary characterizations. For instance, a linguistics package may also contain a font of special symbols so the primary would be by subject area, but the secondary would be in fonts.)

I choose to store the characterization data using mptt (because at the time I was looking it seemed to be all that fit, but it has worked for me so I stuck with it). I call the different characterizations "dimensions" and so my has this.

class Dimen(models.Model):
help_text="What dimension is the package being characterized by?")
help_text="Description of this dimension.")

def __unicode__(self):
return self.dimen

class Meta:

and also this.

class Characterizations(models.Model):
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
help_text="Dimension of characterization")
# unique=True,
help_text="Title of this node (short)")
full_title=models.TextField( # denormalize for speed
# unique=True,
help_text="Title of this node, from the root")
help_text="Description of this node (a paragraph)")
help_text="Where full_title is a > b > c this is a/b/c"

def __unicode__(self):
return repr(unicode(self.full_title))

class Meta:


(note that last line; it is not part of the class definition). Note the denormalization fields in the model class-- searching by url, for instance, is a help.

Finally, the packages are characterized in this way.

class Characterization(models.Model):
help_text="Identifier of node in tree")
help_text="Identifier of package")

def __unicode__(self):
return self.pkg_id.pkg_id

class Meta:

To populate the database, I can't put a .sql file in the sql/ directory of my project because mptt has fields that it uses for bookkeeping and I don't know what values it likes there. So I wrote a script to populate it. I have to import the relevant Django stuff

import django.core,
import az.settings
import django.db
from django.db import models
from django import forms

and some stuff from my project

import az, az.pkgs
from az.pkgs.models import LicenseTypes, Languages, Package, Maintainers, PackageHistory, PackageText, License, OnCtan, OffCtan, RelatedPackages, Keywords, Keyword, Authors, Author, Distributions, Distribution, TexLiveTypes, TexLivePackages, TexLiveCatalogue, Upload, Dimen, Characterizations, Characterization
from az.util import util

and then I make use of a couple of add-a-node routines. The idea is to run code that does this (I'm showing just a small part).

def buildPrimaryByFunctionTree():
"""Build the primary by-function trees
# ------------------ Top -------------------------
# ----------- Top > Document types -----------------
Document_types=addNode(pRoot,'Document types',
'Everything from books and articles to memos and letters. Also here are documents for specific publishers.')
# ----------- Top > Document types > Books -----------------
Publisher_styles=addNode(Books,'Publisher styles',
'Styles for books from specific publishers.')
'Other packages.')

The add-a-node routines were weird:

BRANCH_SEPARATOR=' > ' # separate parts of a branch; should not occur in titles
def getBranchTitle(n):
"""From the node, get the branch title, like 'Top > Fonts' (assumes
n.full_title is not available).
# Like: return n.full_title but get it for setting in the dB
ancestorTitles=[a.title for a in n.get_ancestors(ascending=False)]
return branchTitle


def getRootNode(dimen_str):
"""Get the root node of the tree with the given dimen
if not(nodeQ):
return None
return nodeQ[0].get_root()


def getNodeFromBranchTitle(branchTitle,dimen_str):
"""From the branch title, like 'Top > Fonts', get the node.
""" n=Characterizations.objects.filter(dimen__dimen__exact=dimen_str).get(full_title__exact=branchTitle)
return n

were reasonable, but this one

def addNode(parentNode,title,description):
# I don't get this. I appear to have to fetch the parent node so that
# it is the most recent thing on mptt's mind. See mptt's
# in the section marked "Creation"
return childNode

was so strange that I thought I was doing it wrong. Anyway, it correctly populates the tree.

So now I have a tree. I need to offer the visitor the chance to pick a dimension, and then display the resulting tree using suckerfish menus.

In I put

urlpatterns += patterns('az.views',

and then I needed a views/ . I also needed to make a widget, a field, and a form.

The widget required some fiddling. I feed it choices that are pairs
(url_path, [list of tree node labels]) . It uses the length of the list in the second entry to decide if it needs to go to a child node, or if this is a sibling node, etc. Then it renders a simple html structure like this (based on the discussion from A List Apart; see above).

<ul id="sfish">
<li><a href="/characterization/primary/">pick one</a>
<ul><li><a href="/characterization/primary/"></a>
</li><li><a href="/characterization/primary/document-types/">Document types</a>
<ul><li><a href="/characterization/primary/document-types/books/">Books</a>
<ul><li><a href="/characterization/primary/document-types/books/publisher-styles/">Publisher styles</a></li>
<li><a href="/characterization/primary/document-types/books/others/">Others</a>
</li><li><a href="/characterization/primary/document-types/articles/">Articles</a>

Here is the widget code.

class PickCharacterizationWidget(forms.RadioSelect):
def render(self,name,value,attrs=None,choices=()):
"""Display the tree in a form suitable for suckerfish menus
choices list of pairs (string, list of strings) where the first
is a link to the page you go to if you choose this, and
list of strings is a list like ['a','b','c'] to represent
'a > b > c'
INDENT=" "*4
r=["<ul id="'sfish'">"]
for lnk,ft_list in self.choices:
# print "ft is ",ft
# r.append("\n++"+ft)
if t>s:
# r.append("")
elif t==s:
if prior_ft_list[-1]: # not very first entry
elif t<s:
for i in range(s-t):
r.append("</li><a href="">>" % (lnk,)+ft_list[-1]+"</a>")
for i in range(len(prior_ft_list)-len(ft_list)):
if i>1:
return "".join(r)

Note that this all needs CSS to work. Here is the relevant section of mine (it ain't beautiful).

/* See */
#sfish, #sfish ul { /* all lists */
padding: 0;
margin: 0;
list-style: none;
float : left;
width : 11em;

#sfish li { /* all list items */
position : relative;
float : left;
line-height : 1.25em;
margin-bottom : -1px;
width: 11em;

#sfish li ul { /* second-level lists */
position : absolute;
left: -999em;
margin-left : 21.05em;
margin-top : -1.35em;

#sfish li ul ul { /* third-and-above-level lists */
left: -999em;

#sfish li a {
width: 20em;
w\idth : 20em;
display : block;
color : black;
font-weight : normal;
text-decoration : none;
background-color : white;
border : 1px solid black;
padding : 0 0.5em;

#sfish li a:hover {
color : black;
background-color : #bababa;

#sfish li:hover ul ul,
#sfish li:hover ul ul ul,
#sfish li.sfhover ul ul,
#sfish li.sfhover ul ul ul
#sfish li.sfhover ul ul ul ul
left: -999em;

#sfish li:hover ul,
#sfish li li:hover ul,
#sfish li li li:hover ul,
#sfish li li li li:hover ul,
#sfish li.sfhover ul,
#sfish li li.sfhover ul,
#sfish li li li.sfhover ul
#sfish li li li li.sfhover ul
{ /* lists nested under hovered list items */
left: auto;

#content {
margin-left : 12em;

There is also a little bit of Javascript.

sfHover = function() {
var sfEls = document.getElementById("nav").getElementsByTagName("LI");
for (var i=0; i<sfEls.length; i++) {
sfEls[i].onmouseover=function() {
this.className+=" sfhover";
sfEls[i].onmouseout=function() {
this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
if (window.attachEvent) window.attachEvent("onload", sfHover);

I don't understand JavaScript so I can't vouch for it, but it came from A List Apart so I threw it in.

Here is the field that makes the choices.

class PickCharacterizationField(forms.ChoiceField):
"""The user picks one characterization to look at.
def __init__(self, dimen=None, choices=(), required=True, widget=widgets.PickCharacterizationWidget, label=None, initial=None, help_text=None):
util.printFlush(" PickCharacterizationField() dimen="+repr(dimen))
if dimen:
if not(choices):
super(PickCharacterizationField, self).__init__(choices=choices, required=required, widget=widget, label=label, initial=initial, help_text=help_text)

def get_characterizations(self,dimen,separator=BRANCH_SEPARATOR):
"""Return a list from a traversal of the tree:
(node (subnode1, (..)), (subnode2, ())..)
dimen string The Dimen.dimen field pointed to by this characterization
separator string How fields are separated in the full_title's
node_list=[n.full_title.split(separator) for n in nodes] choices=[(util.path_components_to_url(u'/characterization/'+dimen+u'/',ft_list,u'/'),ft_list) for ft_list in node_list]
choices=[(x,['pick one']+y) for x,y in choices]
choices=[(u'/characterization/'+dimen+u'/',['pick one'])]+choices
return choices

Now came the main question: how to get the choices into the widget? I had to ask on the Django Users list and a nice person there helped me out (thanks to you, Daniel Roseman!). I made a form where the initialization function reaches out and touches the field.

class PickCharacterizationForm(forms.Form):
def __init__(self,*args,**kwargs):
if dimen:
pick_field.dimen = dimen

pick=PickCharacterizationField(required=True,help_text='Select a characterization',widget=widgets.PickCharacterizationWidget)

class Media:

And it works! I have two routines in
that either search for the list of dimensions.
def choose_dimen(req,tmplt=CHARACTERIZATION_TEMPLATE):
"""Allow a person to choose a dimension for the characterization
dimen string Default choice
dimen_triples=[(d.dimen,d.dimen.capitalize(),d.description) for d in dI]
return render_to_response(tmplt,ctext)

or else invoke the form.

def main(req,pth=None,tmplt=CHARACTERIZATION_TEMPLATE):
if not(dimen):
return HttpResponseRedirect('/characterization/choose_dimen/')
except Exception, err:
dimen=re.sub('[a-zA-Z0-9_\-]','',dimen) # safe for display on page
if not(dI):
return HttpResponseRedirect('/characterization/choose_dimen/')
# See which packages are characterized in this way
if cdr:
for cI in cQ:
# Cash out
ctext['full_title']=' > '.join(cdr)
# Finish
return render_to_response(tmplt,ctext)

It is all still rough, and I haven't said what some of the routines do (such as PageNameMap), but perhaps this might help someone who is looking for a place to start with suckerfish and Django.

In the end, though, my menus proved to be too long for the page. The slide off the bottom of the page and so are very hard to use. Oh well.


Wednesday, November 26, 2008

First blog post

This is a test of blogger.