Course
This lesson is part of a course that teaches you how to build a custom visualization on the New Relic 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
In your visualization's nr1.json file, add an enum
configuration object for selectedChart
:
1import React from 'react';2import PropTypes from 'prop-types';3import {4 Radar,5 RadarChart,6 PolarGrid,7 PolarAngleAxis,8 PolarRadiusAxis,9 Treemap,10} from 'recharts';11import {12 AutoSizer,13 Card,14 CardBody,15 HeadingText,16 NrqlQuery,17 SegmentedControl,18 SegmentedControlItem,19 Spinner,20} from 'nr1';21
22const CHART_TYPES = {23 Radar: 'radar',24 Treemap: 'treemap',25};26
27export default class RadarOrTreemapVisualization extends React.Component {28 // Custom props you wish to be configurable in the UI must also be defined in29 // 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 of33 * 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 of39 * 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 a60 * 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 <NrqlQuery100 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 onChange={this.updateSelectedChart}>118 <SegmentedControlItem119 value={CHART_TYPES.Radar}120 label="Radar chart"121 />122 <SegmentedControlItem123 value={CHART_TYPES.Treemap}124 label="Treemap chart"125 />126 </SegmentedControl>127 {selectedChart === CHART_TYPES.Radar ? (128 <RadarChart129 width={width}130 height={height}131 data={transformedData}132 >133 <PolarGrid />134 <PolarAngleAxis dataKey="name" />135 <PolarRadiusAxis tickFormatter={this.formatTick} />136 <Radar137 dataKey="value"138 stroke={stroke || '#51C9B7'}139 fill={fill || '#51C9B7'}140 fillOpacity={0.6}141 />142 </RadarChart>143 ) : (144 <Treemap145 width={width}146 height={height}147 data={transformedData}148 dataKey="value"149 ratio={4 / 3}150 stroke={stroke || '#000000'}151 fill={fill || '#51C9B7'}152 />153 )}154 </React.Fragment>155 );156 }}157 </NrqlQuery>158 )}159 </AutoSizer>160 );161 }162}163
164const EmptyState = () => (165 <Card className="EmptyState">166 <CardBody className="EmptyState-cardBody">167 <HeadingText168 spacingType={[HeadingText.SPACING_TYPE.LARGE]}169 type={HeadingText.TYPE.HEADING_3}170 >171 Please provide at least one NRQL query & account ID pair172 </HeadingText>173 <HeadingText174 spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}175 type={HeadingText.TYPE.HEADING_4}176 >177 An example NRQL query you can try is:178 </HeadingText>179 <code>FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago</code>180 </CardBody>181 </Card>182);183
184const ErrorState = () => (185 <Card className="ErrorState">186 <CardBody className="ErrorState-cardBody">187 <HeadingText188 className="ErrorState-headingText"189 spacingType={[HeadingText.SPACING_TYPE.LARGE]}190 type={HeadingText.TYPE.HEADING_3}191 >192 Oops! Something went wrong.193 </HeadingText>194 </CardBody>195 </Card>196);
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}
Navigate to the root of your Nerdpack at alternate-viz.
$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.
Go to https://one.newrelic.com/?nerdpacks=local. The nerdpacks=local
query string directs the UI to load your visualization from the local server.
Open the Apps page:
Go to Custom Visualizations, which is favorited by default:
In Custom Visualizations, find and click your visualization:
Notice the new Select chart configuration 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
Open your visualization's index.js file. You'll be working here for the rest of the guide.
In render()
, include selectedChart
as a constant you get from destructuring props
, and remove your component's state
:
1import React from 'react';2import PropTypes from 'prop-types';3import {4 Radar,5 RadarChart,6 PolarGrid,7 PolarAngleAxis,8 PolarRadiusAxis,9 Treemap,10} from 'recharts';11import {12 AutoSizer,13 Card,14 CardBody,15 HeadingText,16 NrqlQuery,17 SegmentedControl,18 SegmentedControlItem,19 Spinner,20} from 'nr1';21
22const CHART_TYPES = {23 Radar: 'radar',24 Treemap: 'treemap',25};26
27export default class RadarOrTreemapVisualization extends React.Component {28 // Custom props you wish to be configurable in the UI must also be defined in29 // 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 of33 * 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 of39 * 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 a56 * 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 <NrqlQuery91 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 <SegmentedControlItem110 value={CHART_TYPES.Radar}111 label="Radar chart"112 />113 <SegmentedControlItem114 value={CHART_TYPES.Treemap}115 label="Treemap chart"116 />117 </SegmentedControl>118 {selectedChart === CHART_TYPES.Radar ? (119 <RadarChart120 width={width}121 height={height}122 data={transformedData}123 >124 <PolarGrid />125 <PolarAngleAxis dataKey="name" />126 <PolarRadiusAxis tickFormatter={this.formatTick} />127 <Radar128 dataKey="value"129 stroke={stroke || '#51C9B7'}130 fill={fill || '#51C9B7'}131 fillOpacity={0.6}132 />133 </RadarChart>134 ) : (135 <Treemap136 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
155const EmptyState = () => (156 <Card className="EmptyState">157 <CardBody className="EmptyState-cardBody">158 <HeadingText159 spacingType={[HeadingText.SPACING_TYPE.LARGE]}160 type={HeadingText.TYPE.HEADING_3}161 >162 Please provide at least one NRQL query & account ID pair163 </HeadingText>164 <HeadingText165 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
175const ErrorState = () => (176 <Card className="ErrorState">177 <CardBody className="ErrorState-cardBody">178 <HeadingText179 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);
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}
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.
Update your ternary expression to account for the case where there is no selectedChart
:
1import React from 'react';2import PropTypes from 'prop-types';3import {4 Radar,5 RadarChart,6 PolarGrid,7 PolarAngleAxis,8 PolarRadiusAxis,9 Treemap,10} from 'recharts';11import {12 AutoSizer,13 Card,14 CardBody,15 HeadingText,16 NrqlQuery,17 SegmentedControl,18 SegmentedControlItem,19 Spinner,20} from 'nr1';21
22const CHART_TYPES = {23 Radar: 'radar',24 Treemap: 'treemap',25};26
27export default class RadarOrTreemapVisualization extends React.Component {28 // Custom props you wish to be configurable in the UI must also be defined in29 // 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 of33 * 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 of39 * 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 a56 * 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 <NrqlQuery91 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 <SegmentedControlItem110 value={CHART_TYPES.Radar}111 label="Radar chart"112 />113 <SegmentedControlItem114 value={CHART_TYPES.Treemap}115 label="Treemap chart"116 />117 </SegmentedControl>118 {!selectedChart || selectedChart === CHART_TYPES.Radar ? (119 <RadarChart120 width={width}121 height={height}122 data={transformedData}123 >124 <PolarGrid />125 <PolarAngleAxis dataKey="name" />126 <PolarRadiusAxis tickFormatter={this.formatTick} />127 <Radar128 dataKey="value"129 stroke={stroke || '#51C9B7'}130 fill={fill || '#51C9B7'}131 fillOpacity={0.6}132 />133 </RadarChart>134 ) : (135 <Treemap136 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
155const EmptyState = () => (156 <Card className="EmptyState">157 <CardBody className="EmptyState-cardBody">158 <HeadingText159 spacingType={[HeadingText.SPACING_TYPE.LARGE]}160 type={HeadingText.TYPE.HEADING_3}161 >162 Please provide at least one NRQL query & account ID pair163 </HeadingText>164 <HeadingText165 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
175const ErrorState = () => (176 <Card className="ErrorState">177 <CardBody className="ErrorState-cardBody">178 <HeadingText179 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);
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}
Now, your data is rendered in a RadarChart
if you haven't yet configured the option.
Remove SegmentedControl
from render()
:
1import React from 'react';2import PropTypes from 'prop-types';3import {4 Radar,5 RadarChart,6 PolarGrid,7 PolarAngleAxis,8 PolarRadiusAxis,9 Treemap,10} from 'recharts';11import {12 AutoSizer,13 Card,14 CardBody,15 HeadingText,16 NrqlQuery,17 Spinner,18} from 'nr1';19
20const CHART_TYPES = {21 Radar: 'radar',22 Treemap: 'treemap',23};24
25export default class RadarOrTreemapVisualization extends React.Component {26 // Custom props you wish to be configurable in the UI must also be defined in27 // 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 of31 * 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 of37 * 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 a54 * 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 <NrqlQuery89 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 <RadarChart108 width={width}109 height={height}110 data={transformedData}111 >112 <PolarGrid />113 <PolarAngleAxis dataKey="name" />114 <PolarRadiusAxis tickFormatter={this.formatTick} />115 <Radar116 dataKey="value"117 stroke={stroke || '#51C9B7'}118 fill={fill || '#51C9B7'}119 fillOpacity={0.6}120 />121 </RadarChart>122 ) : (123 <Treemap124 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
143const EmptyState = () => (144 <Card className="EmptyState">145 <CardBody className="EmptyState-cardBody">146 <HeadingText147 spacingType={[HeadingText.SPACING_TYPE.LARGE]}148 type={HeadingText.TYPE.HEADING_3}149 >150 Please provide at least one NRQL query & account ID pair151 </HeadingText>152 <HeadingText153 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
163const ErrorState = () => (164 <Card className="ErrorState">165 <CardBody className="ErrorState-cardBody">166 <HeadingText167 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);
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}
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:
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 on the New Relic platform. When you're ready, continue on to the next lesson: Add custom visualizations to your dashboards.