Repository: bokeh/bokeh

Issue:
Sub-second timezone strftime support
Hi, I realize that this likely hadn't been a heavily supported area of bokeh yet, but for the following datetime axis formatters (note: haven't tried this but I assume it runs +/- typos):

``` python
import datetime
import bokeh.models
import bokeh.plotting

# Spaced apart by 20 microseconds
num_ticks = 5
micros = 20
xs = [datetime.datetime(year, 1, 1, 0, 0, 0, i) for i in range(0, num_ticks * micros, micros)]
ys = [i % 2 for i in range(num_ticks)]
bokeh.plotting.output_server('test')
fig = bokeh.plotting.figure()
fig.line(xs, ys)

# These are what I might have expected to be default formatters for time series.
datetime_fmt = {
    "microseconds": "%H:%M:%S.%f",
    "milliseconds": "%H:%M:%S.%3",
    "seconds": "%H:%M:%S",
    "minsec": "%H:%M:%S",
    "minutes": "%H:%M:%S",
    "hourmin": "%H:%M:%S",
    "hours": "%H:%M:%S",
    "days": "%x"
}
fig.xaxis.formatter = bokeh.models.DatetimeTickFormatter(
    formats={x: [y] for x,y in datetime_fmt.items()})
bokeh.plotting.show(fig)
```

When you zoom into the microsecond range both `%3` and `%f` do not expanded. js-`timezone` supposedly supports `%3` so not sure why it doesn't get expanded. `%f` doesn't get supported because bokehjs' DatetimeTickFormatter uses non-serialized functions as defaults (and hence can't be called via the python api):

``` coffeescript
class DatetimeTickFormatter extends HasProperties
  # This table of formats is convert into the 'formats' dict.
  _formats: {
    'microseconds': [_us, _ms_dot_us]
    'milliseconds': ['%3Nms', '%S.%3Ns']
    'years':        ['%Y', _two_digit_year, _four_digit_year]
  }
```

Instead it would be nicer to, say, use a regex to replace "%f" with 6-digit microsecond strings prior to calling `tz()`.

The documentation regarding this formatter is sparse and it took me quite a while to figure out, for example, why `bokeh.models.DatetimeTickFormatter` accepted `Dict(.., List(String))` as opposed to `Dict(.., String)`. Maybe if somebody could (1) point me to where documentation is in this repo and (2) how to set up bokeh-server to use local coffeescript js, then I could submit a pull request for these issues?

Edit: I think I'll be able to figure out how to do this + submit a pull request.



Discussion:

Resolving patch:
diff --git a/bokeh/models/formatters.py b/bokeh/models/formatters.py
--- a/bokeh/models/formatters.py
+++ b/bokeh/models/formatters.py
@@ -217,7 +217,7 @@ class DatetimeTickFormatter(TickFormatter):
         claim that `timezone`_ makes to support "the full compliment
         of GNU date format specifiers." However, this claim has not
         been tested exhaustively against this list. If you find formats
-        that do not function as expected, please submit a `github issue`,
+        that do not function as expected, please submit a `github issue`_,
         so that the documentation can be updated appropriately.
 
     %a
@@ -254,6 +254,11 @@ class DatetimeTickFormatter(TickFormatter):
         Like %d, the day of the month as a decimal number, but a
         leading zero is replaced by a space.
 
+    %f
+        Microsecond as a decimal number, zero-padded on the left (range
+        000000-999999). This is an extension to the set of directives
+        available to `timezone`_.
+
     %F
         Equivalent to %Y-%m-%d (the ISO 8601 date format).
 
@@ -298,6 +303,13 @@ class DatetimeTickFormatter(TickFormatter):
     %n
         A newline character.
 
+    %N
+        Nanosecond as a decimal number, zero-padded on the left (range
+        000000000-999999999). Supports a padding width specifier, i.e.
+        %3N displays 3 leftmost digits. However, this is only accurate
+        to the millisecond level of precision due to limitations of
+        `timezone`_.
+
     %p
         Either "AM" or "PM" according to the given time value, or the
         corresponding strings for the current locale.  Noon is treated


Test patch: