本教程面向有经验的 JavaScript 开发者,假定您对函数式编程技术有所了解。
在本例中,我们首先使用一个与某些品牌的假想季度销售信息相关的查询。首先,我们将过滤特定品牌的查询,然后按销售季度透视结果。有关示例,请参阅下表。
然后,我们将使用可视化组件构建一个自定义可视化图表,以显示每个品牌的商品在过去一个季度的销售趋势。这会产生一种新的可视化,由嵌套在表中的一系列火花谱线图组成,如下例所示:
这个示例不仅展示了如何创建自定义可视化,还演示了在 React 应用中使用 Looker API 的一些最佳实践。
如需使用 Looker 组件构建自定义可视化图表,请确保您的设置符合要求,然后执行以下步骤:
如果自定义可视化图表要用于嵌入式应用或扩展程序,则适合使用可视化图表组件构建自定义可视化图表。如果您希望为 Looker 实例的 Looker 用户提供自定义可视化图表,请按照
visualization
文档页面中的说明操作。如果您想开发自定义可视化图表并将其上传到 Looker Marketplace,请按照为 Looker Marketplace 开发自定义可视化图表文档页面中的说明操作。
使用要求
在开始之前,您需要准备以下几项元素:
- 您必须有权访问 Looker 实例。
- 无论您是在扩展程序框架中构建,还是在您自己的独立 React 应用中构建,都需要通过 Looker 的 API 进行身份验证并拥有 Looker SDK 对象的访问权限。如需了解详情,请参阅 Looker API 身份验证或我们的扩展框架。
- 确保您已安装 Looker 可视化组件 NPM 软件包 和
@looker/components-data
NPM 软件包。如需了解如何安装和使用可视化组件软件包,请参阅 GitHub 和 NPM 中的 README 文档。
第 1 步:在探索中构建查询并复制查询 ID
在此示例中,我们使用了我们要跟踪的品牌的假想季度销售信息。
我们将透视这些数据,因为透视是 Looker 对查询结果进行分组的内置方式。在探索中,我们可以运行查询,并使用 Looker 的一种原生可视化类型创建数据图表。该图表提供了大量信息,但很难一目了然地解读每个品牌的商品趋势:
与渲染简单可视化图表的示例一样,下一步是从“探索”的网址栏中复制 qid
值。在本示例中,qid
值为 Uijcav7pCA4MZY2MompsPZ
,但该值特定于我们的测试实例;您的值将有所不同。
第 2 步:将数据传递给自定义可视化组件
首先,将从探索的网址中获取的 qid
值传递到 Query
组件,并将经过身份验证的 SDK 对象传递给 DataProvider
。
import React, { useContext } from 'react'
import { ExtensionContext } from '@looker/extension-sdk-react'
import { DataProvider } from '@looker/components-data'
import { Query } from '@looker/visualizations'
export const MyReactApp = () => {
const { core40SDK } = useContext(ExtensionContext)
return (
<DataProvider sdk={core40SDK}>
<Query query='Uijcav7pCA4MZY2MompsPZ'></Query>
</DataProvider>
)
}
接下来,我们将构建一个名为 CustomVis
的自定义组件,而不是通过 Visualization
组件渲染原生 Looker 可视化图表。
Query
组件可以接受任何 React 元素作为子元素,并且只需传递 config
、data
、fields
和 totals
值作为属性,即可渲染您自己的可视化组件。我们将 CustomVis
呈现为 Query
的子项,以便它可以接收所有相关数据作为属性。
import React, { useContext } from 'react'
import { ExtensionContext } from '@looker/extension-sdk-react'
import { DataProvider } from '@looker/components-data'
import { Query } from '@looker/visualizations'
import { CustomVis } from '../path/to/MyCustomVis'
export const MyReactApp = () => {
const { core40SDK } = useContext(ExtensionContext)
return (
<DataProvider sdk={core40SDK}>
<Query query='Uijcav7pCA4MZY2MompsPZ'>
<CustomVis />
</Query>
</DataProvider>
)
}
第 3 步:构建 CustomVis
组件
接下来,我们来构建 CustomVis
组件。从 Query
组件继承的属性包括 config
、fields
、data
、pivots
和 totals
:
config
描述了数据在图表中呈现的所有方式,例如火花谱线图中线条的粗细或散点图中各点的大小和形状。fields
存储有关从查询返回的测量值和维度值的其他元数据,例如值应如何设置格式或为每个轴添加标签的内容。data
是从查询返回的键值对响应。pivots
用于描述透视查询所依据的维度。totals
引用 Looker 的行总计,以便在基于表格的可视化中使用。
我们可以通过插入 Table
组件,将这些未经修改的属性传递到表格可视化图表。
import React from 'react'
import { Table } from '@looker/visualizations'
export const CustomVis = ({ config, fields, data, pivots }) => {
return <Table config={config} data={data} fields={fields} pivots={pivots} />
}
这样,我们就可以了解直接从 SDK 返回的数据。在呈现的响应中,每个品牌都会有一行显示结果,并且结果按季度分组或透视。
第 4 步:转换标准化数据
为了转换此透视数据以使用嵌套的火花谱线图进行渲染,我们会隔离所有测量值并将其传递给子图表。在下图中,我们突出显示了单行数据的相关数据,以说明我们将收起并使用子级可视化结果呈现的数据:
我们将为此创建一个自定义转换。以下示例专门针对此场景;您需要相应地解析自己的数据。
import React from 'react'
import { Table, Sparkline } from '@looker/visualizations'
// we assign this value to a constant to ensure that fields and data
// objects remain in sync.
const NESTED_DATA_KEY = 'orderCount'
const nestSparklines = (data) => {
return data.reduce((acc, d) => {
// the first entry is the dimension (brand name), and the rest of the rows are the
// quarterly sales information we want to pass to the Sparkline.
const [parentDimension, ...measurePairs] = Object.entries(d)
// `nonPivotedData` represents a single data row.
// e.g. [{entry: 1, orderCount: 10}, {entry: 2, orderCount: 15}, ...etc]
const nonPivotedData: SDKRecord[] = measurePairs.map(([_, value], i) => {
return { entry: i, [NESTED_DATA_KEY]: value }
})
// now for each row in the table we render a Sparkline using the `nonPivotedData`
// that we built.
// E.G. [{products.brand: 'adidas', orderCount: <Sparkline />}]
return [
...acc,
{
[parentDimension[0]]: parentDimension[1],
[NESTED_DATA_KEY]: () => (
<Sparkline
height={75}
data={nonPivotedData}
fields={{
measures: [{ name: NESTED_DATA_KEY }],
dimensions: [],
}}
/>
),
},
]
}, [])
}
该函数按照以下步骤创建:
- 减少数据集,以将品牌名称与每行的季度订单数据分离。
- 更新每一行,以包含相应维度以及呈现的 React 组件(可表示表格中每一行的值)。
第 5 步:将转换后的数据插入 CustomVis
现在,使用新函数转换数据,并将输出分配给名为 nestedData
的新变量:
export const CustomVis =({
fields,
data,
config,
pivots,
}) => {
const nestedData = nestSparklines(data)
return (
<Table
fields={{
measures: [{ name: NESTED_DATA_KEY, label: 'Orders Count By Quarter' }],
dimensions: fields.dimensions,
pivots: [],
}}
config={config}
data={nestedData}
pivots={pivots}
/>
)
}
第 6 步:生成自定义可视化
插入转换后的数据并配置图表后,可视化图表将类似于下方的表格示例,其中每行都有单独的火花谱线图:
渲染此可视化内容所需的完整代码如下所示:
import React, { useContext } from 'react'
import { ExtensionContext } from '@looker/extension-sdk-react'
import { DataProvider } from '@looker/components-data'
import { Query, Sparkline, Table } from '@looker/visualizations'
// we assign this value to a constant to ensure that fields and data
// objects remain in sync.
const NESTED_DATA_KEY = 'orderCount'
const ROW_HEIGHT = 75
const nestSparklines = data => {
return data.reduce((acc, d) => {
// the first entry is the dimension (brand name), and the rest of the rows are the
// quarterly sales information we want to pass to the Sparkline.
const [parentDimension, ...measurePairs] = Object.entries(d)
// `nonPivotedData` represents a single data row.
// e.g. [{entry: 1, orderCount: 10}, {entry: 2, orderCount: 15}, ...etc]
const nonPivotedData = measurePairs.map(([_, value], i) => {
return { entry: i, [NESTED_DATA_KEY]: value }
})
// now for each row in the table we render a Sparkline using the `nonPivotedData`
// that we built.
// E.G. [{products.brand: 'adidas', orderCount: <Sparkline />}]
return [
...acc,
{
[parentDimension[0]]: parentDimension[1],
[NESTED_DATA_KEY]: () => (
<Sparkline
height={ROW_HEIGHT}
data={nonPivotedData}
fields={{
measures: [{ name: NESTED_DATA_KEY }],
dimensions: [],
}}
/>
),
},
]
}, [])
}
const CustomVis = ({ fields, data, pivots, config }) => {
const nestedData = nestSparklines(data)
return (
<Table
config={config}
height={500}
fields={{
measures: [{ name: NESTED_DATA_KEY, label: 'Orders Count By Quarter' }],
dimensions: fields.dimensions,
pivots: [],
}}
data={nestedData}
pivots={pivots}
defaultRowHeight={ROW_HEIGHT}
/>
)
}
export const MyReactApp = () => {
const { core40SDK } = useContext(ExtensionContext)
return (
<DataProvider sdk={core40SDK}>
<Query query='Uijcav7pCA4MZY2MompsPZ'>
<CustomVis />
</Query>
</DataProvider>
)
}