Сегодня я хочу рассказать о том, как я писал отчеты на R, с чем сталкивался и как решал проблемы, которые возникали по ходу разработки. Отчеты были в формате PDF и запускались из Python в Camunda.  Первое, с чем пришлось столкнуться - это желание заказчика запускать генерацию отчетов на R из Python. Точнее из Python запускали subprocess.Popen, который запускал R script. R script, в свою очередь, запускал одну из функций генерации того или иного отчета, которая была частью нашего проекта, написанного как пакет на R. Разницу между пакетом и обычными скриптами на R я описал тут - ссылка. Можно сразу дергать функции R и мой коллега пытался переписать вызов отчетов из Python, но то ли из-за проблем с окружением на сервере, то ли из-за Camunda, в которой это все запускалось, такой способ отлично работал локально, но не работал на нашем боевом окружении. Минусом же вызова R через subprocess.Popen является то, что Python вызывает R скрипт через shell, а уже внутри этого скрипта дергается функция пакета R.  Параметры для отчета тоже приходится передавать через shell и уже в R script файле так же их читать как будь то их передают через командную строку.  Часть кода на Python:  Script на R, где ourpackage название нашего пакета: Возникает вопрос как это все тестировать и отлаживать. У нас часть кода на Python, а часть на R. Можно использовать JupiterHub, но наши администраторы настроили его так, что код на Python мы могли вызвать, а вот код на R нет. Мотив был - экономия памяти и ресурсов. В итоге тестировали через RStudio. В ней можно создать файл типа Python: И уже внутри этого файла вызвать функцию python, которая, в свою очередь, вызовет генерацию отчета на R.  Пример вызова: Чтобы проверить и отладить сам R script файл, его можно запустить из Terminal в RStudio. Для этого его вам придется положить внутрь вашего проекта, хотя бы на время теста и отладки. Можно держать его и вне проекта, если вам это позволяют настройки окружения, в котором вы работаете. У меня не было такой возможности, поэтому я размещал script файл в подпапке внутри R папки проекта, так как в пакет содержимое подпапок не попадает и, конечно же, не коммитил эту попдпапку в репозиторий. Команду запуска отчета через script надо писать в Terminal. Это вкладка на нижней панели в RStudio. Пример запуска из shell: В коде, для генерации отчетов, надо указать путь к RMD файлу, на основе которого будет строиться отчет. Пример функции, которая строит отчет ниже, при условии что RMD файл лежит в inst/reports: При сборке пакета часто можно увидеть сообщения типа: В этом сообщении говорится, что если явно для функции rotate не указать название библиотеки, то будет вызываться ggpubr::rotate. Это происходит из-за того, что в разных пакетах есть функции с одинаковыми именами. Чтобы эти сообщения не выводились можно указать какие функции из каких библиотек должны грузиться, а какие нет. У нас в проекте для этого в папке R был создан файл global_imports_pkg.R в котором прописывались именно те функции, которые нам нужны.  Но это потенциально может привести к другой, более коварной ошибке. Пусть у вас в  global_imports_pkg.R написанно так:  А в коде вы вызываете функцию dcast, которой нет в строчке выше. Есл вы запустите функцию из под RStudio, просто написав в консоли: У вас все будет работать, так как локально вы себе инсталлировали весь пакет data.table, а вот при попытке вызвать эту же функцию из Python, у вас будет ошибка, так как в проекте у вас написанно, что в наш пакет нужно подгрузить только 2 функции из data.table - это melt и rbindlist. Ту же ошибку вы можете получить на сервере, хотя локально все будет работать.  Похожее поведение можно так же получить, если забыть добавить используемый вами сторонний пакет в файл DESCRIPTION: При запкуске локально в RStudio все будет работать, так как вы явно установили этот пакет локально, но вот при вызове вашего пакета сторонним кодом или средой вы получите ошибку.  При генерации больших отчеов в PDF формате возникает ошибка, если посмотреть в терминале на процесс генерации шаблона, то видно как он отъедает всю доступную память и падает. Для решения этой проблемы мы резали отчет на части и потом их склеивали. Для этого использовали qpdf::pdf_combine. Проблема с утечкой памяти обсуждается как минимум тут. Какого-то более простого решения найти не получилось, хотя сил и времени было потраченно немало. Для форматирования pdf отчетов использовали Latex. Начальный шаблон для отчета был взят тут.  Код на R для генерации отчета с шаблоном Latex: Так же непосредственно в шапку RMD файла можно добавить команды для форматирования документа: Подробно команды Latex я не буду разбирать, так как достаточно посмотреть на код в тех или иных блоках и понять, как надо его поправить, чтобы изменить форматирование. Во многом я опирался на этот сайт когда форматировал документ. Можно так же гибко настроить какие ошибки и сообщения будут писаться в отчет. Это делается командой:  Можно эти настройки так же включать и отключать в шапке chunk: Для вызова вункций из внешних библиотек, написанных на Python  мы использовали reticulate.  Пример вызова внешней функции: Тест - заглушка для такой функции: При отладке кода есть возможность скопировать значения внутренних переменных в глобальную область памяти и напрямую вызвать нужную нам часть кода с определенными значениями переменных для этого кода.  На картинке выше в верхнем правом углу в поле Data есть переменная df. Чтобы скопировать её в глобальную область надо написать в Console: И выполнить эту команду - нажать ENTER. После этого можно выделить тот код который мы хотим протестировать с этой локальной переменной и запустить его - CTRL+ENTER. Дело в том, что отладка в RMD файле не работает и вся логика по возможности выносится в функции, которые находятся в файлах *.R. К этому ещё добавляется не высокая скорость генерации отчетов из RMD файла. В таких условиях каждый раз делать DEBUG не удобно. Работает все медленно и участки кода в RMD не отладить. А с установкой значений переменных в глобально области можно проверить любой участок кода, даже если он находится непосредственно в RMD файле. Мы использовали ReferenceClasses, решив, что они больше всего нам  подходят. Правда, их невозможно отладить инструментами RStudio. Но есть стандартные функции отладки, с помощью которых сама отладка возможна: Где s - это экземпляр класса, а class_method - это метод класса. Но он оказался не очень удобным и мы отлаживали с помощью переменных в глобальной области видимости. Библиотека для работы с данными для отчетов - dplyr; Чтобы создать список из входящих параметров функции использовали следующий код: Удалить параметры или параметр из глобального окружения можно с помощью команды rm; Статический анализатор кода - lintr; Для автоматической записи документации в Confluence использовали библиотеку conflr; Таблицы в отчетах делали с помощью felxtable. Это статья - памятка, в которой я описал ключевые вещи проекта, которые я не хотел бы забыть и которые, на мой взгляд, были бы полезны тем, кто работает с аналогичными проектами на языке R. Возможно что-то можно улучшить, а чего-то избежать, но не хотелось бы "Изобретать велосипед заново", начиная новый проект на R. В заключении хотел бы пожелать всем успехов, а также хороших и интересных проектов.  Программист