2025, Dec 13 06:01

Почему set_ylim в Shiny for Python не опускает ось y до нуля и что делать

Разбираем, почему в Shiny for Python + Matplotlib ось y в столбчатой диаграмме игнорирует set_ylim(bottom=0), и показываем рабочий способ исправить данные и оси.

Зафиксировать нулевую отметку по оси y в столбчатой диаграмме Matplotlib внутри Shiny for Python на первый взгляд просто: достаточно вызвать set_ylim(bottom=0). Однако иногда ось упрямо начинается с первого значения, например 4.1, и игнорирует ваши границы. Обычно это признак того, что график получает данные не в том виде, в каком вы ожидаете.

Проблема: ось y не начинается с нуля

Ниже приведён минимальный пример на Shiny Express, в котором проявляется эта ситуация. Диаграмма строится, но ось y стартует примерно с 4.1, а set_ylim(bottom=0) визуально ничего не меняет.

from shiny.express import input, render, ui
import matplotlib.pyplot as plt
import numpy as np
series_map = {
    "Maturity": ["1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y"],
    "Yield": [4.1, 4.3, 4.5, 4.7, 4.8, 4.9, 5.0, 5.1],
}
bundle = np.array([series_map["Maturity"], series_map["Yield"]])
print(bundle[1])
def make_bars():
    x_vals = bundle[0]
    y_vals = bundle[1]
    fig, ax = plt.subplots()
    ax.bar(x_vals, y_vals)
    ax.set_xlabel("Maturity")
    ax.yaxis.set_label_text("Yield (%)")
    ax.set_ylim(bottom=0)
    return fig
@render.plot
def show_chart():
    return make_bars()

Почему кажется, что set_ylim игнорируется

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

Решение: избегайте преобразования в массив

Оставьте структуру данных простой и передавайте в Matplotlib подписи по x и числовые значения по y напрямую. На практике отказ от объединения в массив устраняет проблему с осями.

from shiny.express import render
import matplotlib.pyplot as plt
curve = {
    "1Y": 4.1, "2Y": 4.3, "3Y": 4.5, "4Y": 4.7,
    "5Y": 4.8, "6Y": 4.9, "7Y": 5.0, "8Y": 5.1,
}
@render.plot
def draw_bars():
    cats = list(curve.keys())
    vals = list(curve.values())
    fig, ax = plt.subplots()
    ax.bar(cats, vals)
    ax.set_xlabel("Maturity")
    ax.yaxis.set_label_text("Yield (%)")
    ax.set_ylim(bottom=0)
    return fig

Почему это важно

В реактивных дашбордах даже небольшие преобразования данных могут незаметно изменить то, как библиотеки построения графиков интерпретируют входные значения. Как только структура перестаёт быть простой парой «подписи + числовой ряд», операции с осями могут вести себя не так, как вы рассчитываете. Сохраняйте предсказуемость пайплайна — это самый простой способ гарантировать, что настройки графика, вроде границ по оси y, применяются стабильно.

Выводы

Если set_ylim(bottom=0) не опускает базовую линию к нулю в столбчатой диаграмме Shiny for Python + Matplotlib, проверьте путь данных. Передавайте в Matplotlib обычные списки: категориальные подписи по x и числовые значения по y, не сворачивайте их в единый массив. Этот небольшой шаг возвращает оси ожидаемое поведение и делает график корректным.