Building Charts with Arcade¶
Communicative and effective map viewer popups are essential for any good map-centric COTS web app. Configuration specialists are accustomed to utilizing HTML, CSS, and ArcGIS Arcade to extend what's possible out of the box. Arcade isn't limited to just text formatting and conditional logic though - the expression language can be used to create complex chart visualizations1 from input data directly in the popups.
Use Case¶
As part of the solution built for the Missouri Hydrology Information Center in 2025, I built two web apps using Experience Builder to visualize stream gage data. In these apps, we wanted to build a line chart in the web map popup that could be docked in a Feature Info widget. Explore the flood-focused app here - click on a streamgage to see the chart powered by Arcade.
The Code¶
Dissecting Further¶
Data Setup¶
I first set up an empty attributes dictionary and thirFieldInfos array that will store the needed values for my chart. I create a variable thirDays to serve as a where clause to filter my data later:
var thirDays = DateAdd(currDate, -30, "days")
This example works with a related table data strucutre, in which I have a parent stream gage point hosted feature layer in ArcGIS Online with a related Gage_Readings table. The Gage_Readings table stores stream gage height values every hour. Therefore, I create a FeatureSet fs and filter it with my thirDays where clause I created earlier:
var thirFs = Filter(fs, 'Time >= @thirDays')
Looping Through¶
I set up a for loop to iterate over each feature (or row) in the thirFs FeatureSet I've already filtered:
for (var item in thirFs)
I read the stage height in feet of the current gage reading:
var thirStage = item["Stage_ft"]
I set up a guard to remove null values in the streamgage network. This dataset inconsistently had values in the millions or -999 to indicate nulls:
if (thirStage < 10000000 && thirStage > -999)
I format the reading's timestamp into month/day/four digit year hour:minute AM/PM format:
var thirTimex = Text(item["Time"], "M/DD/YYYY h:mm A")
I map the formatted thirTimex string to the thirStage value with a key-value pair:
attributes[thirTimex] = thirStage
Finally, I append the time string into the thirFieldInfos array I created earlier:
Push(thirFieldInfos, thirTimex)
Output¶
Why do we need a dictionary and an array in the first place? In the return statement, we need both an attributes dictionary that contains name/value pairs to supply the chart's data points AND a fields array that contains ordered keys referncing which attribtues to plot. The fields array goes inside the mediaInfo object.
Small detail - notice the colors array in the mediaInfo object. We use this to set the color of the chart in rgba format (I didn't need the alpha value in this example).
End Result¶
The end result is a simple, clean line chart showing stream height over the past 30 days. This chart has a built-in hover effect for users to explore height through time. Notice the altText property that has been included in an effort to make this COTS solution more accessible.