Убираем пустое пространство вокруг карты в MATLAB

Сегодня мы, может быть и не изящным образом, но избавимся от пустого пространства, которое возникает при построении карт в MATLAB.

Для начала посмотрим на проблему. Сделаем простейшее построение карты в MATLAB:

worldmap([50 70],[-20 20])

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

Теперь попробуем немного усугубить ситуацию:

worldmap([50 70],[-60 20])

И вот мы видим MATLAB во всей своей красе. Автоматика при построении карт работает отвратительно и уже много лет MATLAB не хочет с этим ничего делать. Во-первых, значения долгот неприлично близко расположены друг к другу, но давайте это сразу поправим:

worldmap([50 70],[-60 20])
setm(gca, 'mlabellocation',[-60:10:20])

Ну и во-вторых, белого пустого пространства теперь слишком много. Часто проблема решается, если вы мышкой схватите окно с картинкой за край и начнёте менять его размер вручную, однако это не всегда приводит к хорошему результату.

Когда вы имеете дело с простыми графиками в MATLAB, то пустое пространство достаточно просто ликвидировать автоматически и на официальном сайте есть инструкция, как это сделать: Save Plot with Minimal White Space. Отдельную функцию им было сделать, видимо, лень. Если вдруг ссылка устарела, продублирую решение здесь. Достаточно запустить (после построения вашей картинки) следующий код:

ax = gca;
outerpos = ax.OuterPosition;
ti = ax.TightInset; 
left = outerpos(1) + ti(1);
bottom = outerpos(2) + ti(2);
ax_width = outerpos(3) - ti(1) - ti(3);
ax_height = outerpos(4) - ti(2) - ti(4);
ax.Position = [left bottom ax_width ax_height];

Здесь OuterPosition - позиция полной картинки (окна, в котором построена диаграма, карта и т.п.) вместе с любыми пустыми пространствами, Position - размер построенной вами диаграммы (без подписей к осям), а TightInset - это границы вместе с подписями к осям.

Проблема заключается в том, что с нашей картой такое не прокатит. Т.е. если вы запустите вышеупомянутый код, то получите вот что (срежите все крайние значения долгот и не избавитесь полностью от пустого пространства сверху и снизу):

Насколько я понял, корень проблемы заключается в том, что параметр TightInset, который по идее должен выдавать информацию о том, какой размер занимают подписи к осям, неадекватно работает при построении карт или вообще такого понятия в mapping toolbox нет.

Скажу честно, на данный момент, я не знаю хорошего решения этой проблемы, если я его найду, то обязательно напишу об этом отдельную заметку. Ну а пока выдам простой и тупой, но рабочий вариант.

Для начала сделаем несколько манипуляций, которые помогут понять дальнейшие действия. Получим информацию об окне, в котором появилась ваша только что построенная картинка.

fi= gcf;
fi.Position

fi.Position =

   440   378   560   420

Эти цифры будут зависеть он разрешения экрана. Эсли вы взьмёте окно с картинкой и начнёте двигать его в разные стороны, то будут меняться перые две цифры (это координаты нижнего левого угла окна и отсчитываются они от нижнего левого угла экрана, первое число (440) - растояние от этого угла экрана в пикселях по горизонтали, а второе (378) - по вертикали). Если вы начнёте менять размеры окна с картинкой, то будут меняться вторые две цифры (это ширина (560) и высота (420) окна всё в тех же пикселях). Т.е. полный размер вашего окна с какртинкой 560х420 пикселей.

Теперь получим информацию об осях карты, т.е. позиция этих осей внутри нашего окна fi. Заметьте, что для единообразия мы перевели единицы измерения в пиксели (ax.Units='pixels')ведь по умолчанию они исчисляются в условных еденицах:

ax = gca;
ax.Units='pixels';
ax.OuterPosition
ax.OuterPosition =

     1     1   560   420

ax.Position
ax.Position =

   73.8000   47.2000  434.0000  342.3000

Обратите внимание, что ax.OuterPosition очень похоже на размер нашего окна в пикселях (560х420), несложно догадаться, что OuterPosition определяет полные границы наших осей в координатах, в которых ноль расположен в левом нижнем углу нашего окна с картинкой, а не в углу экрана (как это было с параметром fi.Position) . На самом деле ax.OuterPosition я привёл для наглядности и далее мы его использовать не будем. Нам важнее параметр ax.Position, который определяет границы нашей карты без подписей и прочего пространства вокруг и начало координат также имеет в углу окна с картинкой, а не в углу экрана. Т.е. если мы выставим ax.Position=[1 1 560 420] или, что по сути одно и то же:

ax.Position=ax.OuterPosition

то получится такая карта:

Ну и теперь, как я уже говорил, я могу пока только посоветовать подбирать значения, для того, чтобы избавиться от лишнего белого пустого пространства. У меня после подбора получились такие значения (т.е. нижеописынными командами мы и задаём новые значения расположения осей и окна):

fi.Position = [440 378 629 350]
ax.Position = [40 -30 560 420]

Обратите внимание, что в fi.Position я изменил только последние два значения (было [440 378 560 420], стало [440 378 629 350]), отвечающие за ширину и высоту окна. Оставив неизменными первые два значения я оставил левые нижний край окна в том же месте, где он был изначально, т.е. смысла двигать окно с картинкой в разные стороны по экрану не было никакого. В ax.Position третье и четвёртое значение я решил выставить на 560 и 420, для того чтобы пропорции исходной картинки не изменились и дальше их не менял, играясь только с первыми двумя значениями, отвечающими за положение левого нижнего угла (и да получилось так, что начало оси пришлось вынести за начало координат (-30)). Вот что в итоге получилось:

 telegram

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