应用场景 #
在图形开发中,我们可能需要使用 JS 对传递过来的数据进行处理。
所有函数均可直接在图形的 JS 代码区中调用。
数据约定:本文所有示例均以如下标准二维数组为基础,第一行为表头,后续行为数据行:
dataset = [['category', 'C1', 'C2'], ['R1', 12, 18], ['R2', 10, 17]]
数据集转化 #
ds_transform(dataset)
#
行列转置:将二维数组的行与列互换,等同于矩阵转置。常用于坐标轴翻转展示。
result = ds_transform(dataset)
// 结果:
// [['category', 'R1', 'R2'],
// ['C1', 12, 10],
// ['C2', 18, 17]]
ds_createMap(dataset)
#
生成 key → [] 字典:将二维数组转换为以第一列值为 key、其余列组成数组为 value 的字典对象。常用于 ECharts 中按名称取系列数据。
result = ds_createMap(dataset)
// 结果:
// {
// "category": ["C1", "C2"],
// "R1": [12, 18],
// "R2": [10, 17]
// }
// 典型用法:取某一行的数值
let r1Data = result['R1'] // [12, 18]
ds_createMap_all(dataset)
#
生成对象数组:将二维数组转换为 [{列名1: 值, 列名2: 值, ...}, ...] 格式的对象数组(跳过第一行表头)。常用于饼图 data、ECharts dataset source,以及需要按字段名取值的场景。
result = ds_createMap_all(dataset)
// 结果:
// [
// {"category": "R1", "C1": 12, "C2": 18},
// {"category": "R2", "C1": 10, "C2": 17}
// ]
// 典型用法:饼图 data
let pieData = ds_createMap_all(dataset).map(item => ({name: item.category, value: item.C1}))
ds_mapToList(dataset)
#
对象数组还原为二维数组:将 ds_createMap_all 生成的对象数组还原回标准二维数组格式(表头 + 数据行)。常用于处理 MongoDB、Elasticsearch 等 NoSQL 数据源返回的数据。
let objList = [
{"category": "R1", "C1": 12, "C2": 18},
{"category": "R2", "C1": 10, "C2": 17}
]
result = ds_mapToList(objList)
// 结果:
// [['category', 'C1', 'C2'],
// ['R1', 12, 18],
// ['R2', 10, 17]]
ds_pivot(dataset, indexs=null, column=null, value=null)
#
数据透视(行转列):将"维度 … + 透视列 + 值"格式的明细数据透视为宽表。默认取最后两列作为透视列和值列,其余列作为行索引。
| 参数 | 说明 | 默认值 |
|---|---|---|
dataset |
原始二维数组(含表头) | — |
indexs |
行索引列的序号数组 | [0, 1, ..., n-3] |
column |
透视列的序号 | 倒数第二列 |
value |
值列的序号 | 最后一列 |
// 基本用法:两列(维度 + 值)自动透视
dataset3 = [['城市', '户型', '数量'],
['长沙', 'A', 35],
['上海', 'B', 19]]
result = ds_pivot(dataset3)
// 结果:
// [["城市", "A", "B"],
// ["长沙", 35, 0],
// ["上海", 0, 19]]
// 多维行索引透视
dataset4 = [['省份', '城市', '户型', '数量'],
['湖南', '长沙', 'A', 35],
['上海', '上海', 'B', 19]]
result = ds_pivot(dataset4)
// 结果:
// [["省份", "城市", "A", "B"],
// ["湖南", "长沙", 35, 0],
// ["上海", "上海", 0, 19]]
// 自定义索引列、透视列、值列
result = ds_pivot(dataset4, indexs=[1, 0], column=2, value=3)
// 结果:
// [["城市", "省份", "A", "B"],
// ["长沙", "湖南", 35, 0],
// ["上海", "上海", 0, 19]]
ds_tree(dataset, label='label', children='children')
#
生成树形结构:将"父节点、子节点"格式的二维数组转换为 ECharts tree/treemap 组件所需的嵌套树结构。支持通过 fatherName/childName 字段将编码与显示名称分离。
// 基础用法(直接用显示名称)
dataset = [["father", "child"],
["湖南", "长沙"],
["湖南", "郴州"],
["郴州", "安仁"],
["广东", "佛山"],
["广东", "广州"]]
result = ds_tree(dataset)
// 结果(简化):
// [
// {id:"湖南", label:"湖南", children:[
// {id:"长沙", label:"长沙"},
// {id:"郴州", label:"郴州", children:[
// {id:"安仁", label:"安仁"}
// ]}
// ]},
// {id:"广东", label:"广东", children:[...]}
// ]
// 进阶用法:避免同名歧义,SELECT father, child, fatherName, childName
dataset = [["father", "child", "fatherName", "childName"],
["A", "A1", "湖南", "长沙"],
["A", "A2", "湖南", "郴州"],
["A2", "A2A", "郴州", "安仁"],
["B", "B1", "广东", "佛山"],
["B", "B2", "广东", "广州"]]
result = ds_tree(dataset)
// 节点 id 为编码,label 为显示名称,不会因重名引起混淆
ds_distinct(a, b=[])
#
数组去重:对单个或两个数组合并后去重,返回无重复值的新数组。
// 单数组去重
result = ds_distinct(['A', 'B', 'A', 'C'])
// 结果:['A', 'B', 'C']
// 合并两个数组并去重
result = ds_distinct(['A', 'B'], ['B', 'C', 'D'])
// 结果:['A', 'B', 'C', 'D']
// 典型用法:获取某列的不重复值列表
let categories = ds_distinct(dataset.slice(1).map(row => row[0]))
ds_filter(dataset, fun)
#
数据集过滤:使用函数 fun 对数据行进行筛选,自动保留表头行。fun 接收每行数据,返回 true 保留,返回 false 过滤掉。
// 过滤第一列等于 'R1' 的行
result = ds_filter(dataset, item => item[0] === 'R1')
// 结果:
// [['category', 'C1', 'C2'],
// ['R1', 12, 18]]
// 过滤第二列大于 10 的行
result = ds_filter(dataset, item => item[1] > 10)
// 结果:
// [['category', 'C1', 'C2'],
// ['R1', 12, 18]]
// 多条件过滤
result = ds_filter(dataset, item => item[1] > 10 && item[2] < 20)
ds_sort(dataset, index=0, asc=true)
#
数据集排序:按指定列索引对数据行排序(保留表头),支持升序/降序,也支持传入自定义比较函数。
| 参数 | 说明 | 默认值 |
|---|---|---|
index |
排序列的序号,或自定义比较函数 | 0 |
asc |
true 升序,false 降序 |
true |
// 按第二列(序号1)升序排序
result = ds_sort(dataset, 1)
// 结果:
// [['category', 'C1', 'C2'],
// ['R2', 10, 17],
// ['R1', 12, 18]]
// 按第二列降序排序
result = ds_sort(dataset, 1, false)
// 结果:
// [['category', 'C1', 'C2'],
// ['R1', 12, 18],
// ['R2', 10, 17]]
// 使用自定义比较函数(按第三列降序)
result = ds_sort(dataset, (a, b) => b[2] - a[2])
ds_remove_column(dataset, remove_list=[0])
#
移除指定列:删除二维数组中指定序号的列,支持一次移除多列。
// 移除第一列(序号 0,即 category 列)
result = ds_remove_column(dataset, [0])
// 结果:
// [['C1', 'C2'],
// [ 12, 18],
// [ 10, 17]]
// 移除第一列和第三列
result = ds_remove_column(dataset, [0, 2])
// 结果:
// [['C1'],
// [ 12],
// [ 10]]
ds_split(data, sep=',', head_add=[])
#
拆分第一列:将第一列的字符串按分隔符拆分成多个字段,合并到数据集。如果传入 head_add 则使用指定表头,否则用 SQL 字段名(第一列表头)按分隔符拆分作为新表头。
// SQL 返回数据,第一列是逗号拼接的多字段
data = [['province,city', 'sales'],
['湖南,长沙', 100],
['广东,广州', 200]]
// 传入自定义表头
result = ds_split(data, ',', ['省份', '城市'])
// 结果:
// [['省份', '城市', 'sales'],
// ['湖南', '长沙', 100],
// ['广东', '广州', 200]]
// 不传表头,自动从第一列列名"province,city"拆分
result = ds_split(data, ',')
// 结果:
// [['province', 'city', 'sales'],
// ['湖南', '长沙', 100],
// ['广东', '广州', 200]]
ds_sumColumn(dataset, column)
#
列求和:对指定列(从第 1 行开始,跳过表头)所有数值求和,返回合计值。
// 对第二列(序号 1)求和
total = ds_sumColumn(dataset, 1)
// 结果:22 (12 + 10)
// 对第三列(序号 2)求和
total = ds_sumColumn(dataset, 2)
// 结果:35 (18 + 17)
ds_percentAcc(dataset, row)
#
累计占比行:对指定行(按行序号,从 0 开始含表头行)计算累计百分比,并在数据集末尾追加一行。常用于柏拉图(Pareto Chart)。
// 原始数据(先按数量降序排好)
dataset5 = [['品类', '数量'],
['A', 50],
['B', 30],
['C', 20]]
// 对第 1 行(数量行,序号 1)做累计占比
result = ds_percentAcc(dataset5, 1)
// 结果(在末尾追加累计占比行):
// [['品类', '数量'],
// ['A', 50],
// ['B', 30],
// ['C', 20],
// ['数量_acc', 0.5, 0.8, 1.0]]
数据集关联 #
ds_leftjoin(a, b, withhead=true, type=1)
#
左关联:按照两个数据集的第一列进行左连接,a 中所有行都保留,b 中无匹配的列填 0。
dataset2 = [['category', 'C3'],
['R1', 38],
['R6', 13]]
result = ds_leftjoin(dataset, dataset2)
// 结果:
// [['category', 'C1', 'C2', 'C3'],
// ['R1', 12, 18, 38],
// ['R2', 10, 17, 0]] // R2 在 b 中无匹配,C3 填 0
// 注意:R6 仅存在于 b 中,左连接不保留
ds_crossjoin(a, b, withhead=true)
#
交叉关联(内连接):只保留两个数据集第一列匹配的行,等同于 SQL 的 INNER JOIN。
result = ds_crossjoin(dataset, dataset2)
// 结果:
// [['category', 'C1', 'C2', 'C3'],
// ['R1', 12, 18, 38]] // 仅 R1 匹配
ds_fulljoin(a, b, withhead=true)
#
全外连接:保留两个数据集中所有行,无匹配处补 0,等同于 SQL 的 FULL OUTER JOIN。
result = ds_fulljoin(dataset, dataset2)
// 结果:
// [['category', 'C1', 'C2', 'C3'],
// ['R1', 12, 18, 38],
// ['R2', 10, 17, 0], // b 中无 R2,C3 补 0
// ['R6', 0, 0, 13]] // a 中无 R6,C1/C2 补 0
ds_union(a, b, withhead=true)
#
纵向合并(UNION ALL):将两个数据集纵向拼接,取第一个数据集的表头,去掉第二个数据集的表头行。
dataset_extra = [['category', 'C1', 'C2'],
['R3', 5, 9]]
result = ds_union(dataset, dataset_extra)
// 结果:
// [['category', 'C1', 'C2'],
// ['R1', 12, 18],
// ['R2', 10, 17],
// ['R3', 5, 9]]
数据集刷新 #
ds_param(name)
#
获取传入参数:在图形点击联动或 URL 参数传递后,通过参数名获取全局参数字典 filter_param 中对应的值。
// 假设点击图形后传入了 city='长沙'
let city = ds_param('city')
// 结果:'长沙'
// 在 SQL 中使用参数过滤(需配合后端参数语法)
// WHERE city = '${city}'
ds_setParam('参数名', 参数值)
#
设定全局参数:向全局参数字典 filter_param 写入参数,用于控制其他图形刷新时的过滤条件。当参数值为空/null/undefined 时,自动删除该参数,恢复到未传参的初始状态。
// 设置参数
ds_setParam('city', '长沙')
// filter_param 变为:{city: '长沙'}
// 清除参数(传空值)
ds_setParam('city', '')
// filter_param 变为:{}
// 典型联动场景:点击图形时传参并刷新其他图形
myChart.on('click', function(params) {
ds_setParam('city', params.name)
ds_refresh(2) // 刷新序号为 2 的图形
ds_refresh(3) // 刷新序号为 3 的图形
})
ds_refresh(序号, param=filter_param, r=null)
#
刷新图形/获取数据:触发指定序号的图形重新请求数据并渲染。可以传入自定义参数,也可以指定返回值格式用于获取数据。
| 参数 | 说明 | 默认值 |
|---|---|---|
序号 |
图形序号(对应后台配置的 id) | — |
param |
参数字典,默认使用全局参数 | filter_param |
r |
null 同步刷新渲染;0 触发异步刷新但不等待;'list' 同步返回二维数组;'map' 同步返回对象数组 |
null |
// 使用全局参数刷新序号为 2 的图形
ds_refresh(2)
// 使用指定参数刷新
ds_refresh(2, {city: '长沙', year: '2024'})
// 同步获取数据(返回二维数组格式)
let data = ds_refresh(2, filter_param, 'list')
// data = [['city','sales'],['长沙',100],['广州',200]]
// 同步获取数据(返回对象数组格式)
let data = ds_refresh(2, filter_param, 'map')
// data = [{city:'长沙', sales:100}, {city:'广州', sales:200}]
// 触发异步刷新,不等待返回值
ds_refresh(2, filter_param, 0)
数据处理 #
ds_rowname(dataset, start_row=1, column=0)
#
获取指定列数据:从指定起始行开始,提取指定列的所有值,返回一维数组。常用于获取图形的维度列表(X 轴分类)。
// 获取第一列(序号 0)从第 1 行起的所有值(默认)
result = ds_rowname(dataset)
// 结果:['R1', 'R2']
// 获取第二列(序号 1)从第 1 行起的数据
result = ds_rowname(dataset, 1, 1)
// 结果:[12, 10]
// 从第 2 行开始(跳过第 1 行)
result = ds_rowname(dataset, 2, 0)
// 结果:['R2']
ds_toThousands(num)
#
数字转千分位格式:将数字转换为逗号分隔的千分位字符串,支持负数和小数。
ds_toThousands(1234567)
// 结果:'1,234,567'
ds_toThousands(1234567.89)
// 结果:'1,234,567.89'
ds_toThousands(-9876543)
// 结果:'-9,876,543'
// 典型用法:ECharts tooltip/label 格式化
formatter: function(params) {
return ds_toThousands(params.value)
}
ds_round(num, qty=2)
#
小数位格式化:对数字保留指定位数的小数,默认保留两位,返回字符串。
ds_round(3.14159)
// 结果:'3.14'
ds_round(3.14159, 4)
// 结果:'3.1416'
ds_round(100, 0)
// 结果:'100'
// 典型用法:百分比显示
let pct = ds_round(0.3567 * 100, 1) + '%'
// 结果:'35.7%'
ds_generateLastDay(n=15, joinChat='-')
#
生成近 N 天日期数组:生成最近 N 天的日期列表(含表头行 ['zymd']),可用于与其他数据集 join 补全缺失日期。
// 生成最近 5 天
result = ds_generateLastDay(5)
// 结果(假设今天是 2024-01-15):
// [['zymd'],
// ['2024-01-11'],
// ['2024-01-12'],
// ['2024-01-13'],
// ['2024-01-14'],
// ['2024-01-15']]
// 使用斜杠分隔
result = ds_generateLastDay(3, '/')
// 结果:
// [['zymd'],
// ['2024/01/13'],
// ['2024/01/14'],
// ['2024/01/15']]
// 典型用法:与销售数据 fulljoin,补全没有数据的日期
result = ds_fulljoin(ds_generateLastDay(15), salesDataset)
ds_generateUUID()
#
生成 UUID:生成一个随机的 UUID v4 字符串,可用于唯一标识数据行或前端组件 id。
let id = ds_generateUUID()
// 结果示例:'550e8400-e29b-41d4-a716-446655440000'
// 典型用法:为新增数据行生成唯一 id
let newRow = {id: ds_generateUUID(), name: '新数据', value: 100}
new Date().format('yyyy-MM-dd hh:mm:ss')
#
日期格式化:Date 原型扩展方法,将日期对象按指定格式转换为字符串。
| 占位符 | 含义 |
|---|---|
yyyy |
四位年份 |
MM |
两位月份 |
dd |
两位日期 |
hh |
两位小时(24h) |
mm |
两位分钟 |
ss |
两位秒 |
q |
季度 |
S |
毫秒 |
new Date().format('yyyy-MM-dd')
// 结果示例:'2024-01-15'
new Date().format('yyyy-MM-dd hh:mm:ss')
// 结果示例:'2024-01-15 09:30:00'
new Date().format('yyyy年MM月dd日')
// 结果示例:'2024年01月15日'
// 典型用法:作为默认参数值
ds_setParam('start_date', new Date().format('yyyy-MM-dd'))
组件渲染 #
ds_formatArray(dataset, formatStr)
#
格式化数组为字符串:遍历数据集(跳过表头),用每行数据替换格式串中的 $字段名 占位符,多行结果用换行符拼接。
dataset6 = [['name', 'score', 'grade'],
['Alice', 95, 'A'],
['Bob', 82, 'B']]
result = ds_formatArray(dataset6, '$name 的成绩是 $score 分,等级 $grade')
// 结果:
// 'Alice 的成绩是 95 分,等级 A
// Bob 的成绩是 82 分,等级 B'
// 典型用法:生成 ECharts tooltip 内容或 HTML 字符串
let htmlStr = ds_formatArray(dataset6, '<li>$name:$score ($grade)</li>')
document.getElementById('list').innerHTML = '<ul>' + htmlStr + '</ul>'
ds_vue(eid, dataset, param=null, ds_list=null)
#
动态渲染 Vue 组件:异步加载 Vue + ElementUI,并在指定 DOM 元素上创建 Vue 实例,支持联动刷新其他图形。
| 参数 | 说明 |
|---|---|
eid |
DOM 选择器,如 '#container_1' |
dataset |
绑定到 ds 的数据(二维数组或对象) |
param |
绑定到 param 的参数对象 |
ds_list |
调用 refresh() 时要刷新的图形序号数组 |
// 基础渲染
await ds_vue('#container_1', dataset)
// 带参数联动(点击按钮时刷新序号 2、3 的图形)
let vm = await ds_vue('#container_1', dataset, {city: '长沙'}, [2, 3])
// Vue 模板中可调用 refresh() 触发联动
// <el-button @click="refresh()">刷新</el-button>
ds_chart(dataset, index=999, chartType=null)
#
异步动态渲染图形:根据数据集自动判断并渲染 ECharts 图形(饼图或柱状/折线图),支持点击切换图形类型。dataset 也可直接传入 ECharts option 对象或 HTML 字符串。
| 参数 | 说明 | 默认值 |
|---|---|---|
dataset |
二维数组、ECharts option 对象或 HTML 字符串 | — |
index |
渲染到哪个容器序号(container_序号) |
999 |
chartType |
强制指定图形类型:'bar'(柱图)、'pie'(饼图) |
null(自动) |
// 自动判断类型渲染(≤6 行且只有 2 列时用饼图,否则用柱图)
await ds_chart(dataset, 1)
// 强制渲染饼图
await ds_chart(dataset, 1, 'pie')
// 强制渲染柱状图
await ds_chart(dataset, 1, 'bar')
// 直接传入 ECharts option
await ds_chart({
xAxis: {type: 'category', data: ['R1', 'R2']},
yAxis: {type: 'value'},
series: [{type: 'bar', data: [12, 10]}]
}, 1)
// 渲染 HTML 内容
await ds_chart('<div style="color:red">暂无数据</div>', 1)
ds_loadcss(css, id=null)
#
动态加载样式:向页面 <head> 中动态注入 CSS,支持内置 CSS 名称(加载 /static/smartchart/opt/ 目录下对应的 .css 文件)、完整 URL 路径,或直接传入 CSS 字符串(配合 id 参数)。重复加载同一样式会自动跳过。
// 加载内置样式(如 swiper 组件样式)
ds_loadcss('smt_swiper')
// 实际加载:/static/smartchart/opt/smt_swiper.css
// 加载外部样式
ds_loadcss('https://cdn.example.com/style.css')
// 直接注入 CSS 字符串(id 用于防重复)
ds_loadcss('.my-box { color: red; font-size: 14px; }', 'my-custom-style')
Excel 数据集 #
ds_excel_refresh(dataset)
#
刷新复杂报表:向 LuckySheet 表格中批量写入数据,通过在单元格中预先设置 #df数字.字段名 占位符来指定填充位置。dataset 格式为 {df0: 二维数组, df1: 二维数组, ...}。
// dataset 格式
let dataset = {
df0: [['name', 'sales'],
['长沙', 100],
['广州', 200]],
df1: [['total'],
[300]]
}
// 表格中单元格预设占位符:#df0.name、#df0.sales、#df1.total
// 调用后会自动向对应单元格填入数据
ds_excel_refresh(dataset)
ds_excel_value(fillCells, clear=false)
#
获取单元格值:从 LuckySheet 表格中按列行坐标(如 'A1')批量读取单元格的值,返回值数组。常用于数据填报场景。
// 读取 A1、B2、C3 单元格的值
let values = ds_excel_value(['A1', 'B2', 'C3'])
// 结果示例:['张三', 100, '2024-01-15']
// 读取后同时清空这些单元格
let values = ds_excel_value(['A1', 'B2'], true)
// 典型填报场景
let [name, amount, date] = ds_excel_value(['B2', 'C2', 'D2'])
ds_save(1, [[name, amount, date]])
数据上传下载 #
ds_save(序号, contents, update=0, id=null)
#
保存/更新数据:将数据写入 SmartChart 的数据集存储。update=0 为新增,update=1 为更新(以第一列为主键匹配更新)。
// 新增一条数据
ds_save(1, [['name', 'sales'], ['长沙', 100]])
// 更新数据(按第一列 name 匹配更新)
ds_save(1, [['name', 'sales'], ['长沙', 150]], 1)
// 返回值:{status: 200, msg: 'success'}
let result = ds_save(1, contents)
if(result.status === 200) { alert('保存成功') }
ds_download(文件名, dataset, xls=0)
#
下载数据:将数据集下载到本地。默认下载为 CSV 文件;传入 xls=1 则下载为 Excel(.xlsx)文件。
// 下载为 CSV
ds_download('销售数据', dataset)
// 下载文件名:销售数据(浏览器自动加扩展名)
// 下载为 Excel
ds_download('销售数据', dataset, 1)
// 下载文件名:销售数据.xlsx
// 下载纯文本字符串
ds_download('report.txt', '这是一段文本内容')
更多用法参见: 数据下载
ds_uploadfile(blob, filename, name=null, callback=null)
#
上传文件:将文件(Blob 对象)上传到服务端,上传成功后执行回调函数。常与文件选择 input 配合使用。
| 参数 | 说明 |
|---|---|
blob |
文件 Blob 对象 |
filename |
文件名(含扩展名) |
name |
存储分类名,默认使用 dashid |
callback |
上传成功回调,接收服务端返回的数据 |
// 配合文件 input 使用
document.getElementById('fileInput').addEventListener('change', function(e) {
let file = e.target.files[0]
ds_uploadfile(file, file.name, 'my_category', function(data) {
console.log('上传成功,文件路径:', data.url)
})
})
// 上传 Canvas 截图
let canvas = document.getElementById('myCanvas')
canvas.toBlob(function(blob) {
ds_uploadfile(blob, 'screenshot.png', null, function(data) {
alert('截图已上传:' + data.url)
})
})
常用 JS 原生函数 #
// 在末尾追加一行/元素
dataset.push(['R3', 5, 9])
// 在开头插入一行/元素(注意:unshift 拼写)
dataset.unshift(['header', 'C1', 'C2'])
// 切片
dataset = dataset.slice(1) // 去掉表头,从第 1 行开始
dataset = dataset.slice(5, 10) // 取第 5 到第 9 行(不含第 10 行)
dataset = dataset.slice(-3) // 取最后 3 行
// for 循环(性能最好,SmartChart 推荐)
for (let i = 0; i < dataset.length; i++) {
let row = dataset[i]
}
// forEach(可读性好,无法 break)
dataset.forEach(function(row, index) {
console.log(index, row)
})
// map(生成新数组)
let values = dataset.slice(1).map(row => row[1]) // 取第二列值列表
// find(找第一个匹配元素)
let row = dataset.slice(1).find(row => row[0] === 'R1')
// concat(合并数组)
let merged = dataset.concat(dataset_extra.slice(1))
原始数据格式参考 #
假设 SQL = SELECT 维度1, 维度2, 数据 FROM xxxx,生成的标准二维数组格式如下:
dataset = [['category', 'C1', 'C2'], // 第 0 行:表头
['R1', 12, 18], // 第 1 行起:数据
['R2', 10, 17]]
- 第 0 行:表头,对应 SQL 查询的字段名
- 第 1 行起:数据行,第一列通常为维度(分类),后续列为数值
- 所有转化函数均以此格式为输入,输出格式也保持一致(除
ds_createMap、ds_createMap_all等转换函数外)