Now for something completely different. A helicorder style plot is a nice way to quickly look at a large amount of data from a single station, usually a entire day, by breaking it into multiple lines. A common style is 12 lines each covering 2 hours. First we need to get the data, but to illustrate another technique for finding services, we will use the FDSN Datacenter Registry to find the IRIS dataselect web service. As before, we need to create a div to put it in, and we add some headers with spans to label it.
<h3>A Helicorder for <span id="channel"></span>!</h3>
<h5>From <span id="starttime"></span> to <span id="endtime"></span></h5>
<div id="helicorder">
</div>
We also need a little styling to size the div.
div#helicorder {
height: 600px;
}
A little trickery finds the end time that is an even hour boundary, so that if the current time is 10:45, we will make the plot go to 12:00 instead of just 11:00, keeping each line"s hour to an even value. You can create a custom query to the FDSN Datacenters Registry, but there is a convenience method to just get standard FDSN web services. So, we will just get the first fdsn-dataselect web service that we find in the IRISDMC datacenter. Being a remote operation, this also returns a Promise.
const plotEnd = sp.luxon.DateTime.utc().endOf("hour").plus({ milliseconds: 1 });
if (plotEnd.hour % 2 === 1) {
plotEnd.plus({ hours: 1 });
}
const oneDay = sp.luxon.Duration.fromISO("P1D");
const timeWindow = sp.util.durationEnd(oneDay, plotEnd);
const luxOpts = {
suppressMilliseconds: true,
suppressSeconds: true,
};
document.querySelector("span#starttime").textContent =
timeWindow.start.toISO(luxOpts);
document.querySelector("span#endtime").textContent =
timeWindow.end.toISO(luxOpts);
new sp.fdsndatacenters.DataCentersQuery()
.findFdsnDataSelect("IRISDMC")
In the then method of the Promise from findFdsnDataSelect, we
construct our dataselect query. Because the helicorder will need
24 hours of data, it is probably best not to try this on a 100
samples per second HHZ channel, but a 1 sample per second LHZ
channel should be fine. The
querySeismograms()
method of course returns a Promise.
.then((dataSelectArray) => {
return dataSelectArray[0]
.networkCode("CO")
.stationCode("JSC")
.locationCode("00")
.channelCode("LHZ")
.timeRange(timeWindow)
.querySeismograms();
In the following
then
method, we populate out text spans and then configure our
helicorder. One extra bit we add is a marker for the current time.
Since each line is 2 hours, without this marker it is hard to know
if the station is way behind or if we are just in the middle of a
two hour section, so adding a marker helps. Lastly, we draw the
helicorder. If any errors occur, the
catch
is invoked that should output an error message to the page.
})
.then((seisArray) => {
document.querySelector("span#channel").textContent = seisArray[0].codes();
let heliConfig = new sp.helicorder.HelicorderConfig(timeWindow);
heliConfig.title = `Helicorder for ${seisArray[0].codes()}`;
let seisData = sp.seismogram.SeismogramDisplayData.fromSeismogram(
seisArray[0],
);
seisData.addMarkers([
{ markertype: "predicted", name: "now", time: sp.luxon.DateTime.utc() },
]);
let helicorder = new sp.helicorder.Helicorder(seisData, heliConfig);
document.querySelector("div#helicorder").append(helicorder);
helicorder.draw();
})
.catch(function (error) {
const p = document.createElement("p");
document.querySelector("div#helicorder").appendChild(p);
p.textContent = "Error loading data." + error;
console.assert(false, error);
});
Previous: Deconvolution and Filtering
Next: Realtime Data