• /
  • Log in

Customize your visualization with configuration options

10 min

Course

This lesson is part of a course that teaches you how to build a custom visualization in the New Relic One platform.

Each lesson in the course builds upon the last, so make sure you've completed the last lesson, Custom visualizations and the New Relic One SDK, before starting this one.

In the previous lesson, you built a custom visualization that shows queried data in one of two chart types:

You used a SegmentedControl to switch between the two chart types in the visualization UI. This implementation takes up space in the visualization, but it offers your users the choice to switch between two chart types even after you've created an instance of your chart. But what if you only need to be able to select an option once, when initializing the visualization?

In this lesson you'll learn how to add a configuration option to your visualization which replaces the SegmentedControl.

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 on Github.

Add a new configuration option

Step 1 of 8

In your visualization's nr1.json file, add an enum configuration object for selectedChart:

1
import React from 'react';
2
import PropTypes from 'prop-types';
3
import {
4
Radar,
5
RadarChart,
6
PolarGrid,
7
PolarAngleAxis,
8
PolarRadiusAxis,
9
Treemap,
10
} from 'recharts';
11
import {
12
AutoSizer,
13
Card,
14
CardBody,
15
HeadingText,
16
NrqlQuery,
17
SegmentedControl,
18
SegmentedControlItem,
19
Spinner,
20
} from 'nr1';
21
22
const CHART_TYPES = {
23
'Radar': 'radar',
24
'Treemap': 'treemap'
25
}
26
27
export default class RadarOrTreemapVisualization extends React.Component {
28
// Custom props you wish to be configurable in the UI must also be defined in
29
// the nr1.json file for the visualization. See docs for more details.
30
static propTypes = {
31
/**
32
* A fill color to override the default fill color. This is an example of
33
* a custom chart configuration.
34
*/
35
fill: PropTypes.string,
36
37
/**
38
* A stroke color to override the default stroke color. This is an example of
39
* a custom chart configuration.
40
*/
41
stroke: PropTypes.string,
42
/**
43
* An array of objects consisting of a nrql `query` and `accountId`.
44
* This should be a standard prop for any NRQL based visualizations.
45
*/
46
nrqlQueries: PropTypes.arrayOf(
47
PropTypes.shape({
48
accountId: PropTypes.number,
49
query: PropTypes.string,
50
})
51
),
52
};
53
54
state = {
55
selectedChart: CHART_TYPES.Radar,
56
};
57
58
/**
59
* Restructure the data for a non-time-series, facet-based NRQL query into a
60
* form accepted by the Recharts library's RadarChart.
61
* (https://recharts.org/api/RadarChart).
62
*/
63
transformData = (rawData) => {
64
return rawData.map((entry) => ({
65
name: entry.metadata.name,
66
// Only grabbing the first data value because this is not time-series data.
67
value: entry.data[0].y,
68
}));
69
};
70
71
/**
72
* Format the given axis tick's numeric value into a string for display.
73
*/
74
formatTick = (value) => {
75
return value.toLocaleString();
76
};
77
78
updateSelectedChart = (evt, value) => {
79
this.setState({ selectedChart: value })
80
};
81
82
render() {
83
const {nrqlQueries, stroke, fill} = this.props;
84
const {selectedChart} = this.state;
85
86
const nrqlQueryPropsAvailable =
87
nrqlQueries &&
88
nrqlQueries[0] &&
89
nrqlQueries[0].accountId &&
90
nrqlQueries[0].query;
91
92
if (!nrqlQueryPropsAvailable) {
93
return <EmptyState />;
94
}
95
96
return (
97
<AutoSizer>
98
{({width, height}) => (
99
<NrqlQuery
100
query={nrqlQueries[0].query}
101
accountId={parseInt(nrqlQueries[0].accountId)}
102
pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}
103
>
104
{({data, loading, error}) => {
105
if (loading) {
106
return <Spinner />;
107
}
108
109
if (error) {
110
return <ErrorState />;
111
}
112
113
const transformedData = this.transformData(data);
114
115
return (
116
<React.Fragment>
117
<SegmentedControl
118
onChange={this.updateSelectedChart}
119
>
120
<SegmentedControlItem
121
value={CHART_TYPES.Radar}
122
label="Radar chart"
123
/>
124
<SegmentedControlItem
125
value={CHART_TYPES.Treemap}
126
label="Treemap chart"
127
/>
128
</SegmentedControl>
129
{selectedChart === CHART_TYPES.Radar ? (
130
<RadarChart
131
width={width}
132
height={height}
133
data={transformedData}
134
>
135
<PolarGrid />
136
<PolarAngleAxis dataKey="name" />
137
<PolarRadiusAxis tickFormatter={this.formatTick} />
138
<Radar
139
dataKey="value"
140
stroke={stroke || '#51C9B7'}
141
fill={fill || '#51C9B7'}
142
fillOpacity={0.6}
143
/>
144
</RadarChart>
145
) : (
146
<Treemap
147
width={width}
148
height={height}
149
data={transformedData}
150
dataKey="value"
151
ratio={4 / 3}
152
stroke={stroke || '#000000'}
153
fill={fill || '#51C9B7'}
154
/>
155
)}
156
</React.Fragment>
157
);
158
}}
159
</NrqlQuery>
160
)}
161
</AutoSizer>
162
);
163
}
164
}
165
166
const EmptyState = () => (
167
<Card className="EmptyState">
168
<CardBody className="EmptyState-cardBody">
169
<HeadingText
170
spacingType={[HeadingText.SPACING_TYPE.LARGE]}
171
type={HeadingText.TYPE.HEADING_3}
172
>
173
Please provide at least one NRQL query & account ID pair
174
</HeadingText>
175
<HeadingText
176
spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}
177
type={HeadingText.TYPE.HEADING_4}
178
>
179
An example NRQL query you can try is:
180
</HeadingText>
181
<code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>
182
</CardBody>
183
</Card>
184
);
185
186
const ErrorState = () => (
187
<Card className="ErrorState">
188
<CardBody className="ErrorState-cardBody">
189
<HeadingText
190
className="ErrorState-headingText"
191
spacingType={[HeadingText.SPACING_TYPE.LARGE]}
192
type={HeadingText.TYPE.HEADING_3}
193
>
194
Oops! Something went wrong.
195
</HeadingText>
196
</CardBody>
197
</Card>
198
);
visualizations/radar-or-treemap/index.js
1
{
2
"schemaType": "VISUALIZATION",
3
"id": "radar-or-treemap",
4
"displayName": "RadarOrTreemap",
5
"description": "",
6
"configuration": [
7
{
8
"name": "selectedChart",
9
"title": "Select chart",
10
"description": "Select which chart to display",
11
"type": "enum",
12
"items": [
13
{
14
"title": "Radar",
15
"value": "radar"
16
},
17
{
18
"title": "Treemap",
19
"value": "treemap"
20
}
21
]
22
},
23
{
24
"name": "nrqlQueries",
25
"title": "NRQL Queries",
26
"type": "collection",
27
"items": [
28
{
29
"name": "accountId",
30
"title": "Account ID",
31
"description": "Account ID to be associated with the query",
32
"type": "account-id"
33
},
34
{
35
"name": "query",
36
"title": "Query",
37
"description": "NRQL query for visualization",
38
"type": "nrql"
39
}
40
]
41
},
42
{
43
"name": "fill",
44
"title": "Fill color",
45
"description": "A fill color to override the default fill color",
46
"type": "string"
47
},
48
{
49
"name": "stroke",
50
"title": "Stroke color",
51
"description": "A stroke color to override the default stroke color",
52
"type": "string"
53
}
54
]
55
}
visualizations/radar-or-treemap/nr1.json
Step 2 of 8

Navigate to the root of your Nerdpack at alternate-viz.

Step 3 of 8
bash
$
nr1 nerdpack:serve

If you're still serving your Nerdpack from the last lesson, you need to stop it with CTRL-X and serve it again to reflect changes to nr1.json.

Step 4 of 8

Go to https://one.newrelic.com/?nerdpacks=local. The nerdpacks=local query string directs the UI to load your visualization from the local server.

Step 5 of 8

Open the Apps page:

Apps navigation is located in the New Relic One top navigation

Step 6 of 8

Go to Custom Visualizations, which is favorited by default:

Navigate to Custom Visualizations

Step 7 of 8

In Custom Visualizations, find and click your visualization:

Navigate to your visualization

Step 8 of 8

Notice the new Select chart configuration option:

Select chart config option

Selecting a chart type doesn't effect your visualization. This is because you first need to introduce the selectedChart property to the visualization component. Then, you use selectedChart to determine the chart type to render.

Replace your SegmentedControl with the configurable property

Step 1 of 5

Open your visualization's index.js file. You'll be working here for the rest of the guide.

Step 2 of 5

In render(), include selectedChart as a constant you get from destructuring props, and remove your component's state:

1
import React from 'react';
2
import PropTypes from 'prop-types';
3
import {
4
Radar,
5
RadarChart,
6
PolarGrid,
7
PolarAngleAxis,
8
PolarRadiusAxis,
9
Treemap,
10
} from 'recharts';
11
import {
12
AutoSizer,
13
Card,
14
CardBody,
15
HeadingText,
16
NrqlQuery,
17
SegmentedControl,
18
SegmentedControlItem,
19
Spinner,
20
} from 'nr1';
21
22
const CHART_TYPES = {
23
'Radar': 'radar',
24
'Treemap': 'treemap'
25
}
26
27
export default class RadarOrTreemapVisualization extends React.Component {
28
// Custom props you wish to be configurable in the UI must also be defined in
29
// the nr1.json file for the visualization. See docs for more details.
30
static propTypes = {
31
/**
32
* A fill color to override the default fill color. This is an example of
33
* a custom chart configuration.
34
*/
35
fill: PropTypes.string,
36
37
/**
38
* A stroke color to override the default stroke color. This is an example of
39
* a custom chart configuration.
40
*/
41
stroke: PropTypes.string,
42
/**
43
* An array of objects consisting of a nrql `query` and `accountId`.
44
* This should be a standard prop for any NRQL based visualizations.
45
*/
46
nrqlQueries: PropTypes.arrayOf(
47
PropTypes.shape({
48
accountId: PropTypes.number,
49
query: PropTypes.string,
50
})
51
),
52
};
53
54
/**
55
* Restructure the data for a non-time-series, facet-based NRQL query into a
56
* form accepted by the Recharts library's RadarChart.
57
* (https://recharts.org/api/RadarChart).
58
*/
59
transformData = (rawData) => {
60
return rawData.map((entry) => ({
61
name: entry.metadata.name,
62
// Only grabbing the first data value because this is not time-series data.
63
value: entry.data[0].y,
64
}));
65
};
66
67
/**
68
* Format the given axis tick's numeric value into a string for display.
69
*/
70
formatTick = (value) => {
71
return value.toLocaleString();
72
};
73
74
render() {
75
const {nrqlQueries, stroke, fill, selectedChart} = this.props;
76
77
const nrqlQueryPropsAvailable =
78
nrqlQueries &&
79
nrqlQueries[0] &&
80
nrqlQueries[0].accountId &&
81
nrqlQueries[0].query;
82
83
if (!nrqlQueryPropsAvailable) {
84
return <EmptyState />;
85
}
86
87
return (
88
<AutoSizer>
89
{({width, height}) => (
90
<NrqlQuery
91
query={nrqlQueries[0].query}
92
accountId={parseInt(nrqlQueries[0].accountId)}
93
pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}
94
>
95
{({data, loading, error}) => {
96
if (loading) {
97
return <Spinner />;
98
}
99
100
if (error) {
101
return <ErrorState />;
102
}
103
104
const transformedData = this.transformData(data);
105
106
return (
107
<React.Fragment>
108
<SegmentedControl>
109
<SegmentedControlItem
110
value={CHART_TYPES.Radar}
111
label="Radar chart"
112
/>
113
<SegmentedControlItem
114
value={CHART_TYPES.Treemap}
115
label="Treemap chart"
116
/>
117
</SegmentedControl>
118
{selectedChart === CHART_TYPES.Radar ? (
119
<RadarChart
120
width={width}
121
height={height}
122
data={transformedData}
123
>
124
<PolarGrid />
125
<PolarAngleAxis dataKey="name" />
126
<PolarRadiusAxis tickFormatter={this.formatTick} />
127
<Radar
128
dataKey="value"
129
stroke={stroke || '#51C9B7'}
130
fill={fill || '#51C9B7'}
131
fillOpacity={0.6}
132
/>
133
</RadarChart>
134
) : (
135
<Treemap
136
width={width}
137
height={height}
138
data={transformedData}
139
dataKey="value"
140
ratio={4 / 3}
141
stroke={stroke || '#000000'}
142
fill={fill || '#51C9B7'}
143
/>
144
)}
145
</React.Fragment>
146
);
147
}}
148
</NrqlQuery>
149
)}
150
</AutoSizer>
151
);
152
}
153
}
154
155
const EmptyState = () => (
156
<Card className="EmptyState">
157
<CardBody className="EmptyState-cardBody">
158
<HeadingText
159
spacingType={[HeadingText.SPACING_TYPE.LARGE]}
160
type={HeadingText.TYPE.HEADING_3}
161
>
162
Please provide at least one NRQL query & account ID pair
163
</HeadingText>
164
<HeadingText
165
spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}
166
type={HeadingText.TYPE.HEADING_4}
167
>
168
An example NRQL query you can try is:
169
</HeadingText>
170
<code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>
171
</CardBody>
172
</Card>
173
);
174
175
const ErrorState = () => (
176
<Card className="ErrorState">
177
<CardBody className="ErrorState-cardBody">
178
<HeadingText
179
className="ErrorState-headingText"
180
spacingType={[HeadingText.SPACING_TYPE.LARGE]}
181
type={HeadingText.TYPE.HEADING_3}
182
>
183
Oops! Something went wrong.
184
</HeadingText>
185
</CardBody>
186
</Card>
187
);
visualizations/radar-or-treemap/index.js
1
{
2
"schemaType": "VISUALIZATION",
3
"id": "radar-or-treemap",
4
"displayName": "RadarOrTreemap",
5
"description": "",
6
"configuration": [
7
{
8
"name": "selectedChart",
9
"title": "Select chart",
10
"description": "Select which chart to display",
11
"type": "enum",
12
"items": [
13
{
14
"title": "Radar",
15
"value": "radar"
16
},
17
{
18
"title": "Treemap",
19
"value": "treemap"
20
}
21
]
22
},
23
{
24
"name": "nrqlQueries",
25
"title": "NRQL Queries",
26
"type": "collection",
27
"items": [
28
{
29
"name": "accountId",
30
"title": "Account ID",
31
"description": "Account ID to be associated with the query",
32
"type": "account-id"
33
},
34
{
35
"name": "query",
36
"title": "Query",
37
"description": "NRQL query for visualization",
38
"type": "nrql"
39
}
40
]
41
},
42
{
43
"name": "fill",
44
"title": "Fill color",
45
"description": "A fill color to override the default fill color",
46
"type": "string"
47
},
48
{
49
"name": "stroke",
50
"title": "Stroke color",
51
"description": "A stroke color to override the default stroke color",
52
"type": "string"
53
}
54
]
55
}
visualizations/radar-or-treemap/nr1.json

Now that you're using selectedChart from the configuration options instead of component state, you can select a chart in the configuration panel and watch the visualization change. Unfortunately, there's a bug. The default chart option is Radar, but the initial render shows a Treemap.

Step 3 of 5

Update your ternary expression to account for the case where there is no selectedChart:

1
import React from 'react';
2
import PropTypes from 'prop-types';
3
import {
4
Radar,
5
RadarChart,
6
PolarGrid,
7
PolarAngleAxis,
8
PolarRadiusAxis,
9
Treemap,
10
} from 'recharts';
11
import {
12
AutoSizer,
13
Card,
14
CardBody,
15
HeadingText,
16
NrqlQuery,
17
SegmentedControl,
18
SegmentedControlItem,
19
Spinner,
20
} from 'nr1';
21
22
const CHART_TYPES = {
23
'Radar': 'radar',
24
'Treemap': 'treemap'
25
}
26
27
export default class RadarOrTreemapVisualization extends React.Component {
28
// Custom props you wish to be configurable in the UI must also be defined in
29
// the nr1.json file for the visualization. See docs for more details.
30
static propTypes = {
31
/**
32
* A fill color to override the default fill color. This is an example of
33
* a custom chart configuration.
34
*/
35
fill: PropTypes.string,
36
37
/**
38
* A stroke color to override the default stroke color. This is an example of
39
* a custom chart configuration.
40
*/
41
stroke: PropTypes.string,
42
/**
43
* An array of objects consisting of a nrql `query` and `accountId`.
44
* This should be a standard prop for any NRQL based visualizations.
45
*/
46
nrqlQueries: PropTypes.arrayOf(
47
PropTypes.shape({
48
accountId: PropTypes.number,
49
query: PropTypes.string,
50
})
51
),
52
};
53
54
/**
55
* Restructure the data for a non-time-series, facet-based NRQL query into a
56
* form accepted by the Recharts library's RadarChart.
57
* (https://recharts.org/api/RadarChart).
58
*/
59
transformData = (rawData) => {
60
return rawData.map((entry) => ({
61
name: entry.metadata.name,
62
// Only grabbing the first data value because this is not time-series data.
63
value: entry.data[0].y,
64
}));
65
};
66
67
/**
68
* Format the given axis tick's numeric value into a string for display.
69
*/
70
formatTick = (value) => {
71
return value.toLocaleString();
72
};
73
74
render() {
75
const {nrqlQueries, stroke, fill, selectedChart} = this.props;
76
77
const nrqlQueryPropsAvailable =
78
nrqlQueries &&
79
nrqlQueries[0] &&
80
nrqlQueries[0].accountId &&
81
nrqlQueries[0].query;
82
83
if (!nrqlQueryPropsAvailable) {
84
return <EmptyState />;
85
}
86
87
return (
88
<AutoSizer>
89
{({width, height}) => (
90
<NrqlQuery
91
query={nrqlQueries[0].query}
92
accountId={parseInt(nrqlQueries[0].accountId)}
93
pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}
94
>
95
{({data, loading, error}) => {
96
if (loading) {
97
return <Spinner />;
98
}
99
100
if (error) {
101
return <ErrorState />;
102
}
103
104
const transformedData = this.transformData(data);
105
106
return (
107
<React.Fragment>
108
<SegmentedControl>
109
<SegmentedControlItem
110
value={CHART_TYPES.Radar}
111
label="Radar chart"
112
/>
113
<SegmentedControlItem
114
value={CHART_TYPES.Treemap}
115
label="Treemap chart"
116
/>
117
</SegmentedControl>
118
{!selectedChart || selectedChart === CHART_TYPES.Radar ? (
119
<RadarChart
120
width={width}
121
height={height}
122
data={transformedData}
123
>
124
<PolarGrid />
125
<PolarAngleAxis dataKey="name" />
126
<PolarRadiusAxis tickFormatter={this.formatTick} />
127
<Radar
128
dataKey="value"
129
stroke={stroke || '#51C9B7'}
130
fill={fill || '#51C9B7'}
131
fillOpacity={0.6}
132
/>
133
</RadarChart>
134
) : (
135
<Treemap
136
width={width}
137
height={height}
138
data={transformedData}
139
dataKey="value"
140
ratio={4 / 3}
141
stroke={stroke || '#000000'}
142
fill={fill || '#51C9B7'}
143
/>
144
)}
145
</React.Fragment>
146
);
147
}}
148
</NrqlQuery>
149
)}
150
</AutoSizer>
151
);
152
}
153
}
154
155
const EmptyState = () => (
156
<Card className="EmptyState">
157
<CardBody className="EmptyState-cardBody">
158
<HeadingText
159
spacingType={[HeadingText.SPACING_TYPE.LARGE]}
160
type={HeadingText.TYPE.HEADING_3}
161
>
162
Please provide at least one NRQL query & account ID pair
163
</HeadingText>
164
<HeadingText
165
spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}
166
type={HeadingText.TYPE.HEADING_4}
167
>
168
An example NRQL query you can try is:
169
</HeadingText>
170
<code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>
171
</CardBody>
172
</Card>
173
);
174
175
const ErrorState = () => (
176
<Card className="ErrorState">
177
<CardBody className="ErrorState-cardBody">
178
<HeadingText
179
className="ErrorState-headingText"
180
spacingType={[HeadingText.SPACING_TYPE.LARGE]}
181
type={HeadingText.TYPE.HEADING_3}
182
>
183
Oops! Something went wrong.
184
</HeadingText>
185
</CardBody>
186
</Card>
187
);
visualizations/radar-or-treemap/index.js
1
{
2
"schemaType": "VISUALIZATION",
3
"id": "radar-or-treemap",
4
"displayName": "RadarOrTreemap",
5
"description": "",
6
"configuration": [
7
{
8
"name": "selectedChart",
9
"title": "Select chart",
10
"description": "Select which chart to display",
11
"type": "enum",
12
"items": [
13
{
14
"title": "Radar",
15
"value": "radar"
16
},
17
{
18
"title": "Treemap",
19
"value": "treemap"
20
}
21
]
22
},
23
{
24
"name": "nrqlQueries",
25
"title": "NRQL Queries",
26
"type": "collection",
27
"items": [
28
{
29
"name": "accountId",
30
"title": "Account ID",
31
"description": "Account ID to be associated with the query",
32
"type": "account-id"
33
},
34
{
35
"name": "query",
36
"title": "Query",
37
"description": "NRQL query for visualization",
38
"type": "nrql"
39
}
40
]
41
},
42
{
43
"name": "fill",
44
"title": "Fill color",
45
"description": "A fill color to override the default fill color",
46
"type": "string"
47
},
48
{
49
"name": "stroke",
50
"title": "Stroke color",
51
"description": "A stroke color to override the default stroke color",
52
"type": "string"
53
}
54
]
55
}
visualizations/radar-or-treemap/nr1.json

Now, your data is rendered in a RadarChart if you haven't yet configured the option.

Step 4 of 5

Remove SegmentedControl from render():

1
import React from 'react';
2
import PropTypes from 'prop-types';
3
import {
4
Radar,
5
RadarChart,
6
PolarGrid,
7
PolarAngleAxis,
8
PolarRadiusAxis,
9
Treemap,
10
} from 'recharts';
11
import {
12
AutoSizer,
13
Card,
14
CardBody,
15
HeadingText,
16
NrqlQuery,
17
Spinner,
18
} from 'nr1';
19
20
const CHART_TYPES = {
21
'Radar': 'radar',
22
'Treemap': 'treemap'
23
}
24
25
export default class RadarOrTreemapVisualization extends React.Component {
26
// Custom props you wish to be configurable in the UI must also be defined in
27
// the nr1.json file for the visualization. See docs for more details.
28
static propTypes = {
29
/**
30
* A fill color to override the default fill color. This is an example of
31
* a custom chart configuration.
32
*/
33
fill: PropTypes.string,
34
35
/**
36
* A stroke color to override the default stroke color. This is an example of
37
* a custom chart configuration.
38
*/
39
stroke: PropTypes.string,
40
/**
41
* An array of objects consisting of a nrql `query` and `accountId`.
42
* This should be a standard prop for any NRQL based visualizations.
43
*/
44
nrqlQueries: PropTypes.arrayOf(
45
PropTypes.shape({
46
accountId: PropTypes.number,
47
query: PropTypes.string,
48
})
49
),
50
};
51
52
/**
53
* Restructure the data for a non-time-series, facet-based NRQL query into a
54
* form accepted by the Recharts library's RadarChart.
55
* (https://recharts.org/api/RadarChart).
56
*/
57
transformData = (rawData) => {
58
return rawData.map((entry) => ({
59
name: entry.metadata.name,
60
// Only grabbing the first data value because this is not time-series data.
61
value: entry.data[0].y,
62
}));
63
};
64
65
/**
66
* Format the given axis tick's numeric value into a string for display.
67
*/
68
formatTick = (value) => {
69
return value.toLocaleString();
70
};
71
72
render() {
73
const {nrqlQueries, stroke, fill, selectedChart} = this.props;
74
75
const nrqlQueryPropsAvailable =
76
nrqlQueries &&
77
nrqlQueries[0] &&
78
nrqlQueries[0].accountId &&
79
nrqlQueries[0].query;
80
81
if (!nrqlQueryPropsAvailable) {
82
return <EmptyState />;
83
}
84
85
return (
86
<AutoSizer>
87
{({width, height}) => (
88
<NrqlQuery
89
query={nrqlQueries[0].query}
90
accountId={parseInt(nrqlQueries[0].accountId)}
91
pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}
92
>
93
{({data, loading, error}) => {
94
if (loading) {
95
return <Spinner />;
96
}
97
98
if (error) {
99
return <ErrorState />;
100
}
101
102
const transformedData = this.transformData(data);
103
104
return (
105
<React.Fragment>
106
{!selectedChart || selectedChart === CHART_TYPES.Radar ? (
107
<RadarChart
108
width={width}
109
height={height}
110
data={transformedData}
111
>
112
<PolarGrid />
113
<PolarAngleAxis dataKey="name" />
114
<PolarRadiusAxis tickFormatter={this.formatTick} />
115
<Radar
116
dataKey="value"
117
stroke={stroke || '#51C9B7'}
118
fill={fill || '#51C9B7'}
119
fillOpacity={0.6}
120
/>
121
</RadarChart>
122
) : (
123
<Treemap
124
width={width}
125
height={height}
126
data={transformedData}
127
dataKey="value"
128
ratio={4 / 3}
129
stroke={stroke || '#000000'}
130
fill={fill || '#51C9B7'}
131
/>
132
)}
133
</React.Fragment>
134
);
135
}}
136
</NrqlQuery>
137
)}
138
</AutoSizer>
139
);
140
}
141
}
142
143
const EmptyState = () => (
144
<Card className="EmptyState">
145
<CardBody className="EmptyState-cardBody">
146
<HeadingText
147
spacingType={[HeadingText.SPACING_TYPE.LARGE]}
148
type={HeadingText.TYPE.HEADING_3}
149
>
150
Please provide at least one NRQL query & account ID pair
151
</HeadingText>
152
<HeadingText
153
spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}
154
type={HeadingText.TYPE.HEADING_4}
155
>
156
An example NRQL query you can try is:
157
</HeadingText>
158
<code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>
159
</CardBody>
160
</Card>
161
);
162
163
const ErrorState = () => (
164
<Card className="ErrorState">
165
<CardBody className="ErrorState-cardBody">
166
<HeadingText
167
className="ErrorState-headingText"
168
spacingType={[HeadingText.SPACING_TYPE.LARGE]}
169
type={HeadingText.TYPE.HEADING_3}
170
>
171
Oops! Something went wrong.
172
</HeadingText>
173
</CardBody>
174
</Card>
175
);
visualizations/radar-or-treemap/index.js
1
{
2
"schemaType": "VISUALIZATION",
3
"id": "radar-or-treemap",
4
"displayName": "RadarOrTreemap",
5
"description": "",
6
"configuration": [
7
{
8
"name": "selectedChart",
9
"title": "Select chart",
10
"description": "Select which chart to display",
11
"type": "enum",
12
"items": [
13
{
14
"title": "Radar",
15
"value": "radar"
16
},
17
{
18
"title": "Treemap",
19
"value": "treemap"
20
}
21
]
22
},
23
{
24
"name": "nrqlQueries",
25
"title": "NRQL Queries",
26
"type": "collection",
27
"items": [
28
{
29
"name": "accountId",
30
"title": "Account ID",
31
"description": "Account ID to be associated with the query",
32
"type": "account-id"
33
},
34
{
35
"name": "query",
36
"title": "Query",
37
"description": "NRQL query for visualization",
38
"type": "nrql"
39
}
40
]
41
},
42
{
43
"name": "fill",
44
"title": "Fill color",
45
"description": "A fill color to override the default fill color",
46
"type": "string"
47
},
48
{
49
"name": "stroke",
50
"title": "Stroke color",
51
"description": "A stroke color to override the default stroke color",
52
"type": "string"
53
}
54
]
55
}
visualizations/radar-or-treemap/nr1.json
Step 5 of 5

Serve your Nerdpack locally, and view it in the Custom Visualizations app in New Relic. Select a chart type from the dropdown in the configuration sidebar, and see your visualization update to show the matching chart type:

Configured visualization

Summary

Congratulations on completing this lesson! You've learned how to customize your visualization using nr1.json configuration.

Course

This lesson is part of a course that teaches you how to build a custom visualization in the New Relic One platform. When you're ready, continue on to the next lesson: Add custom visualizations to your dashboards.

Create issueEdit page
Copyright © 2021 New Relic Inc.