AdaptiveTimeScale.py


Matplotlib is the python programming language's plotting library. It is extraordinarily sophisticated, capable of producing a huge variety of plot types, as a glance at its gallery page will demonstrate.

When plotting time-series data in matplotlib, an experienced user can set the labels of the axis ticks individually to have whatever format s/he desires, but this requires skill and effort.

There is automated tick-labelling functionality built in to matplotlib that works for many circumstances, but frequently the results are disappointing, as the following figures show:

Unsatisfactory results from matplotlib's automated datetick functionality




Example 1: In this figure, the full yyyy-mm-dd HH:MM:SS date string format is used for the ticks. Even with the tick labels rotated to make better use of space, the result is crowded and difficult to read. Note that the time is "00:00:00" for every tick, so there is a lot of redundant text here.




Example 2: This is the same plot as in Example 1, but zoomed in. Again, there is a lot of redundant text here, resulting in crowding: note that every tick is for a time in January 5, 2005. There's no good reason for including this information in every tick label.




Example 3: An approach that is frequently used to avoid the crowding evident in Examples 1 and 2 is to use more compact tick label formats, as shown here. The result, though, is ambiguous labels, as information is necessarily left out. Are these date ticks on January 2, 4, 6, 8, and 10? Or are they on the first day of February, April, June, August, and October? What is the year?

A better way: time ticks and labels that adapt automatically to the axis limits:

The solution to this dilemma is to put as much information as possible into the x-axis label. This allows the removal of redundant information from the axis tick labels without resulting in ambiguous dates. AdaptiveTimeScale.py does this automatically, adapting for the time range being plotted without user intervention. The following two examples are duplicates of the earlier examples, but created with AdaptiveTimeScale.py instead of matplotlib's built-in time-tick functionality.



Example 4: Plot produced automatically using AdaptiveTimeScale.py. This is a duplicate of the figure in Example 1, but as much information as possible has been incorporated into the x-axis label, allowing the use of compact time-tick labels without creating ambiguity. 



Example 5: Plot produced automatically using AdaptiveTimeScale.py. This is a duplicate of the figure in Example 2 (i.e., it is a zoomed-in version of Examples 2 and 4). Again, as much information as possible has been incorporated into the x-axis label, allowing the use of compact time-tick labels without creating ambiguity. 


How hard is it to use AdaptiveTimeScale.py?

Not hard at all. The following is a complete, if simple, example of its use, including the creation of demonstration data. Lines specific to AdaptiveTimeScale have been highlighted:

import AdaptiveTimeScale
import datetime as dt
import matplotlib.pyplot as plt
y = [1,2,3]
t = [dt.datetime(2015, 12, 31, 16, 0, 0),
dt.datetime(2015, 12, 31, 23, 0, 0), 
dt.datetime(2016, 1, 1, 4, 30, 0)]
fig, ax = plt.subplots()
ax.plot(t, y,'o-')
ax.set_xscale('adaptivetime')
plt.show()

Basically, everything is the same as normal plotting of data against datetime-format time, apart from the "import AdaptiveTimeScale" and "ax.set_xscale('adaptivetime')" commands. The figure that results is shown below:



A more complicated example, showing optional input arguments

The behaviour of AdaptiveTimeScale.py is mostly automated, but some manual control is possible through the use of keyword arguments. In the example plot below, the user has chosen to suppress tick and axis labelling in the upper axes for a less-cluttered plot. The value of "maxTicks" has also been adjusted to prevent thinning of the ticks (the default maximum number of ticks is 8, but in this case it was decided that 9 ticks would not result in an excessively-crowded plot). Finally, the timezone string "UTC" was appended to the axis label.


The code used to generate this figure was:

import AdaptiveTimeScale
import datetime as dt
import numpy as np
import matplotlib.pyplot as plt
y = np.array([440, 100, 200, 50, 400, 300, 60, 70, 80, 90])
timeDelta = dt.timedelta(days=1)
t0 = dt.datetime(2015, 12, 31, 16, 0, 0, 0)
t = [t0 + timeDelta * j for j in range(len(y))]
tlims = [np.min(t),np.max(t)]
fig = plt.figure()
ax1 = fig.add_subplot(2,1,1)
ax1.plot(t, y,'o-')
ax1.set_xlim([tlims[0],tlims[1]])
ax1.set_xscale('adaptivetime',doLabelTicks=False,doLabelAx=False,maxTicks=10)
ax1.set_ylabel('y')
ax2 = fig.add_subplot(2,1,2)
ax2.plot(t, y,'o-')
ax2.set_xlim([tlims[0],tlims[1]])
ax2.set_xscale('adaptivetime',timeZoneStr="UTC",maxTicks=10)
ax2.set_ylabel('y')
plt.show()

Internationalization--An example in French

If your computer is set up to work in a language other than English, most of the conversion to your language will be handled by your computer's operating system. You will need to set up a python dictionary object to enable AdaptiveTimeScale to create axis labels in your language, however. See the get_french_dictionary.py module (included with AdaptiveTimeScale) for an example of setting up such a dictionary object; adapt it to your own language and save it as get_german_dictionary.py, get_korean_dictionary.py, etc. The following code shows how this dictionary object is used to create French axis labels. Here the lines that are highlighted are those related to changing the language:

import AdaptiveTimeScale
import datetime as dt
import matplotlib.pyplot as plt
import locale
import get_french_dictionary
locale.setlocale(locale.LC_ALL,"fr_CA.ISO8859-1")
french_dictionary = get_french_dictionary.get_french_dictionary()
y = [1,2,3]
t = [dt.datetime(2015, 12, 31, 16, 0, 0),
dt.datetime(2015, 12, 31, 23, 0, 0), 
dt.datetime(2016, 1, 1, 4, 30, 0)]
fig, ax = plt.subplots()
ax.plot(t, y,'o-')
ax.set_xscale('adaptivetime',language_dictionary=french_dictionary)
plt.show()

The result is shown below:

French language example plot

But where can I get AdaptiveTimeScale.py?

I'm glad you asked. The source code is available at AdaptiveTimeScale.py's bitbucket repository