---
title: Your first custom visualization
source: https://docs.newrelic.com/docs/new-relic-solutions/build-nr-ui/custom-visualizations/build-visualization
---

Query data from any source and display it on your New Relic dashboard with custom visualizations.

In this guide, you learn how to:

-   Use the `nr1` CLI to generate a default visualization.
-   Run your visualization locally where you can quickly test and iterate.
-   Publish your visualization to the New Relic app catalog.
-   Add your visualization to a dashboard.

## Before you begin [#before]

If you haven't already:

-   Create a [New Relic account](https://newrelic.com/signup).
-   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 a new visualization [#create]

Use `nr1` to generate the boilerplate for a new visualization.

```jsx fileName=visualizations/my-awesome-visualization/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 MyAwesomeVisualizationVisualization 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>
);
```

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

    ````
2.  Create a visualization, called `my-awesome-visualization`, in a Nerdpack, called `my-awesome-nerdpack`:
    ````bash animate
    nr1 create --type visualization --name my-awesome-visualization
    [output] {success}✔  {plain}You are attempting to create a nerdlet outside of a nerdpack. We will create a nerdpack for you. What would you like to name it? ... my-awesome-nerdpack
    [output]
    [output] {success}✔  {plain}nerdpack created successfully!
    [output]    {purple}nerdpack {blue}my-awesome-nerdpack {plain}is available at {green}"./my-awesome-nerdpack"
    [output]
    [output] {success}✔  {plain}visualization created successfully!
    [output]    {purple}visualization {blue}my-awesome-visualization {plain}is available at {green}"./my-awesome-nerdpack/visualizations/my-awesome-visualization"
    ```

    ````

> #### 💡 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. Read more about this and other advanced configurations in [Enable advanced configurations for your Nerdpack](https://docs.newrelic.com/docs/new-relic-solutions/new-relic-one/build-nr-apps/advanced-config).

As a result, you have a new `visualizations/my-awesome-visualization` directory in `my-awesome-nerdpack`:

```bash animate
ls my-awesome-nerdpack/visualizations/my-awesome-visualization
[output] index.js    nr1.json    styles.scss
```

The top-level `visualizations` directory holds all of your Nerdpack's visualizations. The visualization you created is called `my-awesome-visualization`, and it has its own directory. The files in this directory provide an example visualization, a [`RadarChart`](https://recharts.org/en-US/api/RadarChart) populated by a basic [NRQL](https://docs.newrelic.com/docs/nrql/get-started/introduction-nrql-new-relics-query-language) query.

**Files**

-   `nr1.json` provides metadata for your visualization. The `configuration` key in this metadata defines the prop-input fields to be shown in the UI. To learn more about the options available under the `configuration` key, check out the [Configure your custom visualization](https://docs.newrelic.com/docs/new-relic-solutions/build-nr-ui/custom-visualizations/configuration-options).
-   `index.js` defines the React component that receives the props defined in `nr1.json` and renders your visualization. You can install and import any JavaScript libraries you find useful. The example component imports [Recharts](https://recharts.org), a library that wraps [D3](https://d3js.org) submodules for easy-to-compose visualizations.
-   `styles.scss` defines the [Sass](https://sass-lang.com) styles for your visualization.

## Serve your visualization locally

Serve your visualization locally, and view it in **Apps > Custom Visualizations**. There, you can quickly test changes to your code.

From the root directory of your Nerdpack, start a local Node server:

```bash
cd my-awesome-nerdpack
nr1 nerdpack:serve
```

While it's running, your local server recognizes changes to certain files, such as `index.js` and automatically refreshes your visualization. However, it doesn't recognize changes to `nr1.json` or `styles.scss`. Therefore, some changes, such as those to the definition of the `configuration` field in `nr1.json`, won't be reflected in your visualization until you restart your server. To see changes to those files, stop the server, with `CTRL+C`, and start it back up with `nr1 nerdpack:serve`.

Open the link to your visualization that's shown in the terminal when the Node server starts:

```sh
[output] {purple}Visualizations:
[output] ⁎  {green}my-awesome-visualization {blue}https://onenr.io/012ab3cd4Ef
```

Update the fields under **Configure visualization properties**, and watch your visualization update automatically:

To add more of these properties, update the `configuration` field in `nr1.json`, and restart your local server.

Configuring these properties is one way to update your visualization. Changing your React code is another.

In `index.js`, change your component's `Radar.fillOpacity`:

```jsx fileName=visualizations/my-awesome-visualization/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 MyAwesomeVisualizationVisualization 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={1.0}
                  />
                </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>
);
```

Look at your visualization in the New Relic platform to see the change.

Now you've seen how to:

-   Serve your visualization locally
-   View it in New Relic platform
-   Update the visualization with configurable properties and code changes

Once you've developed and configured a chart to show your data in an effective way, you can save that instance of the chart, complete with your configurations and the data or query, in a dashboard. However, you can't do this with a locally served visualization. You need to publish your visualization, first.

## Publish and use your visualization

To add an instance of your visualization to a dashboard, you first need to [publish your Nerdpack](https://docs.newrelic.com/docs/new-relic-solutions/new-relic-one/build-nr-apps/publish).

Publish your Nerdpack from its root directory:

```sh
nr1 nerdpack:publish
```

Look for a success message in your output:

```sh
[output] {success}✔{normal}  Nerdpack published successfully!
[output] {success}✔{normal}  Tagged {purple}5f4c2af8-3b27-40b5-954c-356d1ef88dd0{normal} version {blue}1.0.0{normal} as {blue}STABLE{normal}.
```

This means that your Nerdpack was published to the New Relic app catalog that you can find under **Apps**.

Subscribe to your Nerdpack:

```sh
nr1 nerdpack:subscribe
[output] Subscribed account {blue}3014918{normal} to the nerdpack {purple}5f4c2af8-3b27-40b5-954c-356d1ef88dd0{normal} on the {blue}STABLE{normal} channel.
```

Now, you're subscribed to your Nerdpack and can build an instance of a visualization in New Relic.

Once again, open the **Apps** page at [New Relic](https://one.newrelic.com):

Here, you don't need to use the `?nerdpacks=local` query string because you're looking for a visualization that you've published and subscribed to, rather than one that is locally served.

1.  Go to **Custom Visualizations**.

2.  Find and click your published visualization.

    You may have to refresh your browser page if you can't find your visualization. Notice that this new tile no longer has a **'/' Local** label. This is because you're looking at the visualization you published and subscribed to in the previous steps. If you're still serving your Nerdpack locally, you might see two tiles here, one with the label and one without it.

3.  Configure your visualization the same way you did when it was locally served.

4.  Click **Add to dashboard**. Follow the prompts to [add your visualization to a dashboard](https://docs.newrelic.com/docs/query-your-data/explore-query-data/dashboards/add-custom-visualizations-your-dashboards).

5.  From the homepage, go to **Dashboards** and select the dashboard you added your visualization to, and see your visualization in it.

## Summary

Congratulations on building your first visualization! In this guide, you learned how to:

-   Create a visualization
-   Serve your visualization locally
-   Iterate on visualization code changes and customizations in **Custom Visualizations**
-   Publish your visualization
-   Subscribe to your visualization
-   Add your visualization to a dashboard

## Additional resources

-   New Relic quick tips video: [Dashboards and Custom Visualizations](https://www.youtube.com/watch?v=_F61mxtKfGA) (6 minutes)
-   New Relic NerdBytes video: [Configuring custom visualizations for dashboards](https://www.youtube.com/watch?v=sFpG_iG7Xa8) (7 minutes)
-   New Relic Changelog live stream: [Custom Data Visualizations on New Relic](https://www.youtube.com/watch?v=HuR0EdHGz24) (30 minutes)
