使用Plotly Python的go.Box绘制箱线图仅显示水平线问题求助
解决Plotly go.Box绘制分类箱线图仅显示水平线的问题
问题描述
使用Plotly的go.Box按分类变量绘制箱线图时,图表仅显示一条水平线,但使用px.express绘制相同数据则无此问题。以下是最小可复现示例(MRE):
多列循环绘图代码
import numpy as np import pandas as pd import plotly.graph_objects as go from itertools import cycle color_iter = cycle(['#1f77b4', '#ff7f0e', '#2ca02c']) fares = [np.random.random() for g in np.arange(10000)] types = ["new", "new", "old", "old", "really_old"] * 2000 df = pd.DataFrame({ "bus_fares": fares, "bus_types": types }) traces = [] for k in df["bus_types"].unique(): trace = go.Box( x = [k], y = df[df["bus_types"]==k]["bus_fares"], marker={"color": next(color_iter)}, name="bus_types", showlegend=False ) traces.append(trace) go.Figure(traces).show()
单个箱线图简化代码
x = "bus_types" y = "bus_fares" k = "old" go.Figure(go.Box(x=[k], y=df[df[x]==k][y].values, name=x, showlegend=False)).show()
问题原因
问题出在x参数的设置:你给go.Box的x传入了长度为1的列表[k],但go.Box要求x的长度必须和y的长度完全匹配,这样才能将每个y值映射到对应的分类标签上。当长度不匹配时,Plotly无法正确解析数据,最终只显示一条水平线。
而px.express作为高层API,会自动处理数据的映射关系,无需手动保证x和y的长度一致,因此不会出现这个问题。
解决方法
只需要让x参数的长度和y保持一致即可,有两种简洁的实现方式:
方法1:构造与y长度相同的分类列表
修改循环中的x参数为:
x = [k] * len(df[df["bus_types"]==k]["bus_fares"])
方法2:直接传入对应的分类列子集
更推荐这种方式,直接从DataFrame中提取对应分类的bus_types列,长度自然与y匹配:
x = df[df["bus_types"]==k]["bus_types"]
修改后的完整循环代码示例
import numpy as np import pandas as pd import plotly.graph_objects as go from itertools import cycle color_iter = cycle(['#1f77b4', '#ff7f0e', '#2ca02c']) fares = [np.random.random() for g in np.arange(10000)] types = ["new", "new", "old", "old", "really_old"] * 2000 df = pd.DataFrame({ "bus_fares": fares, "bus_types": types }) traces = [] for k in df["bus_types"].unique(): subset = df[df["bus_types"]==k] trace = go.Box( x = subset["bus_types"], # 直接传入对应分类列 y = subset["bus_fares"], marker={"color": next(color_iter)}, name=k, # 设置name为分类值,方便区分(可选) showlegend=False ) traces.append(trace) go.Figure(traces).show()
修改后的单个箱线图代码示例
x_col = "bus_types" y_col = "bus_fares" k = "old" subset = df[df[x_col]==k] go.Figure(go.Box( x = subset[x_col], y = subset[y_col].values, name=k, showlegend=False )).show()
修改后即可正常显示完整的箱线图,包含中位数、四分位数、须线等元素。
内容的提问来源于stack exchange,提问作者plotmaster473
相关产品推荐
相关产品推荐

