使用可視化元件建立自訂可視化圖表

本教學課程適用於經驗豐富的 JavaScript 開發人員,並假設您對功能式程式設計技巧略知一二。

在本例中,我們先查詢某些品牌的假設季度銷售資訊。首先,我們會篩選特定品牌的查詢,然後依銷售季度樞紐轉換結果。請參閱下表範例。

查詢結果:依品牌查看訂單計數,並以「訂單建立季度」維度樞紐。

接著,我們會使用視覺化元件建立自訂視覺化圖表,顯示每個品牌的產品在過去一個季度的趨勢。結果會是一種新型態的視覺化資料,由一系列微型圖組成,並嵌入表格中,如下圖所示:

自訂視覺化報表會顯示表格,每個品牌對應一列,以及嵌入的線圖視覺化報表,顯示每列的季度訂單。

除了說明如何建立自訂圖表,這個範例也說明瞭在 React 應用程式中使用 Looker API 的最佳做法。

如要使用 Looker 元件建立自訂圖表,請確認設定符合規定,然後執行下列步驟:

  1. 在「探索」中建立查詢並複製 qid
  2. 將資料傳遞至自訂視覺化元件
  3. 建構 CustomVis 元件
  4. 轉換標準化資料
  5. 將轉換後的資料插入 CustomVis
  6. 產生自訂視覺化內容

如果自訂圖表是用於嵌入式應用程式或擴充功能,建議使用圖表元件來建立自訂圖表。如要讓自訂圖表可供 Looker 使用者在 Looker 執行個體中使用,請按照 visualization 說明文件中的操作說明進行。如要開發自訂視覺化報表並上傳至 Looker Marketplace,請按照「為 Looker Marketplace 開發自訂視覺化報表」說明文件中的操作說明進行。

需求條件

開始前,請先準備以下幾項元素:

  • 您必須具備 Looker 執行個體的存取權。
  • 無論您是使用擴充功能架構還是自有的獨立 React 應用程式,都必須透過 Looker API 進行驗證,並存取 Looker SDK 物件。詳情請參閱 Looker API 驗證擴充功能架構
  • 請確認您已安裝 Looker 圖表可視化元件 NPM 套件,以及 @looker/components-data NPM 套件。如要瞭解如何安裝及使用圖像化元件套件,請參閱 GitHubNPM 中的 README 文件。

步驟 1:在探索中建立查詢並複製查詢 ID

在本例中,我們使用假設的季度銷售資訊,針對我們追蹤的品牌進行長期追蹤。

我們會轉換這項資料,因為轉換是 Looker 內建的查詢結果分組方式。在探索資料中,我們可以執行查詢,並使用 Looker 的原生可視化類型建立資料圖表。這張圖表提供許多資訊,但要一眼看出各品牌產品的趨勢,難度不低:

根據品牌查詢訂單計數所產生的圖表,其中「訂單建立季度」維度已轉置。

接下來,請從「探索」的網址列複製 qid 值。在本例中,qid 值為 Uijcav7pCA4MZY2MompsPZ,但這個值僅適用於我們的測試例項;您的值會有所不同。

步驟 2:將資料傳遞至自訂圖表元件

首先,將從 Explore 網址取得的 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 元素做為子項,並只會將 configdatafieldstotals 值傳遞為屬性,以轉譯您自己的視覺化元件。我們會將 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 元件繼承的屬性包括 configfieldsdatapivotstotals

  • config 會說明資料應如何在圖表中顯示,例如 Sparkline 中線條的粗細,或散布圖中點的大小和形狀。
  • 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: [],
            }}
          />
        ),
      },
    ]
  }, [])
}

建立函式的步驟如下:

  1. 對資料集進行縮減,從每個資料列的季度訂單資料中分離出品牌名稱。
  2. 更新每個資料列,納入維度和可代表表格中每個資料列值的呈現 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>
  )
}

後續步驟