This tutorial demonstrates how to display seismic trace headers as an Auxiliary graph. The graph displays values for the selected headers from the XSection window.
# Display Seismic Trace Headers as Auxiliary Graph
The first step is to create a seismic MemoryReader which has three trace headers, 'CDPX', 'CDPY' and 'TraceNumber'. Then, create a Seismic widget with a previously defined pipeline, which internally generates the AuxiliaryChart using the headers and other options.
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { SeismicWidget } from "@int/geotoolkit/seismic/widgets/SeismicWidget.ts";
import { MemoryReader } from "@int/geotoolkit/seismic/data/MemoryReader.ts";
import { SeismicColors } from "@int/geotoolkit/seismic/util/SeismicColors.ts";
import { SeismicPipeline } from "@int/geotoolkit/seismic/pipeline/SeismicPipeline.ts";
import { TraceHeaderChartWidget } from "@int/geotoolkit/seismic/widgets/TraceHeaderChartWidget.ts";
import { ToolTipTool } from "@int/geotoolkit/controls/tools/ToolTipTool.ts";
import { LineChart } from "@int/geotoolkit/controls/shapes/LineChart.ts";
import { TickPosition } from "@int/geotoolkit/axis/TickInfo.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { Point } from "@int/geotoolkit/util/Point.ts";
import { MathUtil } from "@int/geotoolkit/util/MathUtil.ts";
import { Node } from "@int/geotoolkit/scene/Node.ts";
import { Axis } from "@int/geotoolkit/axis/Axis.ts";
import { Selector } from "@int/geotoolkit/selection/Selector.ts";
import { from } from "@int/geotoolkit/selection/from.ts";
import { FieldDesc } from "@int/geotoolkit/seismic/data/FieldDesc.ts";
import { ColorUtil, KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { AutoNumberFormat } from "@int/geotoolkit/util/AutoNumberFormat.ts";
const createPipeline = function(reader) {
const pipeline = new SeismicPipeline({
"name": "MemorySeismic",
"reader": reader,
"statistics": reader.getStatistics()
});
const colorProvider = SeismicColors.getDefault();
pipeline.setOptions({
"colors": {
"colormap": colorProvider.createNamedColorMap("RedWhiteBlue")
},
"plot": {
"type": {
"wiggle": true,
"interpolateddensity": true
},
"decimationspacing": 5
}
});
return pipeline;
};
const createSeismicReader = function() {
const sampleRate = 1;
const sampleCount = 350;
const traceCount = 500;
const cdpyCount = 55;
const cdpxCount = 5;
const reader = new MemoryReader({
"numberoftraces": traceCount,
"numberofsamples": sampleCount,
"samplerate": sampleRate
}).setTraceProcessor({
"getTraceData": function(reader2, trace, traceId) {
const thickness = 30;
const start = 80;
for (let i = start; i < start + thickness; i++) {
trace[i + Math.round(thickness * Math.cos(traceId / 64))] = Math.cos(i / 2);
}
},
"getDataStatistics": function() {
return {
"average": 0,
"min": -1,
"max": 1,
"rms": Math.sqrt(2) / 2
};
},
"getTraceHeaderFields": function() {
return [
new FieldDesc(0, "TraceNumber"),
new FieldDesc(1, "CDPX"),
new FieldDesc(2, "CDPY")
];
},
"getTraceHeader": function(reader2, header, headerData, traceId) {
headerData[0] = traceId;
headerData[1] = 50 + Math.round(traceId / cdpxCount) * cdpxCount;
if (traceId === 499)
headerData[1] = 10;
if (traceId === 6)
headerData[1] = 600;
headerData[2] = 5 + traceId % cdpyCount;
}
});
return reader;
};
function initializeAuxiliaryTooltip(seismicWidget) {
const selector = new Selector();
const multiLineToolTip = true;
const format = new AutoNumberFormat();
seismicWidget.getAuxiliaryChart().connectTool(
new ToolTipTool({
"autoflip": true,
"callback": function(pt) {
const x = pt.getX();
const y = pt.getY();
if (isNaN(x) || isNaN(y))
return "";
let toolTipText = '<span class="tooltip-title">Auxiliary chart</span><br>';
let selection = selector.select(seismicWidget.getRoot(), x, y, 2);
const axes = selection.filter(
(item) => item instanceof Axis && Node.findParent(item, TraceHeaderChartWidget) != null
);
if (axes.length !== 0) {
const axis = axes[0];
const min = format.format(axis.getModelLimits().getTop());
const max = format.format(axis.getModelLimits().getBottom());
toolTipText += "<span style='color: " + axis.getTitleTextStyle().getColor() + ";'>" + axis.getTitle() + ": </span>";
toolTipText += "[" + min + " : " + max + "]<br>";
return toolTipText;
}
selection = selection.filter((item) => item instanceof LineChart);
if (selection.length === 0) {
return "";
}
const lineCharts = from(seismicWidget.getAuxiliaryChart()).where((node) => node instanceof LineChart).selectToArray();
let xValue = lineCharts[0].getSceneTransform().inverseTransformPoint(pt).x;
xValue = Math.round(xValue);
let chartData = lineCharts[0].getData();
let traceIndex = MathUtil.findIndex(xValue, chartData.x);
if (traceIndex < 0) {
traceIndex = ~traceIndex;
if (traceIndex > 0) {
--traceIndex;
}
}
toolTipText += "Trace # " + chartData.x[traceIndex] + "<br>";
const hitTestRadius = 4;
const hitTestPoint = new Point(x, y);
for (let i = 0; i < lineCharts.length; ++i) {
let yValue = null;
chartData = lineCharts[i].getData();
if (!multiLineToolTip) {
const selectedPoint = lineCharts[i].hitTest(hitTestPoint, hitTestRadius);
if (selectedPoint.length > 0 && selectedPoint[0]["points"].length > 0) {
yValue = selectedPoint[0]["points"][0]["y"];
}
} else {
yValue = chartData["y"][traceIndex];
}
if (yValue !== null && !Number.isNaN(yValue)) {
const color = chartData.linestyles.length > i ? chartData.linestyles[i].getColor() : "black";
toolTipText += "<span style='color: " + color + ";'>" + lineCharts[i].getId() + ": </span>" + Math.round(yValue * 100) / 100 + "<br>";
}
}
return toolTipText;
}
})
);
}
function createSeismicWidget(pipeline) {
const formatter = (tickGenerator, parent, orientation, tickInfo, tickIndex, value) => value != null ? (value + 1).toString() : "";
const widget = new SeismicWidget({
"pipeline": pipeline,
"colorbar": {
"axis": {
"tickgenerator": {
"edge": {
"tickvisible": false,
"labelvisible": false
}
}
}
},
"auxiliarychart": {
"size": 120,
"title": {
"text": "Auxiliary Chart",
"textstyle": {
"font": "16px Roboto",
"color": "gray"
},
"size": 20
},
"charts": [
{
"name": "CDPY",
"linestyle": KnownColors.Green
},
{
"name": "CDPX",
"range": new Range(0, 650),
"neatlimits": false,
"axis": {
"linestyle": "blue"
},
"chart": {
"linestyle": KnownColors.Blue
}
}
]
},
"layouttype": "inside",
"statusbar": {
"visible": false
},
"table": {
"visible": false,
"size": 100
},
"tools": {
"colorbar": {
"enabled": true
}
}
}).setScaleOptions({
"tracescale": 30,
"samplescale": 40,
"deviceunit": "in",
"sampleunit": "ms"
});
const headerFields = pipeline.getReader().getTraceHeaderFields();
for (let i = 0; i < headerFields.length; i++) {
const header = headerFields[i];
const headerInfo = widget.setTraceHeaderVisible(header, header.getName() === "TraceNumber");
if (headerInfo) {
headerInfo["label"].getTextStyle().setColor("gray");
headerInfo["axis"].setTickPosition(TickPosition.TopAndBottom).getTickGenerator().setTickStyle("major", "gray").setLabelStyle("major", { "color": "gray" });
if (header.getName() === "TraceNumber") {
headerInfo["axis"].getTickGenerator().setFormatLabelHandler(formatter);
}
}
}
return widget;
}
function toggleChartByName(plot, chartName) {
const widget = plot.getRoot();
const chartOptions = widget.getOptions()["auxiliarychart"];
const charts = chartOptions["charts"];
let chartIndex = -1;
for (let i = 0; i < charts.length; i++) {
const chart = charts[i];
if (chart["name"] === chartName) {
chartIndex = i;
break;
}
}
if (chartIndex === -1) {
charts.push({
"name": chartName,
"linestyle": ColorUtil.getRandomColorRgb(22)
});
} else {
charts.splice(chartIndex, 1);
}
widget.setOptions({
"auxiliarychart": {
"charts": charts
}
});
}
function toggleChart(plot) {
const widget = plot.getRoot();
const chartOptions = widget.getOptions()["auxiliarychart"];
const isChartVisible = chartOptions["visible"] === true;
widget.setOptions({
"auxiliarychart": {
"visible": !isChartVisible
}
});
let headerInfo = widget.getTraceHeaderAxis("TraceNumber");
if (headerInfo == null) {
const headerField = widget.getTraceHeader("TraceNumber");
headerInfo = widget.getTraceHeaderAxis(headerField);
}
if (headerInfo != null) {
headerInfo["axis"].setTickPosition(!isChartVisible ? TickPosition.TopAndBottom : TickPosition.Bottom);
}
}
function createScene(canvas) {
const seismicReader = createSeismicReader();
const pipeline = createPipeline(seismicReader);
const seismicWidget = createSeismicWidget(pipeline);
initializeAuxiliaryTooltip(seismicWidget);
seismicWidget.getAuxiliaryChart().getToolByName("cross-hair").setVerticalLineStyle({
"color": "red",
"width": 2,
"pixelsnapmode": true
});
seismicWidget.getToolByName("cross-hair").setLineStyle({
"color": "red",
"width": 2,
"pixelsnapmode": true
});
return new Plot({
"canvaselement": canvas,
"root": seismicWidget
});
}
export { createScene, toggleChart, toggleChartByName };
createScene(document.querySelector('[ref="plot"]'), () => {
this.setRubberBandEnabled(false);
});