ヒント
このレッスンは、New Relic プラットフォームでカスタム視覚化を構築する方法を学習するコースの一部です。
New Relic のカスタム視覚化を使用すると、New Relic のデータベースからのデータでも外部ソースからのデータでも、New Relic プラットフォームが提供するチャートとは異なる独自の方法でデータを表示できます。
このレッスンでは、 RadarChartまたはTreemapの 2 つのグラフ タイプのいずれかでデータを表示する視覚化を構築します。 次に、New Relic One SDK からSegmentedControlコンポーネントを実装して、2 つのチャート タイプを切り替えることができるようになります。 最終的に、これにより、New Relic の基本機能では不可能な動的な方法でデータを自由に表示できるようになります。
ヒント
コード プロジェクトで迷ってしまったり、各レッスンを終えたときにファイルがどのようになっているかを確認したい場合は、Github のコース プロジェクトを確認してください。
あなたが始める前に
最後に、まだ行っていない場合は、次の操作を行います。
- New Relicアカウントにサインアップ
 - Node.jsをインストールする
 nr1クイックスタートの手順を完了して、CLI をインストールして構成します。
視覚化を作成する
最新バージョンの New Relic CLI を使用していることを確認してください。
$nr1 updateNerdpack のalternate-vizに、 radar-or-treemapという視覚化を作成します。
$nr1 create --type visualization --name radar-or-treemap✔ You’re trying to create a visualization outside of a Nerdpack.  We’ll create a Nerdpack for you—what do you want to name it? … alternate-viz✔  nerdpack created successfully!   nerdpack alternate-viz is available at "./alternate-viz"✔  visualization created successfully!   visualization radar-or-treemap is available at "./alternate-viz/visualizations/radar-or-treemap"ヒント
nr1 createを実行したときに自己署名証明書のRequestErrorを受け取った場合は、Node の証明書チェーンに証明書を追加する必要がある可能性があります。
その結果、 alternate-vizの下に新しいvisualizations/radar-or-treemapディレクトリが作成されます。
$cd alternate-viz$ls visualizations/radar-or-treemapindex.js    nr1.json    styles.scssimport React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,} from 'recharts';import {  Card,  CardBody,  HeadingText,  NrqlQuery,  Spinner,  AutoSizer,} from 'nr1';
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <RadarChart                  width={width}                  height={height}                  data={transformedData}                >                  <PolarGrid />                  <PolarAngleAxis dataKey="name" />                  <PolarRadiusAxis tickFormatter={this.formatTick} />                  <Radar                    dataKey="value"                    stroke={stroke || '#51C9B7'}                    fill={fill || '#51C9B7'}                    fillOpacity={0.6}                  />                </RadarChart>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);コンポーネントの状態を設定する
nr1が作成したデフォルトの視覚化テンプレートにコンポーネント状態を追加します。
alternate-viz/visualizations/radar-or-treemap/index.jsに移動します。 このレッスンの残りの時間はここで作業します。
CHART_TYPESという定数を追加します:
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,} from 'recharts';import {  Card,  CardBody,  HeadingText,  NrqlQuery,  Spinner,  AutoSizer,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <RadarChart                  width={width}                  height={height}                  data={transformedData}                >                  <PolarGrid />                  <PolarAngleAxis dataKey="name" />                  <PolarRadiusAxis tickFormatter={this.formatTick} />                  <Radar                    dataKey="value"                    stroke={stroke || '#51C9B7'}                    fill={fill || '#51C9B7'}                    fillOpacity={0.6}                  />                </RadarChart>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);CHART_TYPES 視覚化で交互に使用する 2 つのグラフ タイプを列挙します。
コンポーネントのstateでselectedChartを初期化します。
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,} from 'recharts';import {  Card,  CardBody,  HeadingText,  NrqlQuery,  Spinner,  AutoSizer,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  state = {    selectedChart: CHART_TYPES.Radar,  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <RadarChart                  width={width}                  height={height}                  data={transformedData}                >                  <PolarGrid />                  <PolarAngleAxis dataKey="name" />                  <PolarRadiusAxis tickFormatter={this.formatTick} />                  <Radar                    dataKey="value"                    stroke={stroke || '#51C9B7'}                    fill={fill || '#51C9B7'}                    fillOpacity={0.6}                  />                </RadarChart>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);このstate値には、データを表示するグラフの種類が格納されます。
視覚化のグラフ タイプのオプションを列挙するオブジェクトを作成し、 state.selectedChartを初期化したので、2 つのグラフ タイプを切り替えるためのコントロール UI を実装する準備が整いました。
追加 SegmentedControl 
state.selectedChart 視覚化のユーザーが実際にグラフの種類を選択できない限り、役に立ちません。 2 つのグラフ タイプを切り替えるには、 SegmentedControlとSegmentedControlItem使用します。
nr1からSegmentedControlとSegmentedControlItemインポートします:
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,} from 'recharts';import {  AutoSizer,  Card,  CardBody,  HeadingText,  NrqlQuery,  SegmentedControl,  SegmentedControlItem,  Spinner,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  state = {    selectedChart: CHART_TYPES.Radar,  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <RadarChart                  width={width}                  height={height}                  data={transformedData}                >                  <PolarGrid />                  <PolarAngleAxis dataKey="name" />                  <PolarRadiusAxis tickFormatter={this.formatTick} />                  <Radar                    dataKey="value"                    stroke={stroke || '#51C9B7'}                    fill={fill || '#51C9B7'}                    fillOpacity={0.6}                  />                </RadarChart>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);render()で、 RadarChartをReact.Fragmentでラップします。
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,} from 'recharts';import {  AutoSizer,  Card,  CardBody,  HeadingText,  NrqlQuery,  SegmentedControl,  SegmentedControlItem,  Spinner,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  state = {    selectedChart: CHART_TYPES.Radar,  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <React.Fragment>                  <RadarChart                    width={width}                    height={height}                    data={transformedData}                  >                    <PolarGrid />                    <PolarAngleAxis dataKey="name" />                    <PolarRadiusAxis tickFormatter={this.formatTick} />                    <Radar                      dataKey="value"                      stroke={stroke || '#51C9B7'}                      fill={fill || '#51C9B7'}                      fillOpacity={0.6}                    />                  </RadarChart>                </React.Fragment>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);これにより、同じrender()から複数のコンポーネントを返すことができます。
SegmentedControlと 2 つのSegmentedControlItemコンポーネントを追加します。各コンポーネントにはvalueとlabelが含まれます。
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,} from 'recharts';import {  AutoSizer,  Card,  CardBody,  HeadingText,  NrqlQuery,  SegmentedControl,  SegmentedControlItem,  Spinner,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  state = {    selectedChart: CHART_TYPES.Radar,  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <React.Fragment>                  <SegmentedControl                    onChange={(event, value) => console.log(value)}                  >                    <SegmentedControlItem                      value={CHART_TYPES.Radar}                      label="Radar chart"                    />                    <SegmentedControlItem                      value={CHART_TYPES.Treemap}                      label="Treemap chart"                    />                  </SegmentedControl>                  <RadarChart                    width={width}                    height={height}                    data={transformedData}                  >                    <PolarGrid />                    <PolarAngleAxis dataKey="name" />                    <PolarRadiusAxis tickFormatter={this.formatTick} />                    <Radar                      dataKey="value"                      stroke={stroke || '#51C9B7'}                      fill={fill || '#51C9B7'}                      fillOpacity={0.6}                    />                  </RadarChart>                </React.Fragment>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);ここで、選択を変更すると、 SegmentedControlはSegmentedControlItem.valueをコンソールに記録します。 SegmentedControlItemコンポーネントに定義した値は、前の手順で作成した 2 つのCHART_TYPESに対応します。
alternate-vizにある Nerdpack のルートに移動します。
Nerdpack を地元で提供しましょう:
$nr1 nerdpack:serveNode サーバーの起動時にターミナルに表示される視覚化へのリンクを開きます。
Visualizations: ⁎  radar-or-treemap https://one.nr/012ab3cd4Efアカウント ID とクエリを使用して視覚化を構成します。
チャートの処理に必要なデータがいくつかあるため、ビューの上部にSegmentedControlを含むRadarChartが表示されます。
SegmentedControl ログを確認するには、 browserのコンソールを参照してください。
コンポーネントのstateを SegmentedControl 
stateを更新するメソッドを追加し、そのメソッドを前のセクションで追加したSegmentedControlに接続します。
updateSelectedChart()というコンポーネント メソッドを追加します。
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,} from 'recharts';import {  AutoSizer,  Card,  CardBody,  HeadingText,  NrqlQuery,  SegmentedControl,  SegmentedControlItem,  Spinner,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  state = {    selectedChart: CHART_TYPES.Radar,  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  updateSelectedChart = (evt, value) => {    this.setState({ selectedChart: value });  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <React.Fragment>                  <SegmentedControl                    onChange={(event, value) => console.log(value)}                  >                    <SegmentedControlItem                      value={CHART_TYPES.Radar}                      label="Radar chart"                    />                    <SegmentedControlItem                      value={CHART_TYPES.Treemap}                      label="Treemap chart"                    />                  </SegmentedControl>                  <RadarChart                    width={width}                    height={height}                    data={transformedData}                  >                    <PolarGrid />                    <PolarAngleAxis dataKey="name" />                    <PolarRadiusAxis tickFormatter={this.formatTick} />                    <Radar                      dataKey="value"                      stroke={stroke || '#51C9B7'}                      fill={fill || '#51C9B7'}                      fillOpacity={0.6}                    />                  </RadarChart>                </React.Fragment>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);この新しいメソッドはvalue引数を受け取り、 state.selectedChartをその値に設定します。
SegmentedControl.onChangeをupdateSelectedChart()に設定します:
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,} from 'recharts';import {  AutoSizer,  Card,  CardBody,  HeadingText,  NrqlQuery,  SegmentedControl,  SegmentedControlItem,  Spinner,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  state = {    selectedChart: CHART_TYPES.Radar,  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  updateSelectedChart = (evt, value) => {    this.setState({ selectedChart: value });  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <React.Fragment>                  <SegmentedControl onChange={this.updateSelectedChart}>                    <SegmentedControlItem                      value={CHART_TYPES.Radar}                      label="Radar chart"                    />                    <SegmentedControlItem                      value={CHART_TYPES.Treemap}                      label="Treemap chart"                    />                  </SegmentedControl>                  <RadarChart                    width={width}                    height={height}                    data={transformedData}                  >                    <PolarGrid />                    <PolarAngleAxis dataKey="name" />                    <PolarRadiusAxis tickFormatter={this.formatTick} />                    <Radar                      dataKey="value"                      stroke={stroke || '#51C9B7'}                      fill={fill || '#51C9B7'}                      fillOpacity={0.6}                    />                  </RadarChart>                </React.Fragment>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);ここで、 SegmentedControlで選択内容を変更すると、その選択内容がstateに設定されます。
実装する Treemap 
視覚化にTreemapを追加します。 このマップは既存のRadarChartの代替となります。
技術的詳細
このガイドでは、サードパーティのチャートにRechartsコンポーネントを使用しますが、New Relic の視覚化とアプリを構築するときに、現在の React バージョンと互換性のある他の JavaScript チャート ライブラリを使用することもできます。
rechartsからTreemapをインポートします:
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,  Treemap,} from 'recharts';import {  AutoSizer,  Card,  CardBody,  HeadingText,  NrqlQuery,  SegmentedControl,  SegmentedControlItem,  Spinner,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  state = {    selectedChart: CHART_TYPES.Radar,  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  updateSelectedChart = (evt, value) => {    this.setState({ selectedChart: value });  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <React.Fragment>                  <SegmentedControl onChange={this.updateSelectedChart}>                    <SegmentedControlItem                      value={CHART_TYPES.Radar}                      label="Radar chart"                    />                    <SegmentedControlItem                      value={CHART_TYPES.Treemap}                      label="Treemap chart"                    />                  </SegmentedControl>                  <RadarChart                    width={width}                    height={height}                    data={transformedData}                  >                    <PolarGrid />                    <PolarAngleAxis dataKey="name" />                    <PolarRadiusAxis tickFormatter={this.formatTick} />                    <Radar                      dataKey="value"                      stroke={stroke || '#51C9B7'}                      fill={fill || '#51C9B7'}                      fillOpacity={0.6}                    />                  </RadarChart>                </React.Fragment>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);これで、視覚化コンポーネントでTreemapを使用できるようになりました。
render()にTreemapコンポーネントを追加します。
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,  Treemap,} from 'recharts';import {  AutoSizer,  Card,  CardBody,  HeadingText,  NrqlQuery,  SegmentedControl,  SegmentedControlItem,  Spinner,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  state = {    selectedChart: CHART_TYPES.Radar,  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  updateSelectedChart = (evt, value) => {    this.setState({ selectedChart: value });  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <React.Fragment>                  <SegmentedControl onChange={this.updateSelectedChart}>                    <SegmentedControlItem                      value={CHART_TYPES.Radar}                      label="Radar chart"                    />                    <SegmentedControlItem                      value={CHART_TYPES.Treemap}                      label="Treemap chart"                    />                  </SegmentedControl>                  <RadarChart                    width={width}                    height={height}                    data={transformedData}                  >                    <PolarGrid />                    <PolarAngleAxis dataKey="name" />                    <PolarRadiusAxis tickFormatter={this.formatTick} />                    <Radar                      dataKey="value"                      stroke={stroke || '#51C9B7'}                      fill={fill || '#51C9B7'}                      fillOpacity={0.6}                    />                  </RadarChart>                  <Treemap                    width={width}                    height={height}                    data={transformedData}                    dataKey="value"                    ratio={4 / 3}                    stroke={stroke || '#000000'}                    fill={fill || '#51C9B7'}                  />                </React.Fragment>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);ここでは、 height 、 width 、 fill 、 strokeなどのいくつかのプロパティを使用して、新しいTreemapコンポーネントを定義しました。
Nerdpack をローカルで提供して、視覚化を表示します。 SegmentedControlとRadarChartビューの上部にありますが、下にスクロールすると新しいTreemapが表示されます。
コンポーネントのチャートを切り替える state 
state.selectedChartを使用して、表示するグラフRadarChartまたはTreemapを決定します。
this.stateを分解して、別の定数としてselectedChartにアクセスします。 次に、 selectedChartとCHART_TYPES.Radarを比較します。 同じ場合は、 RadarChartをレンダリングします。 それ以外の場合は、 Treemapをレンダリングします。
import React from 'react';import PropTypes from 'prop-types';import {  Radar,  RadarChart,  PolarGrid,  PolarAngleAxis,  PolarRadiusAxis,  Treemap,} from 'recharts';import {  AutoSizer,  Card,  CardBody,  HeadingText,  NrqlQuery,  SegmentedControl,  SegmentedControlItem,  Spinner,} from 'nr1';
const CHART_TYPES = {  Radar: 'radar',  Treemap: 'treemap',};
export default class RadarOrTreemapVisualization extends React.Component {  // Custom props you wish to be configurable in the UI must also be defined in  // the nr1.json file for the visualization. See docs for more details.  static propTypes = {    /**     * A fill color to override the default fill color. This is an example of     * a custom chart configuration.     */    fill: PropTypes.string,
    /**     * A stroke color to override the default stroke color. This is an example of     * a custom chart configuration.     */    stroke: PropTypes.string,    /**     * An array of objects consisting of a nrql `query` and `accountId`.     * This should be a standard prop for any NRQL based visualizations.     */    nrqlQueries: PropTypes.arrayOf(      PropTypes.shape({        accountId: PropTypes.number,        query: PropTypes.string,      })    ),  };
  state = {    selectedChart: CHART_TYPES.Radar,  };
  /**   * Restructure the data for a non-time-series, facet-based NRQL query into a   * form accepted by the Recharts library's RadarChart.   * (https://recharts.org/api/RadarChart).   */  transformData = (rawData) => {    return rawData.map((entry) => ({      name: entry.metadata.name,      // Only grabbing the first data value because this is not time-series data.      value: entry.data[0].y,    }));  };
  /**   * Format the given axis tick's numeric value into a string for display.   */  formatTick = (value) => {    return value.toLocaleString();  };
  updateSelectedChart = (evt, value) => {    this.setState({ selectedChart: value });  };
  render() {    const { nrqlQueries, stroke, fill } = this.props;    const { selectedChart } = this.state;
    const nrqlQueryPropsAvailable =      nrqlQueries &&      nrqlQueries[0] &&      nrqlQueries[0].accountId &&      nrqlQueries[0].query;
    if (!nrqlQueryPropsAvailable) {      return <EmptyState />;    }
    return (      <AutoSizer>        {({ width, height }) => (          <NrqlQuery            query={nrqlQueries[0].query}            accountId={parseInt(nrqlQueries[0].accountId)}            pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}          >            {({ data, loading, error }) => {              if (loading) {                return <Spinner />;              }
              if (error) {                return <ErrorState />;              }
              const transformedData = this.transformData(data);
              return (                <React.Fragment>                  <SegmentedControl onChange={this.updateSelectedChart}>                    <SegmentedControlItem                      value={CHART_TYPES.Radar}                      label="Radar chart"                    />                    <SegmentedControlItem                      value={CHART_TYPES.Treemap}                      label="Treemap chart"                    />                  </SegmentedControl>                  {selectedChart === CHART_TYPES.Radar ? (                    <RadarChart                      width={width}                      height={height}                      data={transformedData}                    >                      <PolarGrid />                      <PolarAngleAxis dataKey="name" />                      <PolarRadiusAxis tickFormatter={this.formatTick} />                      <Radar                        dataKey="value"                        stroke={stroke || '#51C9B7'}                        fill={fill || '#51C9B7'}                        fillOpacity={0.6}                      />                    </RadarChart>                  ) : (                    <Treemap                      width={width}                      height={height}                      data={transformedData}                      dataKey="value"                      ratio={4 / 3}                      stroke={stroke || '#000000'}                      fill={fill || '#51C9B7'}                    />                  )}                </React.Fragment>              );            }}          </NrqlQuery>        )}      </AutoSizer>    );  }}
const EmptyState = () => (  <Card className="EmptyState">    <CardBody className="EmptyState-cardBody">      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Please provide at least one NRQL query & account ID pair      </HeadingText>      <HeadingText        spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}        type={HeadingText.TYPE.HEADING_4}      >        An example NRQL query you can try is:      </HeadingText>      <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>    </CardBody>  </Card>);
const ErrorState = () => (  <Card className="ErrorState">    <CardBody className="ErrorState-cardBody">      <HeadingText        className="ErrorState-headingText"        spacingType={[HeadingText.SPACING_TYPE.LARGE]}        type={HeadingText.TYPE.HEADING_3}      >        Oops! Something went wrong.      </HeadingText>    </CardBody>  </Card>);ここでは、三項式を使用してRadarChartまたはTreemapをレンダリングしました。 レンダリングされるチャートは、 selectedChartの値によって決まります。
Nerdpack をローカルで提供して、視覚化を表示します。
SegmentedControlからRadar chart [レーダーチャート]を選択します。
SegmentedControlからTreemap chart [ツリーマップ チャート]を選択します。
概要
おめでとう! このレッスンでは、次の方法を学習しました。
- New Relic One SDKコンポーネントを使用して視覚化をカスタマイズする
 - 視覚化に新しいチャートタイプを追加する
 - 視覚化でユーザーインタラクションを作成する
 
ヒント
このレッスンは、New Relic プラットフォームでカスタム視覚化を構築する方法を学習するコースの一部です。 準備ができたら、次のレッスン「設定を使用して視覚化をカスタマイズする」に進んでください。