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.
The markers on the map can also be styled with css, using the
quakeMarker
and
stationMarker
selectors. 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.
<style>
div#mapid {
height: 300px;
width: 100%;
}
div.stationMapMarker {
color: rebeccapurple;
}
path.quakeMapMarker {
fill: orange;
stroke: yellow;
fill-opacity: 0.25;
}
</style>
First, we will create the map, centering it on 35/-100 and at zoom level 4. The World Ocean Base tile layer gives a nice background.
import {
fdsndataselect, fdsnevent, fdsnstation,
seismogram, seismograph,
seismographconfig,
stationxml,
util, luxon} from './seisplotjs_3.0.0-alpha.1_standalone.mjs';
const mymap = document.querySelector('sp-station-event-map');
//mymap.scrollWheelZoom.disable();
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.
let queryTimeWindow = luxon.Interval.fromDateTimes(util.isoToDateTime('2019-07-01'), util.isoToDateTime('2019-07-31'));
let eventQuery = new fdsnevent.EventQuery()
.timeWindow(queryTimeWindow)
.minMag(7)
.latitude(35).longitude(-118)
.maxRadius(3);
let stationQuery = new fdsnstation.StationQuery()
.networkCode('CO')
.stationCode('HODGE')
.locationCode('00')
.channelCode('LH?')
.timeWindow(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.
We also added a couple of
<span>
elements to hold the station codes and earthquake description.
We set the these elements assuming we will only get one of each.
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 then will use the more powerful POST method of the
FDSNWS dataselect
web
service to get the seismograms.
The array of
SeismogramDisplayData
objects works just like the
StartEndDuration
we saw previously but also holds the channel and the quake and will also contain
the resulting seismogram. We ask for data starting at the origin time of the
earthquake and with a duration of 2400 seconds.
Promise.all( [ quakePromise, stationsPromise ] )
.then( ( [ quakeList, networkList ] ) => {
let seismogramDataList = [];
for (const q of quakeList) {
let timeWindow = luxon.Interval.after(q.time, luxon.Duration.fromMillis(1000*2400));
for (const c of stationxml.allChannels(networkList)) {
let sdd = seismogram.SeismogramDisplayData.fromChannelAndTimeWindow(c, timeWindow);
sdd.addQuake(q);
seismogramDataList.push(sdd);
}
}
mymap.seisData = seismogramDataList;
mymap.seisData.forEach(sdd => {
console.log(`${sdd.quakeList.length} ${sdd.quake}`);
})
let dsQuery = new fdsndataselect.DataSelectQuery();
let sddPromise = dsQuery.postQuerySeismograms(seismogramDataList);
return Promise.all( [ quakePromise, stationsPromise, sddPromise ] );
Once these are loaded we will plot them just like we did before. 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( ( [ quakeList, networkList, seismogramDataList ] ) => {
let div = document.querySelector('div#myseismograph');
let seisConfig = new seismographconfig.SeismographConfig();
seisConfig.doGain = false;
seisConfig.centeredAmp = true;
let graphCount = new seismograph.Seismograph(seismogramDataList, seisConfig);
div.appendChild(graphCount);
let seisConfigGain = new seismographconfig.SeismographConfig();
seisConfigGain.doGain = true;
seisConfigGain.centeredAmp = true;
let graphGain = new seismograph.Seismograph(seismogramDataList, seisConfigGain);
div.appendChild(graphGain);
return 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