diff --git a/examples/well_correlation_data/__init__.py b/examples/example_sync_log_viewer/__init__.py similarity index 100% rename from examples/well_correlation_data/__init__.py rename to examples/example_sync_log_viewer/__init__.py diff --git a/examples/well_correlation_data/well_log_testdata.py b/examples/example_sync_log_viewer/example_data.py similarity index 100% rename from examples/well_correlation_data/well_log_testdata.py rename to examples/example_sync_log_viewer/example_data.py diff --git a/examples/well_correlation_data/well_correlation_panel_testapp.py b/examples/example_sync_log_viewer/well_correlation_panel_app.py similarity index 96% rename from examples/well_correlation_data/well_correlation_panel_testapp.py rename to examples/example_sync_log_viewer/well_correlation_panel_app.py index 38cc8baa1..42035506a 100644 --- a/examples/well_correlation_data/well_correlation_panel_testapp.py +++ b/examples/example_sync_log_viewer/well_correlation_panel_app.py @@ -3,7 +3,7 @@ import dash import flask -from examples.well_correlation_data.well_log_testdata import ( +from examples.example_sync_log_viewer.example_data import ( axis_mnemos, axisTitles, color_tables, diff --git a/react/src/demo/example-data/discrete-facies-test.json b/react/src/demo/example-data/discrete-facies-test.json index 38370fe36..810f27f43 100644 --- a/react/src/demo/example-data/discrete-facies-test.json +++ b/react/src/demo/example-data/discrete-facies-test.json @@ -35,7 +35,7 @@ "dimensions": 1 }, { - "name": "PORO_TOT", + "name": "PORO", "description": "continuous", "quantity": "", "unit": "", @@ -47,25 +47,25 @@ [ 1400, 2, - 2, + 1, 0.247 ], [ 2179, - 2, 1, + 2, 0.247 ], [ - 2180.6093750344276, + 2300.0, + 3, 3, - 2, 0.137 ], [ - 3541.6093750344276, - 3, + 3541.6, 3, + 4, 0.237 ], [ diff --git a/react/src/demo/example-data/synclog_template_lithologytrack.json b/react/src/demo/example-data/synclog_template_lithologytrack.json index 7b2e48a84..6a6bf3a69 100644 --- a/react/src/demo/example-data/synclog_template_lithologytrack.json +++ b/react/src/demo/example-data/synclog_template_lithologytrack.json @@ -13,19 +13,6 @@ } ] }, - { - "plots": [ - { - "name": "PORO" - }, - { - "name": "NTG" - }, - { - "name": "SW" - } - ] - }, { "plots": [ { @@ -34,53 +21,23 @@ } ] }, - { - "plots": [ - { - "name": "MFOA" - } - ] - }, { "plots": [ { - "name": "FACIES", - "style": "discrete" + "name": "PORO" + }, + { + "name": "NTG" + }, + { + "name": "SW" } ] }, { "plots": [ { - "name": "DD_VOLUME" - } - ] - }, - { - "plots": [ - { - "name": "TEMP" - } - ] - }, - { - "plots": [ - { - "name": "BITSIZE" - } - ] - }, - { - "plots": [ - { - "name": "GRSIM" - } - ] - }, - { - "plots": [ - { - "name": "RACESHM" + "name": "MFOA" } ] }, @@ -99,63 +56,6 @@ "type": "dot" } ] - }, - { - "plots": [ - { - "name": "MDIA", - "style": "MD" - } - ] - }, - { - "plots": [ - { - "name": "MTOA" - } - ] - }, - { - "plots": [ - { - "name": "MTIA" - } - ] - }, - { - "plots": [ - { - "name": "ECDT" - } - ] - }, - { - "plots": [ - { - "name": "BDTI" - } - ] - }, - { - "plots": [ - { - "name": "BDDI" - } - ] - }, - { - "plots": [ - { - "name": "BRVC" - } - ] - }, - { - "plots": [ - { - "name": "TCTI" - } - ] } ], "styles": [ diff --git a/react/src/lib/components/WellLogViewer/components/LithologyTrack.tsx b/react/src/lib/components/WellLogViewer/components/LithologyTrack.tsx index 249a9ff58..7d98097bc 100644 --- a/react/src/lib/components/WellLogViewer/components/LithologyTrack.tsx +++ b/react/src/lib/components/WellLogViewer/components/LithologyTrack.tsx @@ -50,47 +50,63 @@ export class LithologyTrack extends StackedTrack { constructor(id: string | number, props: LithologyTrackOptions) { super(id, props); this.lithologyInfo = props.lithologyInfoTable as LithologyInfoTable; // TODO - ensure table is given and valid + setupLithologyInfoMap(this.lithologyInfo); this.patterns = new Map(); + this.loadPatterns = this.loadPatterns.bind(this); } - loadPatterns(): void { - const { data } = this; - if (!data) return; + async loadPatterns():Promise { + return new Promise(resolve => { + const { data } = this; + if (!data) return; + // Find unique canvas code names in data for this track. Later only load images for used codes + const uniqueCodes = [ + ...new Set(data.map((item: LithologyTrackDataRow) => item.name)), + ] as (string | number)[]; // TODO: why doesn't typescript understand this itself? - // Find unique canvas code names in data for this track. Later only load images for used codes - const uniqueCodes = [ - ...new Set(data.map((item: LithologyTrackDataRow) => item.name)), - ] as (string | number)[]; // TODO: why doesn't typescript understand this itself? - setupLithologyInfoMap(this.lithologyInfo); - uniqueCodes.forEach((code) => { - const pattern = lithologyInfoMap.get(code); - // const pattern = patterns.find(pattern => code === pattern.code) - if (pattern?.patternImage) { - // Check if we have loaded pattern - if (!this.patterns.get(code)) { - // Temporarily set solid color while we get image to avoid fetching multiple times - this.patterns.set(code, "#eee"); - // Create pattern - const patternImage = new Image(); - patternImage.src = pattern.patternImage; - patternImage.onload = () => { - this.patterns.set( - code, - this.ctx?.createPattern( - patternImage, - "repeat" - ) as CanvasPattern - ); - }; + let numUniquePatternsLoading = uniqueCodes.length; + uniqueCodes.forEach((code) => { + const pattern = lithologyInfoMap.get(code); + // const pattern = patterns.find(pattern => code === pattern.code) + if (pattern?.patternImage) { + // Check if we have loaded pattern + if (!this.patterns.get(code)) { + // Temporarily set solid color while we get image to avoid fetching multiple times + this.patterns.set(code, "#eee"); + // Create pattern + const patternImage = new Image(); + patternImage.src = pattern.patternImage; + patternImage.onload = () => { + this.patterns.set( + code, + this.ctx?.createPattern( + patternImage, + "repeat" + ) as CanvasPattern + ); + numUniquePatternsLoading -= 1; + // Resolve on last image. + if (numUniquePatternsLoading <= 0) { + this.isLoading = false; + resolve(); + } + }; + } else { + numUniquePatternsLoading -= 1; + } + } else { + numUniquePatternsLoading -= 1; } + }); + if (numUniquePatternsLoading <= 0) { + this.isLoading = false; + resolve(); } - }); + }) } plot(): void { - super.plot(); const { ctx, scale: yscale, data, patterns } = this; - if (!ctx || !data) return; const rectangles = scaleData(yscale, data); const { width: rectWidth, clientWidth, clientHeight } = ctx.canvas; @@ -156,7 +172,8 @@ export class LithologyTrack extends StackedTrack { options.data().then( (data: LithologyTrackDataRow[]) => { this.data = data; - this.plot(); + // @ts-ignore + this.loadPatterns().then(this.plot()); }, (error: Error | string) => super.onError(error) ); @@ -189,8 +206,8 @@ export class LithologyTrack extends StackedTrack { this.plot(); } onDataLoaded(): void { - this.loadPatterns(); - this.plot(); + // @ts-ignore + this.loadPatterns().then(this.plot()); } } diff --git a/react/src/lib/components/WellLogViewer/utils/tracks.ts b/react/src/lib/components/WellLogViewer/utils/tracks.ts index 2469dd37a..3264d6883 100644 --- a/react/src/lib/components/WellLogViewer/utils/tracks.ts +++ b/react/src/lib/components/WellLogViewer/utils/tracks.ts @@ -60,8 +60,8 @@ import { deepCopy } from "./deepcopy"; import { createPlotType } from "@equinor/videx-wellog"; import { defaultPlotFactory } from "@equinor/videx-wellog"; import { - LithologyInfoTable, LithologyTrack, + LithologyInfoTable, LithologyTrackOptions, } from "../components/LithologyTrack"; export function indexOfElementByName(array: Named[], name: string): number { @@ -978,6 +978,28 @@ function createAreaData( }; } +async function createLithologyData( + data: [number | null, number | string | null][] +) { + // Remove possibly null values for depth + const data_no_null_depths = data.filter((elem) => { + return elem[0] !== null; + }); + // Setup areas where value used for interval is taken from the first depth (current code has a bug where value is taken from the last depth) + return data_no_null_depths.map((dataRow, index) => { + const value = dataRow[1] == null ? Number.NaN : dataRow[1].toString(); + return { + from: dataRow[0], + to: + index < data.length - 1 + ? data_no_null_depths[index + 1][0] + : dataRow[0], + name: value, + color: { r: 255, g: 25, b: 25 }, // Apparently, this is needed by the mother class in videx, use dummy for now + }; + }); +} + async function createStackData( data: [number | null, number | string | null][], colorTable: ColorTable | undefined, @@ -1290,19 +1312,13 @@ function addGraphTrack( } } function addLithologyTrack( - info: TracksInfo, - welllog: WellLog, + name: string, + currentMinMaxPrimaryAxis: [number, number], curves: WellLogCurve[], data: WellLogDataRow[], iPrimaryAxis: number, - templateTrack: TemplateTrack, - templateStyles?: TemplateStyle[], - colorTables?: ColorTable[], lithologInfoTable?: LithologyInfoTable -): void { - const templatePlot = templateTrack.plots[0]; - const name = templatePlot.name; - +): LithologyTrack | undefined { const iCurve = indexOfElementByName(curves, name); if (iCurve < 0) return; // curve not found const curve = curves[iCurve]; @@ -1311,58 +1327,20 @@ function addLithologyTrack( if (dimensions !== 1) return; const plotData = preparePlotData(data, iCurve, iPrimaryAxis); - checkMinMax(info.minmaxPrimaryAxis, plotData.minmaxPrimaryAxis); - - // make full props - const templatePlotProps = getTemplatePlotProps( - templatePlot, - templateStyles - ); - const templateTrackFullPlot: TemplateTrack = deepCopy(templateTrack); - - templateTrackFullPlot.title = makeTrackHeader(welllog, templateTrack); - templateTrackFullPlot.plots[0].type = templatePlotProps.type; - - // curve.valueType === "integer", "string" - const logColor = templatePlotProps.colorTable; - let colorTable: ColorTable | undefined = undefined; - if (logColor) { - if (colorTables) { - colorTable = colorTables.find( - (colorTable) => colorTable.name == logColor - ); - if (!colorTable) - console.error("Missed '" + logColor + "' color table"); - } else { - console.error( - "No color tables file given for '" + logColor + "' color table" - ); - } - } else { - console.error("No color table given in template plot props"); - } - const meta = getDiscreteMeta(welllog, name); - if (!meta && curve.valueType == "integer") - console.log( - "Discrete meta information for '" + - name + - "' not found. Use default" - ); - - const showLines = true; + checkMinMax(currentMinMaxPrimaryAxis, plotData.minmaxPrimaryAxis); const options: LithologyTrackOptions = { abbr: name, // name of the only plot legendConfig: stackLegendConfig, - data: createStackData.bind(null, plotData.data, colorTable, meta), + data: createLithologyData.bind(null, plotData.data), showLabels: true, - showLines: showLines, + showLines: true, lithologyInfoTable: lithologInfoTable, }; - setStackedTrackOptionFromTemplate(options, templateTrackFullPlot); const track = new LithologyTrack(undefined as unknown as number, options); updateStackedTrackScale(track); - info.tracks.push(track); + return track; } + function addStackedTrack( info: TracksInfo, welllog: WellLog, @@ -1492,17 +1470,15 @@ export function createTracks( break; } case "canvas": { - addLithologyTrack( - info, - welllog, + const lithologyTrack = addLithologyTrack( + templateTrack.plots[0].name, + info.minmaxPrimaryAxis, curves, data, iPrimaryAxis, - templateTrack, - templateStyles, - colorTables, lithologyInfoTable ); + if (lithologyTrack) info.tracks.push(lithologyTrack); break; } default: {