---
title: Customize your visualization with SDK components
source: https://docs.newrelic.com/docs/new-relic-solutions/tutorials/custom-visualization-sdk
---

> #### 💡 TIP
>
> This lesson is part of a course that teaches you how to build a custom visualization on the New Relic platform.

Use New Relic custom visualizations to display your data, whether it's from New Relic's database or an external source, in unique ways that are distinct from the charts offered by the New Relic platform.

In this lesson, you build a visualization that displays your data in one of two chart types: [`RadarChart`](https://recharts.org/en-US/api/RadarChart) or [`Treemap`](https://recharts.org/en-US/api/Treemap). You then implement a `SegmentedControl` component from the New Relic One SDK, which allows you to alternate between the two chart types. Ultimately, this gives you freedom to view your data in a dynamic way that isn't possible with New Relic's base offerings.

> #### 💡 TIP
>
> If you get lost in the code project and would like to see what the files should look like when you're done with each lesson, check out the [course project](https://github.com/newrelic/nru-custom-visualization-course) on Github.

## Before you begin [#begin]

Finally, if you haven't already:

-   Sign up for a [New Relic account](https://newrelic.com/signup?utm_source=developer-site)
-   Install [Node.js](https://nodejs.org/en/download/)
-   Complete the steps in the [`nr1` quick start](https://one.newrelic.com/launcher/developer-center.launcher?pane=eyJuZXJkbGV0SWQiOiJkZXZlbG9wZXItY2VudGVyLmRldmVsb3Blci1jZW50ZXIifQ==) to install and configure the CLI

## Create your visualization [#create-visualization]

1.  Ensure you're working with the latest version of the New Relic CLI:
    ````bash
    nr1 update
    ```

    ````
2.  Create a visualization, called `radar-or-treemap`, in a Nerdpack, called `alternate-viz`:
    ````bash animate
    nr1 create --type visualization --name radar-or-treemap
    [output] {success}✔ {plain}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
    [output]
    [output] {success}✔  {plain}nerdpack created successfully!
    [output]    {purple}nerdpack {blue}alternate-viz {plain}is available at {green}"./alternate-viz"
    [output]
    [output] {success}✔  {plain}visualization created successfully!
    [output]    {purple}visualization {blue}radar-or-treemap {plain}is available at {green}"./alternate-viz/visualizations/radar-or-treemap"
    ```

    <Callout variant="tip">
      If you receive a `RequestError` for a self-signed certificate when you run `nr1 create`, you may need to add a certificate to Node's certificate chain.
    </Callout>

    As a result, you have a new `visualizations/radar-or-treemap` directory under `alternate-viz`:

    ```bash
    cd alternate-viz
    ls visualizations/radar-or-treemap
    [output] index.js    nr1.json    styles.scss
    ```

    ````

```jsx fileName=visualizations/radar-or-treemap/index.js
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';

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>
);
```

## Set up your component state [#set-component]

Add component state to the default visualization template that `nr1` created for you.

1.  Navigate to `alternate-viz/visualizations/radar-or-treemap/index.js`. You'll work in here for the rest of this lesson.
2.  Add a constant called `CHART_TYPES`:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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` enumerates the two chart types you'll alternate between in your visualization.

    ````
3.  Initialize `selectedChart` in your component's `state`:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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>
    );
    ```

    This `state` value stores the chart type in which you want to show your data.

    Now that you've created an object which enumerates the chart type options for your visualization, and you've initialized `state.selectedChart`, you're ready to implement a control UI for switching between the two chart types.

    ````

## Add `SegmentedControl` components [#segmentedcontrol]

`state.selectedChart` isn't useful unless your visualization's users can actually select a chart type. Use `SegmentedControl` and `SegmentedControlItem` to switch between the two chart types.

1.  Import `SegmentedControl` and `SegmentedControlItem` from `nr1`:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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>
    );
    ```

    ````
2.  In `render()`, wrap `RadarChart` in a `React.Fragment`:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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>
    );
    ```

    This allows you to return multiple components from the same `render()`.

    ````
3.  Add a `SegmentedControl` and two `SegmentedControlItem` components, each with a `value` and a `label`:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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>
    );
    ```

    Here, your `SegmentedControl` logs the `SegmentedControlItem.value` to the console when you change your selection. The values you've defined for your `SegmentedControlItem` components correspond to the two `CHART_TYPES` you created in a previous step.

    ````
4.  Navigate to the root of your Nerdpack at `alternate-viz`.
5.  Serve your Nerdpack locally:
    ````bash
    nr1 nerdpack:serve
    ```

    ````
6.  Open the link to your visualization that's shown in the terminal when the Node server starts:
    ````bash
    [output] {purple}Visualizations:
    [output]  ⁎  {green}radar-or-treemap {blue}https://onenr.io/012ab3cd4Ef
    ```

    ````
7.  Configure your visualization with an account ID and a query.
    With some required data for your chart to process, you now see a `RadarChart` with the `SegmentedControl` at the top of the view.
    Look at your browser's console to see your `SegmentedControl` logs.

## Connect your component's `state` to the `SegmentedControl` [#connect-component]

Add a method to update `state` and connect that method with the `SegmentedControl` you added in the last section.

1.  Add a component method, called `updateSelectedChart()`:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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>
    );
    ```

    This new method takes a `value` argument and sets `state.selectedChart` to that value.

    ````
2.  Set `SegmentedControl.onChange` to `updateSelectedChart()`:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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>
    );
    ```

    Now, when you change your selection in the `SegmentedControl`, your selection will be set in `state`.

    ````

## Implement a `Treemap` option [#implement-treemap]

Add a [`Treemap`](https://recharts.org/en-US/api/Treemap) to your visualization. This map will be an alternative to the existing `RadarChart`.

> #### 💡 TECHNICAL DETAIL
>
> This guide uses [Recharts](https://recharts.org) components for third-party charts, but you can use any other JavaScript charting libraries that are compatible with the current React version when you build New Relic visualizations and apps.

1.  Import `Treemap` from `recharts`:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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>
    );
    ```

    Now, you can use `Treemap` in your visualization component.

    ````
2.  In `render()`, add a `Treemap` component:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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>
    );
    ```

    Here, you've defined a new `Treemap` component with some props, including `height`, `width`, `fill`, and `stroke`.

    ````
3.  With your Nerdpack served locally, [view your visualization](https://one.newrelic.com?nerdpacks=local). The `SegmentedControl` and `RadarChart` are at the top of the view, but if you scroll down, you'll see your new `Treemap`.

## Switch between charts with your component's `state` [#switch-charts]

Use `state.selectedChart` to determine which chart to show: the `RadarChart` or the `Treemap`.

1.  Destructure `this.state` to access `selectedChart` as a separate constant. Then, compare `selectedChart` to `CHART_TYPES.Radar`. If they are the same, render a `RadarChart`. Otherwise, render a `Treemap`:
    ````jsx fileName=visualizations/radar-or-treemap/index.js
    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>
    );
    ```

    Here, you used a ternary expression to render a `RadarChart` or a `Treemap`. The rendered chart is determined by the value of `selectedChart`.

    ````
2.  With your Nerdpack served locally, [view your visualization](https://one.newrelic.com?nerdpacks=local).
    Select **Radar chart** from the `SegmentedControl`.
    Select **Treemap chart** from the `SegmentedControl`.

## Summary [#summary]

Congratulations! In this lesson, you learned how to:

-   Customize your visualization using New Relic One SDK components
-   Add a new chart type to your visualization
-   Create a user interaction in your visualization

> #### 💡 TIP
>
> This lesson is part of a course that teaches you how to build a custom visualization on the New Relic platform. When you're ready, continue on to the next lesson: [Customize visualizations with configuration](https://docs.newrelic.com/docs/new-relic-solutions/tutorials/custom-visualization-config).
