It would be nicer if we could add some useful labels to this instead
of just a raw seismogram. Perhaps getting some information about
this particular earthquake and the station it was recorded at. We
will use the IRIS
FDSNWS
station
web service to get the station and channels and the USGS
FDSNWS
event
web service to get the earthquake. Since we will have the
locations for the quake and station, we might as well plot them on a
map. We can use
Leaflet
, a
javascript map library
that creates nice looking maps and has lots of flexibility, for this.
Seisplotjs includes leaflet and provides helper functions in the
seisplotjs.leafletutil
module.
We can add some additional styling to size the map. Because the quake and the station are more or less east west of each other, we can use a map that is relatively narrow vertically, but spans the entire window.
<style>
sp-station-quake-map {
height: 300px;
width: 90%;
}
sp-seismograph {
height: 300px;
}
</style>
First, we will create the map in the html, centering it on 34/-100 and at zoom level 5. The World Ocean Base tile layer gives a nice background.
<sp-station-quake-map centerLat="34" centerLon="-100" zoomLevel="5" fitBounds="false"
tileUrl="https://services.arcgisonline.com/arcgis/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{z}/{y}/{x}"
tileAttribution="Tiles © Esri — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri" >
</sp-station-quake-map>
The markers on the map can also be styled with css, using the
quakeMarker
and
stationMarker
selectors. However, because we are using
custom HTML elements
, they
are insulated from the CSS in the containing page, so we have to inject
the CSS into the element. Many of the seisplotjs elements have a
addStyle()
method that will
put the CSS into the correct place.
We will change the color from the default red and blue to illustrate. Note that the station icon is actually a div that contains a triangle unicode character, \u25B2, while the quake marker is a circle created from an svg path element and so we use stoke and fill instead of color.
const mymap = document.querySelector('sp-station-quake-map');
mymap.addStyle(`
div.stationMapMarker {
color: rebeccapurple;
}
path.quakeMapMarker {
fill: orange;
stroke: yellow;
fill-opacity: 0.25;
}
`);
Then we will create the queries for the quake and station.
Again, both of these queries
are asynchronous and so we will have to use promises. We first create
both the
EventQuery
and
StationQuery
objects. The time range on the event query means the earthquake happened
within the window, but for the station query it means the station was
active (or at least existed) during some part of the window, i.e. it overlaps.
let queryTimeWindow = sp.util.startEnd('2019-07-01', '2019-07-31');
let eventQuery = new sp.fdsnevent.EventQuery()
.timeRange(queryTimeWindow)
.minMag(7)
.latitude(35).longitude(-118)
.maxRadius(3);
let stationQuery = new sp.fdsnstation.StationQuery()
.networkCode('CO')
.stationCode('HODGE')
.locationCode('00')
.channelCode('LH?')
.timeRange(queryTimeWindow);
Next we call the
query
methods for eventQuery and stationQuery, which each
return a Promise to an array of Network or Quake objects
and then use those to plot the earthquakes and stations on the map.
The station will be plotted as
a generic triangle as the map marker, but the quake is
plotted as a circle with the radius scaled by the magnitude.
let stationsPromise = stationQuery.queryChannels();
let quakePromise = eventQuery.query();
We then use a separate
then()
for the actual seismograms. Because we will need both the earthquake and
the chanenls, we use
Promise.all()
to ensure both have successfully completed. We also set the content of
a couple of
<span>
elements to hold the station codes and earthquake description,
assuming we will only get one of each.
The easiest way to use the more powerful POST method of the
FDSNWS dataselect
web
service to get the seismograms is to first create an
array of
SeismogramDisplayData
objects, which start out as just having a channel and a time range.
The time range starts at the origin time of the
earthquake and has a duration of 2400 seconds. Then
we manually attach the earthquake. The map knows to look for station and
earthquake locations within
SeismogramDisplayData
objects, so we can plot both on the map by setting the
seisData
field on the map.
Passing the array of
SeismogramDisplayData
objects to the
postQuerySeismograms()
function will query the remote DataSelect service and insert the
actual seismograms into each SeismogramDisplayData
when the DataSelect query returns. Of course this function will return
a Promise.
Promise.all( [ quakePromise, stationsPromise ] )
.then( ( [ quakeList, networkList ] ) => {
document.querySelector("span#stationCode").textContent = networkList[0].stations[0].codes();
document.querySelector("span#earthquakeDescription").textContent = quakeList[0].description;
let seismogramDataList = [];
for (const q of quakeList) {
const timeWindow = sp.util.startDuration(q.time, 2400);
for (const c of sp.stationxml.allChannels(networkList)) {
let sdd = sp.seismogram.SeismogramDisplayData.fromChannelAndTimeWindow(c, timeWindow);
sdd.addQuake(q);
seismogramDataList.push(sdd);
}
}
mymap.seisData = seismogramDataList;
let dsQuery = new sp.fdsndataselect.DataSelectQuery();
return dsQuery.postQuerySeismograms(seismogramDataList);
Once the Promise returns, we will plot the seismograms using the already existing sp-seismograph element. Because we have the channel, we can also plot the seismograms corrected for overall gain and in units of m/s. The default text coloring colors the seismograms and the corresponding array of strings in the title the same color, making them easier to identify. Note the units on the left hand side are now m/s.
}).then( seismogramDataList => {
seismogramDataList.forEach(sdd => {
sdd.seismogram = sp.filter.rMean(sdd.seismogram);
});
let graph = document.querySelector('sp-seismograph');
let seisConfigGain = new sp.seismographconfig.SeismographConfig();
seisConfigGain.doGain = true;
seisConfigGain.amplitudeMode = "mean";
graph.seismographConfig = seisConfigGain;
graph.seisData = seismogramDataList
}).catch( function(error) {
const div = document.querySelector('div#myseismograph');
div.innerHTML = `
<p>Error loading data. ${error}</p>
`;
console.assert(false, error);
});
Previous: Let"s get some real data