I couldn't really see the point of doing that, unless you were to generate *all* the ticks automatically
As we have it, the numbers are just explicit, so why generalise this  part of it ?

I could indeed form the contour levels (and tick values) by calculation from the min and max with matplotlib.ticker.LogLocator.  But that turns out to be a bit more involved than you might think, as I discovered when I tried it.  This is my neatest result so far ...
```
    # Add a colourbar, with suitable "log" ticks, and end-extensions to show
    # the handling of any out-of-range values.

    # Calculate decade-spaced tick values from the limit values.
    tick_levels = mticks.LogLocator(subs=[1, 3]).tick_values(
        minimum_log_level,
        maximum_scale_level)
    tick_levels = [tick for tick in tick_levels
                   if minimum_log_level <= tick <= maximum_scale_level]
    tick_levels = [-tick for tick in tick_levels[::-1]] + tick_levels

    # Replace the central pair of ticks at -min, +min with a single tick, to
    # stop them overlapping.
    i_minval_tick = len(tick_levels) / 2 - 1
    tick_levels.pop(i_minval_tick)

    # Create tick labels, adding a +/- character to the (single) minimum label.
    tick_format = "{:.1g}"
    tick_labels = [tick_format.format(tick) for tick in tick_levels]
    tick_labels[i_minval_tick] = r'$\pm$' + tick_labels[i_minval_tick]

    colorbar_tick_formatter = mticks.FixedFormatter(tick_labels)
```
(just in case you thought I couldn't do it :wink: !)

But all this is, I think, just far too distracting.
By contrast, using manual selection has the advantage that that the ticks and labels are *literals*, which means you can see - **without having to explicitly explain it** - how the contour levels and tick values need to be constructed slightly differently.

So I think in practice, a purely manual selection of values is simply clearer, and less likely to obscure the things we are actually interested in here.