Добавление дат на график временного ряда в MATLAB

При работе с временными рядами часто требуется их визуализировать. Однако, для того, чтобы отложить по оси Х даты нужно немного специальных навыков работы с датами. Начнём мы с более старого сценария работы, который до сих пор может быть актуален, если у вас версия матлаба старее 2014 года. Также полезно будет его изучить, если вы будете разбираться в старых кодах.

Итак, наиболее классическим является вариант представления даты в виде, так называемого, serial date number. Например, 14 октября 1992 года в этой сиситеме будет равняться 727851:

datenum(1992, 10, 14)

ans =

      727851

Не сложно догадаться, что функция datenum как раз таки и переводит "человеческую" дату в этот формат. Само число при этом (в нашем случае число 727851) - это количество дней прошедших с первого января нулевого года ('Jan-1-0000 00:00:00').

Вообще говоря, вышеупомянутое обращение к функции datenum - не единственно возможное. Можно, например, так:

datenum('12-jun-17','dd-mmm-yy')

ans =

      736858

Аргумент 'dd-mmm-yy' даёт матлабу пояснение - в каком виде представлена наша дата. Видов этих может быть много, так год можно представить из четырёх цифр (yyyy) или из двух (yy), месяц записать полностью буквами (mmmm), трёхбуквенным сокращением (mmm), двумя цифрами (mm) или одной буквой (m) и т.д. Полный список вариантов можно найти в хэлпе к функции datenum. Иными словами, вы можете собирать дату как конструктор, главное рассказать матлабу, что вы имеете ввиду, например:

datenum('12--:06_+2017','dd--:mm_+yyyy')

ans =

      736858

Ну и на всякий случай скажем, что если вы хотите перевести дату обратно к текстовому виду, то сделать это можно так:

datestr(728447)

ans =

    '02-Jun-1994'

а если к раскидать дату в виде чисел и записать в матрицу, то так:

datevec(728447)

ans =

        1994           6           2           0           0           0

Давайте попробуем с этим поработать на конкретном примере. Для этого скачаем данные с ежемесячными значениями индекса NAO с сайта noaa, а именно Monthly mean NAO index since January 1950 - Ascii format for downloading.

Загрузим скачанные данные в MATLAB:

nao = load('norm.nao.monthly.b5001.current.ascii');
Первый столбец - годы, второй - месяцы, третий - значения индекса NAO

Сам временной ряд выглядит так:

plot (nao(:,3))

И для того, чтобы по оси Х отображались даты, первое, что приходит в голову - скормить функции plot вектор с годами.

plot (nao(:,1),nao(:,3))

Как видите, ничего хорошего из этого не вышло. Значит будем помещать на график даты другим путём. И для начала используем именно datenum.

Поскольку данные у нас ежемесячные, то столбца с днями у нас нет, однако datenum требует указывать дату с точностью до дня. Поэтому будем указывать середину месяца (15 число).

datenum(nao(1,1),nao(1,2),15)

ans =

      712238

Так мы получили дату в маталбовском формате для первого измерения. Мы можем, конечно последовательно рассчитать это для каждой строки матрицы или создать цикл, но datenum прекрасно работает с векторами (даже в перемешку со скалярами), поэтому:

d = datenum(nao(:,1), nao(:,2), 15);

Теперь нужно указать наш вектор с датами в функции plot:

plot (d,nao(:,3))

Как видно на рисунке, MATLAB не знает, что наши числа - означают матлабовские даты, поэтому просто откладывает эти числа по оси Х. Однако это легко исправить, запустив функцию dateteick:

datetick('x','YYYY')

где 'x' - ось, с которой мы будем работать, а 'YYYY' - формат записи даты (само собой, вы можете указать какой угодно, например 'dd-mmm-yyyy', 'mm/dd/yy', 'mmmyy' и т.п.).  В результате получаем такую картинку:

В 2014 году в MATLAB ввели новый формат переменных - datetime. Он имеет много возможностей и вероятно заметки на эту тему ещё будут на нашем сайте. Пока же ограничимся нашей задачей. Создать вектор со значениями в формате datetime очень просто и аналогично тому, как мы это делали с datenum. С построением тоже сложностей не должно возникнуть:

d_new = datetime(nao(:,1),nao(:,2),15);
plot (d_new,nao(:,3))

Если вы захотите изменить формат отображения чисел, то можно использовать xtickformat:

xtickformat('yyyy-mm')

Как видно, оба рассмотренных нами способа достаточно простые, но по всей видимости datetime в современных версиях MATLAB более предпочтителен, на нём уже завязаны многие обновлённые функции, а будет завязано ещё больше.  Если же у вас уже даты представлены в формате datenum, то перевести его в datetime не сложно:

d_new2 = datetime(d,'ConvertFrom','datenum');
 telegram

Чтобы не пропустить новые материалы с рецептами по работе с океанологическими данными, подпишитесь на канал в Telegram: https://t.me/koldunovaleksey