Gnuplot:基于项目ID生成随机但确定的调色板解决颜色重复
问题描述
我用Gnuplot生成了堆叠柱状图,数据和代码如下。图表效果没问题,但颜色重复得太早(前四种颜色会出现两次)。我希望基于项目ID生成随机但固定的颜色,避免颜色随时间变化,同时要保持实现的通用性,不想手动逐个设置颜色,该怎么改?
数据
id,title,alice,bob,charly,diana,eleanor foo1,Foo1 Project,,,,, foo2,Foo2 Project,,22,,, foo3,Foo3 Project,18,4,,10, bar1,Bar One,,,4,4,15, bar2,Bar Two,,,,2, bar3,Bar Three,,,,, baz1,First Baz,4,6,10,7, baz3,Second Baz,,3,,, baz3,Third Baz,2,,6,2,2, quux1,Quux the 1st,4,6,6,1, quux2,Quux the 2nd,,,8,,10, quux3,Quux the 3rd,,,2,4,
原Gnuplot代码
csvfile = 'wochenvorschau/alle.csv' set datafile separator ',' set output 'output/persons.png' set terminal png size 1000,600 set term png font "sans" set style data histograms set style histogram columnstacked set style fill solid 0.7 noborder set boxwidth 0.75 set xtics rotate by 90 right set grid ytics linestyle 0 set key outside set xlabel "Person" set ylabel "Arbeitsstunden" set timestamp "Stand: %d.%m.%Y %H:%M" bottom stats csvfile using 0 nooutput colmax = STATS_columns rowmax = STATS_records plot for [COL=3:colmax] csvfile using COL title columnhead, \ for [ROW=1:rowmax-1] '' every ::ROW::ROW using (t=strcol(2),NaN) with boxes lc ROW title t
解决方案
核心思路是基于项目ID的字符串生成固定哈希值,再把哈希值映射到RGB颜色空间,这样每个项目ID对应唯一且固定的颜色,不会重复,也不用手动配置。
1. 实现字符串哈希函数
Gnuplot没有内置字符串哈希,可通过遍历字符计算简单哈希,保证相同字符串输出相同整数:
# 字符串哈希函数:将输入字符串转为固定整数 str_hash(s) = sum [i=1:strlen(s)] (char(s[i]) * 256**(i%4))
2. 哈希值转RGB颜色
把哈希值映射到0-255的RGB范围,确保颜色差异明显:
# 哈希值转RGB三元组,s为项目ID字符串 hash_to_rgb(s) = (h=str_hash(s), \ r=int(h % 256), \ g=int((h/256) % 256), \ b=int((h/65536) % 256), \ rgb(r,g,b))
3. 修改绘图代码,绑定项目ID到颜色
原代码用lc ROW按行号取颜色,现在改为用项目ID的哈希颜色,同时用数组存储项目信息避免重复读取文件:
完整修改后的代码:
csvfile = 'wochenvorschau/alle.csv' set datafile separator ',' set output 'output/persons.png' set terminal png size 1000,600 set term png font "sans" set style data histograms set style histogram columnstacked set style fill solid 0.7 noborder set boxwidth 0.75 set xtics rotate by 90 right set grid ytics linestyle 0 set key outside set xlabel "Person" set ylabel "Arbeitsstunden" set timestamp "Stand: %d.%m.%Y %H:%M" bottom # 定义字符串哈希函数 str_hash(s) = sum [i=1:strlen(s)] (char(s[i]) * 256**(i%4)) # 哈希转RGB颜色 hash_to_rgb(s) = (h=str_hash(s), r=int(h%256), g=int((h/256)%256), b=int((h/65536)%256), rgb(r,g,b)) # 读取所有项目ID和标题,存储到数组 stats csvfile using 0 nooutput colmax = STATS_columns rowmax = STATS_records # 初始化数组存储项目ID和标题 array project_ids[rowmax-1] array project_titles[rowmax-1] do for [ROW=2:rowmax] { # 跳过表头行 project_ids[ROW-1] = strcol(1) project_titles[ROW-1] = strcol(2) } # 绘图:为每个项目绑定对应ID生成的颜色 plot for [COL=3:colmax] csvfile using COL title columnhead, \ for [ROW=1:rowmax-1] '' every ::ROW+1::ROW+1 using (NaN) with boxes lc hash_to_rgb(project_ids[ROW]) title project_titles[ROW]
关键修改说明
- 新增哈希与颜色转换函数,确保每个项目ID对应唯一固定颜色
- 用数组存储项目ID和标题,避免重复读取文件
- 替换
lc ROW为lc hash_to_rgb(project_ids[ROW]),用项目ID哈希颜色替代行号颜色
修改后,项目颜色由ID决定,不会随运行时间或数据顺序变化,无需手动配置颜色映射,通用性强。
内容的提问来源于stack exchange,提问作者memowe
相关产品推荐
相关产品推荐

