Selectively exporting headlines in org-mode

| categories: org-mode | tags:

I have on several occasions needed to selectively export only portions of an org document. For example, I may write a problem set or exam, and have some headlines that are the problems, and others that are the solutions. Or, I may have done some analysis in a headline, e.g. statistics of problem scores that I do not want in exported content, or I have a manuscript with a supporting information section that does not go in the exported manuscript, and the manuscript cannot go in the supporting information file.

org-mode supports selective export through use of tags. However, this is inflexible if you want to export multiple different documents with different selective exports, unless you don't mind changing the settings, or commenting and uncommenting lines all the time.

Enter dynamic binding of variables in emacs-lisp. We can temporarily define variables, especially org-export-select-tags and org-export-exclude-tags, and write emacs-lisp code blocks to export the current document the way we want. First, let us create some headlines.

1 problem 1   problem

description of a hard problem

1.1 solution to problem 1   solution

it is an easy solution

2 problem 2   problem

what is the square root of 100?

2.1 solution to problem 2   solution

why it's 10 of course.

3 Code to export   code

3.1 Export just the problems

First, let us output this document with just the problems. The code block does that, just put your cursor in in block and press C-c C-c (in emacs of course).

(let ((org-export-exclude-tags '("solution" "code"))
      (org-latex-default-packages-alist
       '(("" "lmodern" nil)
         ("linktocpage,
  pdfstartview=FitH,
  colorlinks,
  linkcolor=blue,
  anchorcolor=blue,
  citecolor=blue,
  filecolor=blue,
  menucolor=blue,
  urlcolor=blue" "hyperref" t)))
      (async nil)
      (subtreep nil)
      (visible-only nil)
      (body-only nil)
      (ext-plist '()))
  (org-latex-export-to-pdf async subtreep visible-only body-only ext-plist))
(rename-file "blog.pdf" "blog-1.pdf")

You get this: blog-1.pdf which only has the problems in it.

3.2 Problems and solutions

Next, we consider the problems and the solutions. We cannot just get solutions in this document because solutions are nested in the problems.

(let ((org-export-exclude-tags '("code"))
      (org-latex-default-packages-alist
       '(("" "lmodern" nil)
         ("linktocpage,
  pdfstartview=FitH,
  colorlinks,
  linkcolor=blue,
  anchorcolor=blue,
  citecolor=blue,
  filecolor=blue,
  menucolor=blue,
  urlcolor=blue" "hyperref" t)))
      (async nil)
      (subtreep nil)
      (visible-only nil)
      (body-only nil)
      (ext-plist '()))
  (org-latex-export-to-pdf async subtreep visible-only body-only ext-plist))
(rename-file "blog.pdf" "blog-2.pdf" t)

This document (blog-2.pdf ) now has problems and solutions. Note that neither of these documents has the section we labeled :code:.

4 Summary

Tags are a nice way to label sections. In combination with dynamic binding, you can build code blocks that selectively export pieces of an org-file by temporarily defining the values of variables. In this example, there are four versions of this document: 1) the org-file that contains everything, 2) the html blog post, 3) a pdf with the problems, and 4) a pdf with problems and solutions. Good luck getting that out of a Word file ;)

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

org-mode source

Discuss on Twitter

Custom directives

| categories: org-mode, emacs | tags:

You can define custom special blocks in org-mode. Here is an example of creating attention and note directives. Note you need to specify the styles and environments in the header like this:

#+HTML_HEAD_EXTRA:  <style>.attention {font-size: 30px; text-indent: 50px; color: red; background-color:HotPink;}</style>
#+HTML_HEAD_EXTRA:  <style>.note {font-size: 30px; text-indent: 50px; background-color:LightSkyBlue;}</style>

#+LATEX_HEADER: \usepackage[usenames,dvipsnames,svgnames,table]{xcolor}
#+LATEX_HEADER: \newenvironment{attention}{\color{red}}{\ignorespacesafterend}
#+LATEX_HEADER: \newenvironment{note}{\itshape}{\ignorespacesafterend}

That allows you to define different looks for exporting to html and LaTeX. For the blog post, I put the style in the body of the html.

Here is the markup for an attention block.

#+BEGIN_ATTENTION
Pay attention to this text!
#+END_ATTENTION

Renders like this:

Pay attention to this text!

A note is defined as:

#+begin_note
this is a note
#+end_note

and it renders like this:

this is a note.

I am not sure if it is possible to add arguments, e.g. via attributes. Anyway, this may enable some flexibility in adding content that may be rendered in html and LaTeX in org-mode. There is a function (org-html-special-block and org-latex-special-block) that does the rendering, and it has an info plist that probably has the information. It does not appear you can pass arguments in though. That would require a filter that redefines the rendering.

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

org-mode source

Discuss on Twitter

Add subheadings to all headings in an org-file at some level

| categories: org-mode | tags:

On the org-mode mailing list someone asked how to insert a sub-heading with properties at some level in a tree. The application is they have a tree they use to store grades for a class, and they want to easily add a new level for an assignment for each student. The new level will have a title, and some properties to store the grade in.

This can be done with org-map-entries. This will visit all the headlines and run a function. For this example, students are at level 3, and we want to add a headline at level 4 with the title "Essay 2", and with a property for the grade. The following code does this.

(let ((MATCH t)
      (SCOPE 'file)
      (SKIP nil)
      (spacing nil))
  (org-map-entries
             (lambda ()
               (let ((level (nth 1 (org-heading-components))))
                 (if (= level 3)                     
                     (save-restriction
                       (org-narrow-to-subtree)
                       (goto-char (point-max))
                       
                       (org-insert-heading)
                       (insert "Essay 2\n")
                       (org-entry-put (point) "GRADE" nil)
                       ;; now cut tree and paste at level 4
                       (org-cut-subtree)
                       (org-paste-subtree 4)
                       )))) MATCH SCOPE SKIP))

This code does not check for duplicates, so if you run it again, you get another set of entries for Essay 2. That might actually be hard to prevent without setting a unique ID for each new entry, something like Student-Name-Essay-2.

I found it necessary to cut and paste the new subtree to get to the level I wanted because in Class two, there were not already subtrees at level 4, and the code above went into a recursion loop.

I could not figure out why I had to narrow to the subtree, and go to the end of that subtree. Without doing that there was another recursion loop.

Below here is a slightly modified subtree showing a structure of two courses an instructor might have, with students in headlines at level 3. The code above has already added headlines at level 4 for "Essay 2". You have to check out the actual org-file to see that the properties are there.

For application, the code above could be put in an emacs-lisp file as an interactive command you could call with M-x.

1 Class One

1.1 Student 1

1.1.1 Essay One

Here is my comment to the student on their essay. The grade/mark itself will be stored as a property or priority. <<<<<<<<<<<<<<HERE I'd like to add a node for "Essay Two"

1.1.2 Essay 2

1.2 Student 2

Comment on John's essay. <<<<<<<<<<<<<< I to add the same node skeleton here, automatically

1.2.1 Essay 2

1.3 Student 3

1.3.1 Essay One

Comment on Sally's essay. <<<<<<<<<<<<<< And here.

1.3.2 Essay 2

2 Class Two

2.1 Student 1

2.1.1 Essay 2

2.2 Student 2

2.2.1 Essay 2

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

org-mode source

Discuss on Twitter

Writing exams in org-mode

| categories: org-mode | tags:

There are a few aspects of writing exams that are tedious the way I normally do it. Typically I write exams in Word because I can easily see the layout, how much whitespace there is to write answers in, etc… I like to put a gradesheet on the final page which lists each problem, the points it is worth, and a blank to put the grade for that problem into. It is tedious to go back through 10 pages of questions to look up all the points, enter them in, add them up, etc… And if I decide to renumber the questions or move them, it must be repeated.

Construction of the grade sheet ought to be automated. That is not going to happen in my hands in MS Word. I have seen this done in LaTeX in the Acrotex educational package, but I don't see myself hacking LaTeX any time soon either. Enter org-mode. I could see writing the exam in org-mode, and writing some code to construct the grade table.

The idea is that we would store the points in a PROPERTY of an org-heading. Then, to create the table, we just loop through the headlines, gather the levels and points, and then construct a table to put in the exported LaTeX. The next section contains some exam questions that will form the basis of this post.

1 The exam section

1.1 Do you get it?

What is the answer to the universe? \vspace{2cm}

1.2 Multipart question

1.2.1 Circle the best answer

What is 1 + 1? a) 2 b) 3 c) 4

1.2.2 Describe a cat.

\vspace{2cm}

1.3 Essay question

Expound on the meaning of life. \vspace{3cm}

2 Back to the grade table construction

We will parse the buffer to get the headlines, and then extract some properties from each headline. For each headline that has points we will print the title and points it is worth, and finally the total number of points.

(setq total-points 0)    ; counter for the total points

;; now loop over headlines
(org-element-map 
    (org-element-parse-buffer 'headline) 'headline 
  ;; function to print headline title and points
  (lambda (headline) 
    (let ((points (org-element-property :POINTS headline))
          (title  (org-element-property :title headline)))
      (if points (progn
                   (setq total-points (+ total-points (string-to-number points)))
                   (princ (format "title=%s\nPOINTS=%s\n\n" title points)))))))

(princ (format "Total points = %s" total-points))
title=Do you get it?
POINTS=5

title=Circle the best answer
POINTS=10

title=Describe a cat.
POINTS=4

title=Essay question
POINTS=25

Total points = 44

That is the foundation for the grade table. What I would like is the grade table to be structured like this:

problem Points grade
ref to heading #points  

Where the ref to heading is the same number as the actual heading. During the export, labels are generated for each section, which we could refer to. To take advantage of this we need to figure out what the labels are, so we can refer to them.

After quite a bit of hackery, I figured out how to access this information 1. It is not readily apparent this is how to do it, but it works!

(let* ((info (org-export-collect-tree-properties (org-element-parse-buffer 'headline) '()))
       (headline-numbering (plist-get info :headline-numbering)))
(org-element-map (plist-get info :parse-tree) 'headline
  (lambda (headline) 
    (format "\\ref{sec-%s}" (mapconcat 
                      (lambda (x) (format "%s" x)) (cdr (assoc headline headline-numbering)) "-")))))
("\\ref{sec-1}" "\\ref{sec-2}" "\\ref{sec-2-1}" "\\ref{sec-2-2}" "\\ref{sec-2-2-1}" "\\ref{sec-2-2-2}" "\\ref{sec-2-3}" "\\ref{sec-3}" "\\ref{sec-}")

So, let us try putting this all together 2.

(setq total-points 0)    ; counter for the total points
(princ "#+caption: The grade table\n")
(princ "#+attr_latex: :align |c|c|c|\n")
(princ "|-\n")
(princ "|Problem|Possible Points|Points earned|\n|-\n")
(let* ((info (org-export-collect-tree-properties (org-element-parse-buffer 'headline) '()))
       (headline-numbering (plist-get info :headline-numbering)))
  (org-element-map (plist-get info :parse-tree) 'headline
    (lambda (headline) 
      (let ((ref (format "\\ref{sec-%s}" (mapconcat 
                                          (lambda (x) (format "%s" x)) (cdr (assoc headline headline-numbering)) "-")))
            (points (org-element-property :POINTS headline)))
        (if points (progn
                     (setq total-points (+ total-points (string-to-number points)))
                     (princ (format "|%s|%s|  |\n|-\n" ref points))))))))

(princ (format "| |Total points| %s|\n" total-points))
(princ "|-\n")
Table 1: The grade table
Problem Possible Points Points earned
\ref{sec-1-1-1} 5  
\ref{sec-1-1-2-1} 10  
\ref{sec-1-1-2-2} 4  
\ref{sec-1-1-3} 25  
  Total points 44

Note this table gets munged by Mathjax in HTML. I am not sure that is fixable. You can open the pdf and see the results.

This works ok. There is still some work to be done. For example the boxes in the grade table are not very large. The references are a little odd in this case, but that is an artifact of the fact that you cannot nest a section deeper than 3 levels in LaTeX without some work, and I nested my exam section in a second level heading so it would appear in the blog post. A real application of this would not have all these other sections, and would not export the build section. It is a tad tedious to hand build the table, but not too bad.

It might be better to use CUSTOM_ID labels in the sections, rather than try to build up the references. You still need to think about what the labels would be, and we are used to seeing numbers!

3 building the pdf

I have gotten in the habit of building the latex file from commands, and manually running them with C-c C-c.

(let ((org-latex-default-packages-alist
       '(("" "minted" nil)
         ("linktocpage,
  pdfstartview=FitH,
  colorlinks,
  linkcolor=blue,
  anchorcolor=blue,
  citecolor=blue,
  filecolor=blue,
  menucolor=blue,
  urlcolor=blue" "hyperref" t)))
      (async nil)
      (subtreep nil)
      (visible-only nil)
      (body-only nil))

  (org-latex-export-to-latex async subtreep visible-only body-only '()))
(progn
  (shell-command "pdflatex -shell-escape writing-exams-in-orgmode")
  (shell-command "pdflatex -shell-escape writing-exams-in-orgmode"))

Footnotes:

1

This code does not generate correct labels for headlines with TODO in them, or for footnotes.

2

Note this table gets munged by Mathjax in HTML.

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

org-mode source

Discuss on Twitter

Enabling right-clicks in org-mode links

| categories: org-mode | tags:

Out of the box you can click on org-mode links to make the do things. On my machine, all clicks are equal, left mouse, middle mouse, and right mouse all act as a "click". I was curious about whether I could get different behavior on a link with a left or right mouse click. It is easy enough to define a new link type . You define a function that is run when you click on the link.

To figure out what to do here, I looked into the events handling in emacs. According to this page , there are click events. So, after we click on a link, there should be a click event which was the last input event. We can get that, figure out which button was pressed, and run code accordingly. We will make the code add some lines to the buffer after the link about what happened.

Here is my link definition.

(setq counter 1)
(org-add-link-type
 "test"
 ;; this function is run when you click
 (lambda (link-string) 
   (let ((button (car last-input-event)))
     (cond ((eq button 'mouse-1) 
            (end-of-line)
            (insert (format "\nclick %s. mouse-1 pressed %s\n" counter last-input-event))
            (setq counter (+ counter 1)))
           ((eq button 'mouse-2) 
            (end-of-line) 
            (insert (format "\nclick %s. mouse-2 pressed %s\n" counter last-input-event))
            (setq counter (+ counter 1)))
           ((eq button 'mouse-3) 
            (end-of-line)
            (insert (format "\nclick %s. mouse-3 pressed %s\n" counter last-input-event))
            (setq counter (+ counter 1))))))
 ;; formatting
(lambda (keyword desc format)
   (cond
    ((eq format 'html) (format "<pre>%s:%s</pre>" keyword desc)))))

Here we make a link. When you click on it, it adds lines right after the link telling you what was clicked on. I left-clicked, middle-clicked and right-clicked. The right-clicked result is the first line.

test:which-button
click 3. mouse-3 pressed (mouse-3 (#<window 46 on blog.org> 56959 (57 . 456) -320964819 nil 56959 (7 . 28) nil (1 . 8) (8 . 16)))

click 2. mouse-2 pressed (mouse-2 (#<window 46 on blog.org> 56959 (57 . 456) -320965724 nil 56959 (7 . 28) nil (1 . 8) (8 . 16)))

click 1. mouse-2 pressed (mouse-2 (#<window 46 on blog.org> 56959 (57 . 456) -320966660 nil 56959 (7 . 28) nil (1 . 8) (8 . 16)))

Curiously, this only shows that mouse-2 (for left or middle mouse) or mouse-3 (for right click) was pressed, never mouse-1. I am not sure what causes that. If I try to capture an event it does show mouse-1 is active.

(princ (read-event))
(down-mouse-1 (#<window 34 on blog.org> 56437 (253 . 308) -322917920 nil 56437 (31 . 19) nil (93 . 4) (8 . 16)))

Anyway, it looks conceivable that you could have different link actions occur for different mouse clicks. I could see using this in a citation link, where a left click might open the citation in my bibtex file, and right clicking would open a pdf of the citation if it existed.

I have not figured out how flexible this might be, for example could you use modifier keys with mouse clicks? This code suggests that it is possible in emacs, but so far none of these make it into the last-input-event in the org-link clicks.

(princ (read-event))
(S-down-mouse-1 (#<window 34 on blog.org> 56725 (1 . 299) -322897656 nil 56725 (0 . 18) nil (1 . 11) (8 . 16)))

It might be difficult remembering all the modifiers and clicks, but it would be cool if it was possible!

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

org-mode source

Discuss on Twitter
« Previous Page -- Next Page »