2025, Dec 31 03:02

Выборочное жирное начертание подписей в Plotly через HTML-теги

Как сделать часть подписей жирными в Plotly для точечной диаграммы: используем HTML-теги без дробления трасс. Простой пример кода на Python. С пояснениями.

Сделать несколько подписей жирными в точечной диаграмме Plotly кажется простой доработкой интерфейса, но базовый API оформления применяет настройки ко всей трассе, а не к отдельным точкам. Если попытаться передать стиль шрифта построчно в данных, ничего не произойдет. К счастью, Plotly поддерживает небольшой поднабор HTML внутри текстовых полей, что позволяет точно и надежно выделять жирным только нужные подписи.

Постановка задачи

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

import plotly.express as px
import pandas as pd
payload = {
    "label_txt": ["test 98lop1", "test9665 opp1", "test QSDFR1", "test ABBE1", "testtest21", "test23"],
    "xv": [12.6, 10.8, -1, -15.2, -10.4, 1.6],
    "yv": [15, 5, 44, -11, -35, -19],
    "bubble_s": [375, 112.5, 60, 210, 202.5, 195],
    "hue": ["green", "green", "green", "red", "red", "red"],
    "weight_flag": ["normal", "normal", "normal", "bold", "bold", "bold"],
}
frame = pd.DataFrame(payload)
chart = px.scatter(
    frame,
    x="xv",
    y="yv",
    color="hue",
    size="bubble_s",
    text="label_txt",
    hover_name="label_txt",
    color_discrete_map={"red": "red", "green": "green"},
    title="chart",
)
chart.update_traces(
    textposition="middle right",
    textfont_size=14,
    textfont_color="black",
    textfont_family="Inter",
    hoverinfo="skip",
)
legend_names = {"red": "red title", "green": "green title"}
chart.update_layout(
    {
        "yaxis": {
            "range": [-200, 200],
            "zerolinewidth": 2,
            "zerolinecolor": "red",
            "tick0": -200,
            "dtick": 45,
        },
        "xaxis": {
            "range": [-200, 200],
            "zerolinewidth": 2,
            "zerolinecolor": "gray",
            "tick0": -200,
            "dtick": 45,
        },
        "height": 800,
    }
)
chart.add_scatter(
    x=[0, 0, -200, -200],
    y=[0, 200, 200, 0],
    fill="toself",
    fillcolor="gray",
    zorder=-1,
    mode="markers",
    marker_color="rgba(0,0,0,0)",
    showlegend=False,
    hoverinfo="skip",
)
chart.add_scatter(
    x=[0, 0, 200, 200],
    y=[0, -200, -200, 0],
    fill="toself",
    fillcolor="yellow",
    zorder=-1,
    mode="markers",
    marker_color="rgba(0,0,0,0)",
    showlegend=False,
    hoverinfo="skip",
)
chart.update_layout(paper_bgcolor="#F1F2F6")
chart.show()

Что происходит на самом деле

Оформление текста, переданное на уровне трассы — размер, гарнитура, цвет — применяется одинаково ко всем точкам этой трассы. Иными словами, отдельного переключателя font-weight для каждой точки здесь нет. Зато текстовые поля в Plotly принимают ограниченный набор HTML, позволяя вставлять встроенную разметку прямо в строки с подписями.

Chart Studio использует поднабор HTML-тегов для таких вещей, как перенос строки (<br>), жирное начертание (<b></b>), курсив (<i></i>) и гиперссылки (<a href=’…’></a>). Также поддерживаются теги <em>, <sup> и <sub>.

Этот поднабор работает и в текстовом содержимом Plotly, поэтому достаточно обернуть нужные подписи в <b>…</b>, чтобы получить желаемый результат.

Решение: встроенный HTML для выборочного жирного начертания

Самый простой прием — предварительно обработать подписи и обернуть <b>…</b> вокруг тех, что нужно выделить. Ниже подписи преобразуются перед созданием DataFrame, сопоставляя каждое значение с его “weight_flag”.

import plotly.express as px
import pandas as pd
payload = {
    "label_txt": ["test 98lop1", "test9665 opp1", "test QSDFR1", "test ABBE1", "testtest21", "test23"],
    "xv": [12.6, 10.8, -1, -15.2, -10.4, 1.6],
    "yv": [15, 5, 44, -11, -35, -19],
    "bubble_s": [375, 112.5, 60, 210, 202.5, 195],
    "hue": ["green", "green", "green", "red", "red", "red"],
    "weight_flag": ["normal", "normal", "normal", "bold", "bold", "bold"],
}
payload["label_txt"] = [
    (f"{txt}" if w == "bold" else txt)
    for txt, w in zip(payload["label_txt"], payload["weight_flag"])
]
frame = pd.DataFrame(payload)
chart = px.scatter(
    frame,
    x="xv",
    y="yv",
    color="hue",
    size="bubble_s",
    text="label_txt",
    hover_name="label_txt",
    color_discrete_map={"red": "red", "green": "green"},
    title="chart",
)
chart.update_traces(
    textposition="middle right",
    textfont_size=14,
    textfont_color="black",
    textfont_family="Inter",
    hoverinfo="skip",
)
legend_names = {"red": "red title", "green": "green title"}
chart.update_layout(
    {
        "yaxis": {
            "range": [-200, 200],
            "zerolinewidth": 2,
            "zerolinecolor": "red",
            "tick0": -200,
            "dtick": 45,
        },
        "xaxis": {
            "range": [-200, 200],
            "zerolinewidth": 2,
            "zerolinecolor": "gray",
            "tick0": -200,
            "dtick": 45,
        },
        "height": 800,
    }
)
chart.add_scatter(
    x=[0, 0, -200, -200],
    y=[0, 200, 200, 0],
    fill="toself",
    fillcolor="gray",
    zorder=-1,
    mode="markers",
    marker_color="rgba(0,0,0,0)",
    showlegend=False,
    hoverinfo="skip",
)
chart.add_scatter(
    x=[0, 0, 200, 200],
    y=[0, -200, -200, 0],
    fill="toself",
    fillcolor="yellow",
    zorder=-1,
    mode="markers",
    marker_color="rgba(0,0,0,0)",
    showlegend=False,
    hoverinfo="skip",
)
chart.update_layout(paper_bgcolor="#F1F2F6")
chart.show()

Так сохраняется вся логика оформления, а жирным становятся только нужные элементы.

Зачем это держать под рукой

Выделение текста на уровне отдельных точек помогает направлять внимание без дробления данных на несколько трасс и без постобработки фигуры. Встроенный HTML — решение минималистичное, явное и удобное для ревью кода. К тому же оно не меняет структуру графика и легенду, что упрощает последующие интеграции.

Вывод

Когда требуется выборочно выделить текст в Plotly, вставляйте поддерживаемые HTML‑теги прямо в строки подписей. Это небольшое изменение дает большой выигрыш: точный контроль над акцентами, неизменная логика построения и результат, который остается верным данным. Подход подходит для жирного, курсива, верхних и нижних индексов, а остальное оформление оставляйте на уровне трассы.