2025, Dec 11 03:00
How to Bold Only Specific Labels in a Plotly Scatter Plot Using Inline HTML (Python)
Learn how to make only selected labels bold in a Plotly scatter plot using inline HTML. Python example, no extra traces, clean per-point text styling.
Making a handful of labels bold in a Plotly scatter plot looks like a trivial UI tweak, yet the straightforward styling API applies to an entire trace, not to individual points. If you try to pass a per-row font style in the data, nothing happens. Fortunately, Plotly supports a small subset of HTML inside text fields, which gives you a precise and reliable way to bold specific labels only.
Problem setup
The following code draws a scatter plot with labels, sizes, colors, and custom axes. The goal is to make only three labels bold, while keeping the rest normal-weight.
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()
What’s really going on
Text styling passed via the trace, such as size, family, and color, is applied uniformly to all points in that trace. In other words, there’s no built-in per-point font-weight switch in this setup. However, Plotly text fields accept a limited set of HTML, which allows inline markup directly inside the label strings.
Chart Studio uses a subset of HTML tags to do things like newline (<br>), bold (<b></b>), italics (<i></i>), and hyperlinks (<a href=’…’></a>). Tags <em>, <sup>, and <sub> are also supported.
This subset works in Plotly text content, so wrapping just a few labels with <b>…</b> achieves the desired effect.
Solution: inline HTML for selective bold
The simplest fix is to preprocess the labels and embed <b>…</b> around those you want in bold. Below, the labels are updated before building the DataFrame by pairing each value with its “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()
This keeps all styling logic intact while selectively bolding only the intended labels.
Why you want this in your toolbox
Per-point text emphasis helps direct attention without fragmenting your data into multiple traces or post-processing the figure. Inline HTML is minimal, explicit, and easy to audit in code reviews. It also avoids changing the chart’s structure or legend, which keeps downstream integrations simpler.
Conclusion
When you need selective emphasis for text in Plotly, inject a supported HTML tag directly into the label strings. It’s a small change with a big payoff: precise control over emphasis, unchanged plotting logic, and results that stay faithful to your data. Use this approach for bold, italics, superscripts, subscripts, and keep the rest of the styling trace-wide.