Проблема в том, что в Питоне потоки немножко увечные (ключевое слово GIL), а потому реально работают только в двух случаях:
1. Исполняемый длительный код написан не на питоне, а принадлежит одному из бинарных модулей
2. Исполняемый код большую часть времени ждёт (например, операции ввода/вывода).
В случае с многопроцессностью проблем меньше, но появляетя проблема обмена данными между процессами.
Я бы запустил несколько процессов воркеров, которые умеют рендерить предоставленные данные и возвращать график как массив байт, содержащий изображение. Тогда основной бот кидает задание в некую очередь, один из воркеров просыпается, рендерит задание, и кладёт ответ в другую очередь. Словом, паттерн поставщик-потребитель. Конечно, могут быть проблемы с тем, чтобы подружить multiprocessing.Queue с асинхронным кодом, но имхо так всё равно изящнее.
Более того, если искомые данные лежат в БД или ином внешнем источнике - можно нагрузить воркеров их извлечением. Тогда задание будет содержать в себе только критерии выборки данных.