使用Bokeh绘制CSV数据多线图求助(Python 2.7环境)
解决Bokeh multi_line绘制CSV数据的问题
嘿,我来帮你搞定这个Bokeh multi_line绘图的问题!结合你的Python 2.7.14和Bokeh 0.12.13环境,我整理了一套可行的方案,还会帮你排查可能踩的坑:
完整可运行代码示例
首先,我们用pandas来处理CSV数据(Python2.7也能正常使用pandas),代码如下:
import pandas as pd from bokeh.plotting import figure, show, output_file from bokeh.models import ColumnDataSource # 1. 读取并预处理CSV数据 # 注意Python2.7的编码问题,若CSV含中文可换成encoding='gbk' df = pd.read_csv('data.csv', encoding='utf-8') # 将time列转为datetime类型,Bokeh才能正确渲染时间轴 df['time'] = pd.to_datetime(df['time']) # 2. 按Id分组整理multi_line需要的数据格式 grouped = df.groupby('Id') # multi_line要求xs和ys是「列表的列表」,每个子列表对应一条线的x/y数据 xs = [] ys = [] line_labels = [] for id_, group in grouped: # 添加当前Id的上行字节曲线数据 xs.append(group['time'].tolist()) ys.append(group['upbyte'].tolist()) line_labels.append("ID {} - 上行字节".format(id_)) # 添加当前Id的下行字节曲线数据 xs.append(group['time'].tolist()) ys.append(group['downbyte'].tolist()) line_labels.append("ID {} - 下行字节".format(id_)) # 3. 创建数据源并绘制图表 source = ColumnDataSource(data=dict( xs=xs, ys=ys, labels=line_labels )) # 初始化绘图对象,指定x轴为时间类型 p = figure(x_axis_type="datetime", title="各ID上下行字节流量趋势", x_axis_label='时间', y_axis_label='字节数') # 调用multi_line绘制所有曲线 p.multi_line(xs='xs', ys='ys', source=source, legend='labels', line_width=2) # 输出到HTML文件并在浏览器打开 output_file('byte_traffic.html') show(p)
关键注意事项(你之前失败可能踩的坑)
- 时间格式必须正确:如果
time列是字符串类型,Bokeh无法识别为时间轴,必须用pd.to_datetime()转成datetime对象 - multi_line的数据格式要求:
xs和ys必须是列表嵌套列表,每个子列表对应一条独立曲线的x/y数据,不能直接传单列数据 - Python2.7字符串格式化:别用Python3.6+的f-string,必须用
.format()方法来拼接字符串 - 编码问题:如果读取CSV时出现乱码,调整
encoding参数(比如gbk、utf-8-sig)
不用pandas的替代方案(纯csv模块)
如果你不想用pandas,也可以用Python内置的csv模块处理数据:
import csv from datetime import datetime from bokeh.plotting import figure, show, output_file # 读取CSV并按Id分组 data = {} with open('data.csv', 'rb') as f: reader = csv.DictReader(f) for row in reader: id_ = row['Id'] # 手动将时间字符串转为datetime对象,替换成你的实际时间格式 time_ = datetime.strptime(row['time'], "%Y-%m-%d %H:%M:%S") upbyte = float(row['upbyte']) downbyte = float(row['downbyte']) if id_ not in data: data[id_] = {'times': [], 'upbytes': [], 'downbytes': []} data[id_]['times'].append(time_) data[id_]['upbytes'].append(upbyte) data[id_]['downbytes'].append(downbyte) # 整理multi_line需要的xs/ys数据 xs = [] ys = [] line_labels = [] for id_ in data: xs.append(data[id_]['times']) ys.append(data[id_]['upbytes']) line_labels.append("ID {} - 上行字节".format(id_)) xs.append(data[id_]['times']) ys.append(data[id_]['downbytes']) line_labels.append("ID {} - 下行字节".format(id_)) # 绘图部分和之前一致 p = figure(x_axis_type="datetime", title="各ID上下行字节流量趋势", x_axis_label='时间', y_axis_label='字节数') p.multi_line(xs=xs, ys=ys, legend=line_labels, line_width=2) output_file('byte_traffic.html') show(p)
内容的提问来源于stack exchange,提问作者ME_sociaty
相关产品推荐
相关产品推荐

