Skip to content

Commit

Permalink
Added logic for wrapping line plots, both linear and logarithmic
Browse files Browse the repository at this point in the history
  • Loading branch information
tomktjemsland committed Jan 24, 2024
1 parent ee0584d commit 5c5b175
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 4 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": false,
"name": "@equinor/videx-wellog",
"version": "0.8.3",
"version": "0.8.4",
"license": "MIT",
"description": "Visualisation components for wellbore log data",
"repository": "https://github.com/equinor/videx-wellog",
Expand Down
9 changes: 9 additions & 0 deletions src/plots/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ export interface LinePlotOptions extends PlotOptions {
* @example [4, 4] // 4 pixels stroked, 4 pixels skipped
*/
dash?: number[],
/**
* If enabled, will wrap logs outside of domain and display as dashed.
*/
allowWrapping?: boolean,
/**
* Dash array used for wrapped plot (Default: [2, 3])
* @example [2, 3] // Draw 2, skip 3 pixels
*/
dashWrapped?: number[],
}

/**
Expand Down
70 changes: 69 additions & 1 deletion src/plots/line-plot.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { line } from 'd3-shape';
import { Line, line } from 'd3-shape';
import Plot from './plot';
import { Scale } from '../common/interfaces';
import { PlotData, LinePlotOptions } from './interfaces';
Expand Down Expand Up @@ -49,6 +49,74 @@ export default class LinePlot extends Plot {
ctx.stroke();
}

// Plot wrapping segments
if (options.allowWrapping) {
this.plotWrapped(ctx, lineFunction);
}

ctx.restore();
}

/**
* Renders segments outside of domain.
*/
plotWrapped(ctx: CanvasRenderingContext2D, lineFunction: Line<[number, number]>) {
const {
scale: xscale,
data: plotdata,
options,
} = this;

const isLogarithmic = (options.scale === 'log');

// Return if plot has no points, or is horizontal
// TODO: Add support for horizontal plots?
if (!plotdata || plotdata.length === 0 || options.horizontal) {
return;
}

ctx.setLineDash(options.dashWrapped || [2, 3]);

/** Helper function for plotting segment with given displacement. */
const plotSegment = (segment: PlotData, disp: number) => {
ctx.beginPath();
lineFunction(segment.map(
([y, x]) => (isLogarithmic ? [y, 10 ** (Math.log10(x) + disp)] : [y, x + disp]),
));
ctx.stroke();
};

const [min, max] = isLogarithmic ? xscale.domain().map(Math.log10) : xscale.domain();
const range = (max - min);

let prev = plotdata[0];
let segment: PlotData = [];

// Distance to displace the segment in order to wrap
let segmentDisp: number;

for (let i = 1; i < plotdata.length; i++) {
const cur = plotdata[i];
const curX = isLogarithmic ? Math.log10(cur[1]) : cur[1];
if (curX > max || curX < min) {
segmentDisp = (curX > max) ? -range : range;
if (segment.length === 0) {
segment.push(prev);
}
segment.push(cur);
} else if (segment.length > 0) {
segment.push(cur);
plotSegment(segment, segmentDisp);
segment = [];
}
prev = cur;
}

// If the data ends with point outside of range
if (segment.length > 0) {
plotSegment(segment, segmentDisp);
}

ctx.setLineDash([]);
}
}

0 comments on commit 5c5b175

Please sign in to comment.