Auxiliary Chart

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);
        });