Better typography for IPython notebooks

(Warning: ignorant rant coming up)

Like everyone else who’s ever used it, I love the IPython notebook. It’s not only an awesomely productive environment to work in, it’s also the most powerful weapon in the Python evangelist’s arsenal (suck it, Matlab).

I also think it’s not hard to imagine a world where scientific papers are all just literate programs. And the notebook is probably one of the best tools for literate programming around in any language. The intregration of markdown and LaTeX/MathJax into the notebook is just fantastic.

But it does have one weakness as a literate programming tool. The default typography is ugly as sin.

There are several issues, but two major ones are easily fixable.

Long lines

By far the biggest issue is that the text and input cells extend to 100% of the window width. Most people keep their browser windows open wider than is comfortable reading width, so you end up with long hard-to-read lines of text in the markdown cells.

And for the code, it would be nice to have the code cell discourage you from long lines. The variable width cells don’t. I’m an 80-character anal retentive, and even I have trouble in the notebook getting a sense of when a line is too long.

When you write a script in a text editor, there’s lots of previous code in the viewable window, so your eye gets a sense of the ‘right-margin’ of the code. (Not to mention many editors will indicate the 80- or whatever-character column, so you know exactly when to break). But in the notebook, your code is typically broken up into smaller blocks, and those blocks are interspersed with output and other cells. It’s hard to get a visual sense of the right margin.

Ugly fonts

Text and markdown cells are typically rendered in Helvetica or Arial. Helvetica is a fine font, obviously, but it’s not really suitable for paragraphs of text (how many books, magazines, newspapers, or academic papers do you see with body text typeset in Helvetica?). And combined with the small size and long lines makes it hard to read and just plain ugly. I don’t think I have to say anything about Arial.

The way I use the notebook–with markdown cells used for long stretches of explanatory text and result interpretation–it’s better to have the text cells render in a serif font. This way it stands out from the code and output cells more. Serif fonts also have more distinctive italics, and integrate better with LaTeX/MathJax math.

Code cells and interpreter output cells render in whatever your default monospace font is. That’s typically Courier or Courier New. This is fine, but really, this is the 21st century–we can do a lot better.

Update: one more thing

I realize I’ve made one other change that I think is important. The default ordered list in the notebook uses roman numerals (I, II, III, …). I almost always want arabic numerals (1, 2, 3, …) instead. We can change this in the file renderedhtml.css with


.rendered_html ol {list-style:decimal; margin: 1em 2em;}

(Also check the comments for other, and typically better ways to make changes.) You can also modify sub-levels ol ol, ol ol ol, etc. Ideally I’d like to have nested numbers 1.1, 1.1.1, but this isn’t straightforward so I haven’t implemented it. If anyone has tips, I’d be thrilled to hear them.

Fixing it (locally, at least)

(Warning: I don’t know what I’m doing. Don’t make any of these changes, or any others, without backing up the files first.)

(Update: Matthias Bussonnier has an informative post showing the right way to make these changes. If you make the CSS changes I describe below, do it the way he advises, not through the files I describe here.)

The notebook is served through the browser, so its frontend is basically just HTML, Javascript, and CSS. The typography and appearance of the notebook is nearly all driven by CSS files located where IPython is stored on your system. This will differ based on your OS and your Python distribution. On my mac, with the AnacondaCE distribution, the stylesheets are located in /Users/cvogel/anaconda/lib/python2.7/site-packages/IPython/frontend/html/notebook/static. There are several subfolders there, including one called /css and /codemirror. You can also take a look at the stylesheet files by firing up a notebook, and using your browser’s inspector. If your browser (e.g. Chrome) lets you edit stylesheets on the fly in the inspector, you can try out changes relatively safely.

Here are the edits I’ve made on my system to address the issues above. First, in the /css folder, in the file called notebook.css

1. Set code input cells to be narrower (code that runs past the width will be invisible). I try to set this for about 80 characters plus some buffer. There’s not way to set width as number of characters in CSS, so you may have to experiment to see what ex-widths works with your font.

div.input {
width: 105ex; /* about 80 chars + buffer */
...
}

2. Fixing markdown/text cells. I make changes to the font, width, and linespacing. I’m using Charis SIL, a font based on the classic Bitstream Charter, and freely available here. Shortening the lines and adding some line space (120% to 150% of point size is usually a good range) for legibility.

div.text_cell {
width: 105ex /* instead of 100%, */
...
}
div.text_cell_render {
/*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/
font-family: "Charis SIL", serif; /* Make non-code text serif. */
line-height: 145%; /* added for some line spacing of text. */
width: 105ex; /* instead of 'inherit' for shorter lines */
...
}

3. Add styles to specify sizes for headers.

/* Set the size of the headers */
div.text_cell_render h1 {
font-size: 18pt;
}
div.text_cell_render h2 {
font-size: 14pt;
}

Then, in the /codemirror/lib subfolder, there’s a file called codemirror.css. In here we can change the font used for code, both input and interpreter output. I’m using Consolas.


.CodeMirror {
 font-family: Consolas, monospace;
 }

Obviously these changes only affect notebooks you view on your local machine, and whoever views your notebooks on their own machine, or on nbviewer will see the default style.

Here are before and after shots of these changes:

ipynb_unstyled

ipynb_styled

Fixing it (globally?)

So this is all cute right? And it’s nice that we can do some customizations to the notebook, but, you know, big deal.

I’d argue this is actually more important than just aesthetic tinkering. The IPython notebook is becoming a one-stop-shop for exploration, collaboration, publication, distribution, and replication in data analysis. Like I said above, I think it’s not unreasonable that notebooks could replace a large class of scientific papers. But to do that, it has to perform as well as all the fragmented tools that researchers are currently using. Otherwise, people are going to keep pasting their code and results into Word and Latex documents. In other words, the notebook has to work not just as an interactive environment, but also as a static document. The IPython team realizes this, which is why tools like nbconvert exist.

People are doing amazing things in the notebook. The typography should encourage people to read them, and not just serve as suped-up comments.

Tools are often strongly associated with aesthetic characteristics that are only peripheral to the tool itself. ggplot can make charts that look however you want, but when people think of ggplot, they think of the gray background and the Color Brewer palette. And while main selling point of ggplot is its abstraction of the graph-making process, I think it was the distinctive and attractive style of its graphs that made it catch on so successfully. On the opposite end of the spectrum, when people think of Stata graphics, they think of this, and wince. And Latex will typeset documents with whatever crazy font you want, but in everyone’s mind, Latex <-> Computer Modern (for better or worse). Design defaults are important: they’re marketing and they encourage good habits by your users. It’d be a shame to have it be that people think of the IPython notebook and picture long lines of small, single-spaced Helvetica Neue.

It’s an insanely powerful tool. It’d be awesome if it were beautiful too, and that goal seems eminently do-able.

About these ads
This entry was posted in Uncategorized and tagged , . Bookmark the permalink.

14 Responses to Better typography for IPython notebooks

  1. Oh, I am so glad that someone is paying attention to typography. That is an area we have not spent much time and I know we have lots of room for improvement. Before diving into your actual comments, one tip: anyone can try these, or other, css changes by simply putting the css inside tags in a markdown cell. I have started to do this when I give talks using the notebook and want to increase the font sizes.

    Long lines of text. This is a great point, and I completely agree that reading long lines of text is difficult. But, there is a tension here: output often has long lines. I don’t want to narrow down everything and make dealing with output difficult. Question…would you make the code/markdown cells have fixed width? A smaller percentage? What would you do with the extra width on the page?

    Long lines of code. I agree having the full window width is probably not needed, but limiting it to 80 chars it too narrow. The big problem is that code cells become difficult to work with when they grown horizontal scroll bars. I like that I never have to worry about this right now. How far could we narrow things and still preserve this feature?

    Fonts. We did spend quite a bit of time thinking about the font used in code cells. Ultimately, we decided to go with the default monospace, not because it is pretty, but because that allows users to set the monospace font at the browser level and we will respect that. If we choose a global monospace font, it is more difficult for users to override it with the best choice on their system.

    Serif/Sans. Need to think more about this. You raise a great point that books, papers, mags, etc. all use serif fonts. But most modern web and native applications use san serif fonts. So it becomes a question of identity. Is the notebook a web application? Or is it more of a programmable book?

    Vertical spacing. I agree that a bit more would be nice, but vertical space in super precious. We have been very deliberate to compress things vertically as much as possible. Right now, the heading cells have too much vertical space relative to everything else. I need to play around with this to find the right balance.

    Now I want to play…

    • Carl says:

      Brian,
      First of all thanks for all the hard work you and your team have done on the notebook. It’s completely changed how I work. Second, thanks for your thoughtful comments, let me try to address all your good points (this is going to be long).

      One overall point, is that this is an incredibly tricky problem. Typographic design is supposed to reinforce the content and the authors intent. But unlike print, or even web sites, the notebook’s content is made on the fly, and you have to make design decisions anticipating all the kinds of content authors may use, and all the ways they may be presenting it. Like you say, it’s a question of identity. Whether the notebook is a:
      1. Console for code/data exploration
      2. Literate program
      3. “Live” scientific paper with interweaved code (a “programmable book”)
      4. Static blog post
      5. Presentation on large screens/slides
      6. Printed article (dead trees, PDF, etc)

      all ideally require different typographical choices. (I love the term “programmable book,” by the way.) You’ll have to prioritize some use cases over others, or do a LOT of work with stylesheets and conversion tools. I’d say that having the more accessible styling interfaces you and Stefan pointed out is a huge help for these issues.

      And there’s a tension between giving users full freedom to use the notebook how they want (and the notebook’s flexibility is one of its greatest assets), and enforcing some good style on them. I tend to fall a bit more on the “enforce good style” end of the spectrum than most. I do think 9 out of 10 times the way to go is to make “good style” defaults so users have to make an effort to be ugly if the need to.

      To your specific points:

      Long lines of text. Right now, I’ve only styled input and text cells to be narrower. Output cells still run 100% window width, for the reasons you point out. For cells whose width you’d want to constrain, I think ‘em’ or ‘ex units are the way to go (% of window is sensitive to monitor sizes; fixed pixels will break if users want a larger type.). The idea would be to have 65-80 characters per line, regardless of what size the characters are displayed at.

      Long lines of code. I agree it’s tricky. If users need, or just want, to have a long line of code you don’t want to make it difficult for them to work just to enforce PEP8 fanaticism. (Even my setting is longer than 80 chars). Maybe there’s a compromise – like a wider box with some graphical element indicating the 80 char margin. I’d have to think about it a little bit. But like I said, making users customize to get bad-style is not the worst policy. It’s better than making users work to keep good style. I also think it’s just a natural tension between exploration and presentation. It’s a hassle to keep to 80 chars when you’re just fooling around with code, but when you want to show it to someone else, you want it clean.

      Code font. I understand your logic. My partial rebuttal to it is that monospace code. If I have set monospace in the browser to get a particular code font in the notebook, then that’s a global change on every website I visit, and I may prefer not to do that. (Then again, I’m not sure how much non-code monospace is floating around on the web. Hopefully not too much.)

      Serif/sans-serif. I think the preference towards sans-serif fonts on web sites is largely an artefact of low res monitors. In the era of retina displays, I think that’s less of a concern. And especially now with the increasing availability of web fonts, I’m seeing more and more sites in serifs. (And if you look at say, nearly every major newspaper’s web site, their articles are in serif typefaces). But I think the strongest argument in favor of a serif font for markdown cells is math typesetting. There’s no good way, as I see it, to do math typesetting in a sans-serif typeface. And I think having sans-serif text around serif math looks awful. I think your design benchmarks should be academic journals, not websites.

      Vertical spacing. I understand the tradeoff, but I think readability should be the first priority. No point fitting a bunch of stuff on the screen if no one is going to read it. I’d rather scroll than squint.

    • Brian, please could we have the ability to distribute iPython themes separately, ‘packaged’? Then people could tinker and share their themes, and others could include them.

      Thinking visually, could you provide two sliders in the footer of the window, one to control text line length, and the other code cells? That would give the user control for whatever worked best on their monitor/browser.

      iPython is amazing and I’m loving the work to bring other programming languages into it!

  2. Thinking more about the serif fonts. If we did go in that direction, what serif font(s) would you use that would be available to everyone?

    • Carl says:

      One of the benefits of the notebook over a web site is that to use it, people have to have installed IPython. This means you can (license permitting) feasibly ship the font with the notebook. (And serve it on nbviewer). So I don’t think you’re stuck with web/system fonts like Georgia, TNR, etc.

      Given that, I think (1) integration with math typesetting and (2) screen readability are the priorities. Ideally you want a text font that works with Latex math and has a full set of symbols, etc. You could use Computer Modern, but that looks awful on screen (it’s too thin)(and it doesn’t look great in print either). This article discuss some other options: http://www.tug.org/pracjourn/2006-1/hartke/hartke.pdf

      I like Charis a lot because (1) it’s open source and has a very open liscence, (2) is attractive on print and screen (it’s based on Charter, which Matthew Carter optimized for printing on early 300-dpi laser printers), (3) has lots of symbols, including true small caps, and (4) is compatible with the Latex ‘charter’ font package (see the article I linked to). I you have math typeset in Charter, it will fit right in with Charis text (the two are basically identical).

      But there are certainly other options. Like I said in my comment above, I’d look to academic journals for design cues, not necessarily the web. But that may be because I see that notebooks more as “programmable books” and have a limited imagination for other contexts.

  3. Stefan says:

    Great ideas, thanks for sharing! Even better: If you’re running a recent 14-dev build (i.e. from the Github master branch), you can apply all these CSS changes via a custom CSS file in your profile:

    ~/.ipython/profile_default/static/css/custom.css

    Simply add !important to each CSS statement to make sure the additions take precedence, e.g.

    div.text_cell {
    width: 105ex !important; /* instead of 100%, */
    }

    That should make it easier to preserve customizations when updating IPython.

    • Carl says:

      Stefan -
      Thanks, that sounds great! Seems like it also makes your changes easier to distribute with your notebook.

      • Stefan says:

        Just noticed a typo: the file name should be custom.css, not static.css — maybe you can change that in my original comment Carl.

    • Actually anything in `~/.ipython/profile_default/static/` will overwrite its counter part in static folder of ipython installation. so you could copy/past lib/codemirror/codemirror.css and modify it. works also for js.

      Another user have made proposition on changing the default css. We just want to move to bootstrap/less before to have a more customisable css.

      Embedding css in mdcell should survive the nbviewer step.

  4. jiffyclub says:

    Yeah not a fan of the serif fonts in the browser. It would be nice to have an 80 character guide in the code cells, though. Letting users customize this is I think the best way to go. I have my notebook setup to use Adobe’s Source fonts, but those are custom installs so not everyone will have them.

    • Carl says:

      I like the Source fonts a lot. No one will ever accuse Adobe of having bad taste in type. I think Source Code is a great option for code and output (I linked to it in the post). (Though for some reason it’s got terrible hinting on my windows box).

      See my comments to Brian on why I can’t agree on the sans serif.

      As for user customization, I agree. The notebook is simply too flexible and used in too many ways for one design to fit all needs. Nonetheless, that doesn’t mean giving up on making good default design choices based on ‘priority’ use cases.

  5. You make a great point about LaTeX/Math being rendered using serif fonts. I will have a look at the different serif font options.

    Further questions about layout. If we narrow code+markdown cells, how would we layout the page horizontally:

    1. We could center the notebook area and leave empty areas on the L and R, like github for example. In this case i would probably make the notebook area ~940 px so the cells would have that width.
    2. We could create a new area on the L for widgets and other content and push the notebook area to the R. This area might be useful to have, but I don’t want to go looking for new stuff to put on the page that would clutter things up.
    3. Fixed width of fluid layout?

  6. Carl says:

    You have a better sense than I do what the trade-offs of moving around widgets, etc., are. Moving them to the side would free up vertical space, but I remember the pre-0.12 versions had something similar, and folks (including myself) weren’t crazy about it.

    From my perspective, I don’t know that narrowing cells requires any other serious layout changes. If you see my styled version, yeah there’s a lot of white space on the right, but so what? You could feasibly center it, maybe that looks ok. My inclination would be to just add a little bit of gutter on the left (so text doesn’t butt right up against the edge of the window), but that’s it.

    I’m a web design ignoramus (my limited design/type background is in print). But my thinking would be to specify cell widths in ems (even though I used ex’s in mine), so that layout is robust users who want to shrink or grow their font size. Maybe I’m missing something though. I’ll have to play around a bit more to know better.

  7. Pingback: Better typography for IPython notebooks, now | Healthy Algorithms

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s