0.0.32
Central to wellioviz is the concept that how to plot and what to plot can be put into a JSON template that has sensible defaults, such that the end-user only has to understand what they want to change about the plotting, not the whole d3.js code.
Most geologists who make charts of well logs via code seem to do so in Python, often working in Jupyter notebooks. This is fine for a lot of things, but there are some use-cases where having a JavaScript visualization library makes for a better option.
GUIs for well correlation. Currently, there really isn't a free open-source application for well log correlation, at least to the best of my knowledge. This means if you don't have Enterprise scale money, (academics, non-profits, hobbyest, students, people in between jobs, etc.) you're often limited to correlating a handfull of wells at most using paper and pencil. Wellio (something to convert LAS files to JSON) and Wellioviz (something to visualize well logs as JSON into SVGs on a webpage) are critical pieces for a free non-code web-based well log visualization to exist. Although a full GUI (graphic user interface) is slightly out of scope for wellioviz, wellioviz could be extended to do this.
Websites that provide well logs to audiences on the web. Although PNG images of well logs could be created and stored on server before being sent on demand to the front-end, this is less than ideal as all the images have to be created, stored, and loaded before the user needs them. This takes a lot of storage space. Additionally, it prevents scrolling, zooming, and overlays. Visualizing the logs on the fly in JavaScript is a better option for websites that want to given users an idea what a well log contains.
Interactive well plotting with export into SVG or full HTML Pages from inside Jupyter Notebook Building the visualization in JavaScript also opens up the possibility of working in a Jupyter notebook and exporting wells as SVGs or full HTML webpages. Additionally, there aren't any limits on interactivity that you might hit in a python visualization package that is wrapping JavaScript behind the scenes. Kepler.gl in Jupyter is an example of this functionality where beautiful maps get created inside Jupyter notebook and get published as self-contained front-end only full HTML/CS/JS pages.
Point of Caution: To some of extent, all of these are not completely in scope of the project. Wellioviz is a visualization library. 1,2,&3 also require graphic user interfaces and other things that are better to be built as projects that utilize wellioviz.
Wellioviz is a node.js module. If you've only brought JavaScript into an HTML project via a tag, you probably want to learn a little bit about how to use npm (node package manager) to get JavaScript modules into your front-end code. This is a short demo that only covers the minimum you need to know.
To use wellioviz in a ObservableHQ.com JavaScript notebook, you can simply have a cell that says
wellioviz = require('https://bundle.run/wellioviz)
If you want to bring in a specific version, you can add the version on the end like so
.wellioviz = require('https://bundle.run/wellioviz@0.0.25')
You would then call wellioviz functions in other cells by adding the function name on the end of wellioviz like:
.example_template = wellioviz.curveBoxTemplateExamples("example")
You can find an example of this in the Hello Wellioviz" notebook on ObservableHQ.com.
As mentionted above, if you haven't used npm modules in an HTML page before, you probably want to reach a little about them.
There is more than one way to get npm modules into a front-end project. Wellioviz doesn't have anyting about it that requires very advanced ways. For example, here and here are two different blog posts to walk you through installing a npm JavaScript module into a front-end project.
{ "dependencies": { "wellioviz": "0.0.25" } }
Note, the latest version of wellioviz is probably not 0.0.25 by now. Any other modules you need would go in here too after wellioviz line separated by a comma.npm install
. This will create a folder called "node_modules" and there should be another folder called wellioviz.<script src="node_modules/wellioviz/dist/index.js"></script>
. You should be able to call wellioviz functions in your other JavaScript files now.This way is slightly cleaner in terms of namespace. Additionally, you may not want to include your entire node modules folder if that gets big!
npm install wellioviz
JS
. JS
directory and create a file called main.js
.wellio = require('wellioviz');
.browserify main.js other.js more.js -o bundle.js
. This would not only combine those folders into a single file, but it would also pull in the wellioviz library because of the line in step 8.<script src="JS/bundle.js"></script>
. You should be able to call wellioviz functions in your other JavaScript files now.You're probably not going to use wellioviz on the backend. The one exception is if you wanted to create a large number of static SVGs of well logs from your LAS files.
npm install wellioviz
.node --require wellioviz
. This should start the node console with wellioviz included. You should see a >
on the next console line.var wellio = require('wellioviz')
undefined
, which is a bit scary, sorry. wellioviz.help
you'll now see returned on the next line = 'I'm really no help. Please check out the docs at https://justingosses.github.io/wellioviz/ or the main README.md at https://github.com/JustinGOSSES/wellioviz. Best of luck.'
.wellioviz
+ .
+ function name with arguments included inside the ()
.pip install panel
(and its dependancies) from your python enviroment command line.panel serve example_panel_app --show
-- IN PROGRESS --
-- IN PROGRESS --
git clone https://github.com/
+yourUserName+/wellioviz.git
.cd wellioviz
.For context on usage, it is probably worthwhile to quickly check out the Architecture section and examples listed in the README.md then come back here.
WELLIOVIZ is a JavaScript library that provides functionality to visualize well logs using the d3.js version 5 visualization library.
Central to wellioviz is the concept that what to plot and how to plot it can be put into a JSON template of instructions. That template will already has sensible defaults filled in, such that the end-user only has to understand what they want to change about the plotting, not all possible changes or the d3.js code itself.
Wellioviz doesn't have any native well log file loading capabilities. It is only visualization.
Therefore, most of the demos use something else to load the well log curves and get them into JSON. The companion library, Wellio.js, is the standard option for converting LAS 2.0 files into JSON entirely with JavaScript. However, wellioviz is built with the idea that developers will write adaptors to transform their data into the wellioviz template before passing it to the curveBox function.
One example of this is the sparse input data transformation functions Wellioviz has that are built around the idea that some people want to strip out the parts of the well log you aren't plotting and only send to Wellioviz on the front-end the minimal amount of data needed. This speeds things up by shrinking the data you need to send from a backend system to the front-end.
Check out the installation section of the docs for more information on how to get wellioviz working in different settings.
The only mandatory parts of wellioviz really are (1) the plotting JSON template given to the curveBox() function that contains information about what to plot and how to plot it and (2) the curveBox function. Everything else is optional depending on need.
Load your LAS 2.0 file into memory. This will come in as a txt file converted to a string. General JavaScript functions can be used to load the file into memory. There are a couple different ways to do this depending on if the LAS 2.0 well log comes in from a file saved in the same directory as the code, a file loaded from the user's local computer into a web application, or pulled from somewhere else on the web via an API. All of these examples are shown in different Observable Demos linked to in this repositories README.md file.
Use wellio to convert the string of well log information into a wellio-style JSON.
well_json_01_01_095_19W4 = wellio.las2json(well_as_string)
Supply this and the depth curve name to the next function, like so:
The three_things objects holds an object or dict with three key:value pairs. The three keys are "curve_names", "uwi", and "well_log_curves_reformatted_for_d3". We'll use these in the next steps.three_things_2 = wellioviz.fromJSONofWEllGetThingsForPlotting(well_json_01_01_095_19W4,"DEPTH")
First though we need to get a blank template to be populated. This template holds both the data and the style for how things are visualized by wellioviz. We'll get one from wellioviz by calling:
example_template = wellioviz.curveBoxTemplateExamples("example")
You can either use the default style options for each curve, exert a large amount of fine grain control, or style things somewhere between. In this example, we'll do something somewhere in between using the function:
wellioviz.minimumDataIntoTemplateFunc()
gr_plot_template_noFill =
wellioviz.minimumDataIntoTemplateFunc(
example_template,well_log_curves_reformatted_for_d3_2,[uwi2],["CALI"],["black"],[""],[
{"curve_name":"GR",
"fill":"no",
"fill_direction":"left",
"cutoffs":[0,ShaleSiltCutOff,SiltSandCutOff],
"fill_colors":["gray","orange","yellow"],
"curve2":""
}
],
"well_holder_1A",200,400,"DEPT")
resd_plot_template_1 = wellioviz.minimumDataIntoTemplateFunc(example_template,well_log_curves_reformatted_for_d3_2,[uwi2],['ILD'],["RED"],[""],[
{"curve_name":"ILD","fill":"yes","fill_direction":"left","cutoffs":[5,10,25],"fill_colors":["#ffe6e6","#ffb3b3","red"],"curve2":"ILD"}],"well_holder_1B",200,400,"DEPT")
poro_plot_template_1 = wellioviz.minimumDataIntoTemplateFunc(example_template,well_log_curves_reformatted_for_d3_2,[uwi2],["NPHI","DPHI"],["purple","pink"],[""],[{
"curve_name":"NPHI",
"fill":"yes",
"fill_direction":"between",
"cutoffs":[0],
"fill_colors":["lightblue"],
"curve2":"DPHI"
},
{
"curve_name":"DPHI",
"fill":"no",
"fill_direction":"left",
"cutoffs":[],
"fill_colors":[],
"curve2":""
}
],"well_holder_1C",200,400,"DEPT")
We'll then put each of those well log curves into a single div to hold all the curves for that well.
result_1 = wellioviz.multipleLogPlot("well_holder",[gr_plot_template_noFill,resd_plot_template_1,poro_plot_template_1])
This will create a div with several sub-divs with SVGs within them that represent the various curves in the well. They will all get appended to the div called "well_holder".
The absolutely quickest way to get started (no installation) is to try it out on ObservableHQ. There is a Hello Wellioviz demo that shows how to bring wellioviz into Observable and uses a small number of functions to quickly plot an example LAS 2.0 well log. You can also load your own LAS 2.0 well logs file from your computer into the browser and try it.
https://observablehq.com/@justingosses/first-wellio-example-with-all-wellioviz-functions-from-npm
-- IN PROGRESS --
-- IN PROGRESS --
-- IN PROGRESS --
This code is written with the assumption that different users will want to bring in well log data in different formats. Code will need to transform that data into an established template format.
Some users will want to only send to the JavaScript the data they want to plot. They might want this to minimize the amount of data that has to be sent from backend server to the client's front-end website. This is referred to elsewhere in the code and documentation as the sparse incoming data approach.
Others might use wellio.js to convert a whole LAS 2.0 formatted well log file to JSON on the front-end. They would then send that whole JSON along with instructions with how to plot some portion of it to wellioviz.
Still others might want to bring in data in a format I don't know of. Ideally, it should be easy to adapt for that purpose as the plotting function takes a standard JSON. End users should be able to provide their own functions to reformat their data & style choices into the template that is fed into the curveBox function.
Code is organized into 4 groups of functions:
Loading, Transformation, Packaging, & Plotting.
The further one gets through the steps, the more there is one way to do things as opposed to multiple ways.
Organization of input information is:
Use of JSON as input to plotting functions using standard format enables:
There are multiple options for combining curveboxes. This will require the JavaScript code to generate not just SVGs, but also divs that are appended to divs created by other code.
Inside this main curvebox div, header information and curves within curvebox are optionally separate divs or a single SVG.
An initial CurveBox JSON template is used that has good defaults that then has limited key:value pairs replaced with new information for that specific curveBox. Things will be possible like:
All the visual pieces below are generated by the curveBox() function according to the explicity instructions within the plotting JSON given to the curveBox() function.
curve_box: an object
components:
An array with one object inside with three keys: curves, lines, and rectanges.
curves: An array of curve objects
lines: An array of line objects
rectangles: An array of rectangle objects
All contributions welcome! Big, small, code, documentation, or questions.
If you’d like to contribute, but you’re not so experienced with JavaScript, look for good first issue tags or email the maintainer for suggestions.
Check the Issues for outstanding issues & features under development. There is an attempt at organizing the issues using the project board here. For the most part, the issues board contains all the issues.. just in an organization to make it clear what is being worked on now.
Add a feature request or bug report issue here When you add an issue, there will be two choices for issues templates to use, one for bug reports and another for feature requests.
If you've fixed an issue in the code, please consider submitting a pull request, which is basically a fork or branch of this repository submitted back to it with a specific change. 1. State why you are proposing this change. 2. When you make a pull request, please try to keep the changes to one feature at a time if possible (not always possible). 3. We don't have tests yet, so in lieu of that, please fork the active Observable notebook noted in the README add in your changed functions and make sure everything still works with your changes. If there are changes needed to be made to get things to work that are not in index.js but only in the Observable notebook, please note that in your pull request. This is unlikely but theoretically possible.
Please submit a pull request or issue for anything confusing or absent in documentation as well.
Wellioviz documentation is built with documentation.js, a library that grabs inline code documentation above each function and markdown files specified in docs/doc_setup.yml to build HTML documentation pages. You can find a live version of the docs here
documentation build ./dist/index.js --config docs/doc_setup.yml -f html -o docs
python3 -m http.server
. Alternatively, if you have node.js and would like to use that you can run in your terminal http-server
. Please note, that if you run the server from anywhere except the docs directory, the image links won't work. The docs page on the github.com repository runs from the docs folder on the master branch as well.The tricky part is probably the bundle.js script. Everything else works like vanilla JavaScript. To regenerate the bundle.js script in docs/js used in the demo.html page:
.git clone https://github.com/JustinGOSSES/wellioviz.git
Install npm if it isn't already installed.
Navigate to the top folder of wellioviz if you aren't already there by running
.cd wellioviz
. npm install
cd docs/js
browserify call_plots.js main.js get_wellio.js vkbeautify.js -o bundle.js
python3 -m http.server
.
Originally, I would develope in an Observable notebook and then move the code into dist/index.js
in this repo. For this type of work, it has been a faster way to write working code.
However, now I mostly developer in VS code on the repository directly and use the demo.html page for experimentation and testing instead.
npm publish
. dist/index.js
and does not pull from the published version of wellioviz on npm.If anything is confusing, open an issue.
ALSO - If you got here relate to the hackathon, check out the Transform2020 Hackathon notes: https://justingosses.github.io/wellioviz/#swung-hackathon
Make Changes to Documentation:
Fork an example on Observable and add in your own well log & change how it is displayed.
Improve the documentation!
Add new variable to plotting template and main plotting function curveBox() <=== need to write instructions for this!
Issue boards:
There are a variety of issues that can be worked on for wellioviz. Some issues that are better suited for small hackathon scale springs have been tagged with either "hackathon_easy" or "hackathon_advanced".
This is more of a full hackathon project. What exists currently is best demonstrated by this Observable notebook and this barebones demo webpage. What doesn't exist yet is a webpage or Observable notebook where a non-code user can play around with all the style configuration variables in the plotting template to change things like colors, fills, line widths, sizes, etc. You can see an example of what is possible in the Observable notebook where there is a slider to change the dividing line between shale & silt and silt & sand in the gamma-ray log.
If you're going to use LAS 2.0 files and don't mind loading the entire file and then converting it all to JSON on the front-end, the best way to do that is to use the wellio.js library. We're also working on a conversion between JSON from LASIO.pys to WELLIO.js style JSON.
If you're not using wellio.js, getting the data into the front-end for JavaScript is done by functions you write.s
Wellioviz works with JSON templates.
These functions give you examples templates that you can simply add your data into.
Sensible defaults in a pre-packaged template that comes with wellioviz are combined with the reformatted data from the transformation step.
How the data should be plotted and what data should be plotted is turned into an SVG.
In addition to the 4 main groups of functions above, there are some odds and ends helper functions, mostly for getting templates and examples.
This brings in wellio.js as a dependency used by wellioviz. It returns the object that contains all its functions as a module that is called like "module.exports.wellio.[insert a wellio.js function here]"
obj
:
It returns the wellio.js object and all its functions as a module.
This brings in d3.js as a dependency used by wellioviz. It returns the d3.js object and all its functions as a module that is called like "module.exports.d3.[insert a d3.js function here]"
obj
:
It returns the d3.js object and all its functions as a module.
A function that directs users to the docs if they need help.
string
:
It says = I'm really no help. Please check out the docs at
https://justingosses.github.io/wellioviz/
or the main README.md at
https://github.com/JustinGOSSES/wellioviz
. \n If you would like to know what wellioviz does, try wellioviz.define(). \n If you would like to see an example template, try wellioviz.curveBoxTemplateExamples('example') \n If you would like to see an example template defintions, try wellioviz.curveBoxTemplateExamples('definitions') Best of luck.
A function that returns a short description of what the wellioviz library is all about.
string
:
Returns a string that defines wellioviz.
curveBoxTemplateExamples gives an example of the template giving to the plotting functions and definitions of the fields. A string of either "help" "example" or "definitions" is given as function argument and either a string or Object is returned depending on string provided as input parameter. This is used to help construct the JSON object that is given to the curveBox plotting function. Someone might run this function with "example" as the parameter, give back the JSON template, replace a few pieces with their own data or format choices and then pass it as the argument into the curveBox function.
(string)
A string of either "help" "example" or "definitions"
getFakeIncomingSparseDataExample is a function that takes nothing and returns a JSON of fake sparse incoming data. This is much less than the JSON wellio gives when it converts a LAS file into a JSON. This is one of the type examples of data input. It is an alternative to wellio.js style JSON. It is used next by funtion _ and .
array
:
returns an array that contains an object. probably just a single object? Many of the things like max and min depth that are auto-calculated when the input is a wellio JSON and instead explicitly defined here. This saves data transmission from a backend as well as front-end calculation time.
findDepthName is a function that takes in a wellio style JSON representation of the well log, looks at all the curve names and finds the one that is probably the depth curve, then returns it. This is useful for not plotting the depth curve.
(object)
a full wellio style JSON
string
:
returns a string representation of the curve name that is likely the depth curve. It assumes there is only one!
convertWellJSONToObj is a function that takes in wellio style JSON of all LAS file well log information, array of curves names, and a string for UWI and returns the data array of objects that D3.js likes for data used in plotting.
(object)
a full wellio style JSON
(array)
array of curve names as strings
(string)
a string the represents the well name
(any)
array
:
returns array of objects that contain key:value pairs of curve name and value at each depth. Depth is also a key:value pair.
fromJSONofWEllGetThingsForPlotting is a function that takes in wellio style JSON of all LAS file well log information, and returns an object that contains 3 things in an object format that are used in function ___ for plotting. the data array of objects that D3.js likes for data used in plotting.
(object)
a full wellio style JSON
(string)
String for the depth curve name
array
:
returns an object of 3 things that will eventually be used in plotting. {"well_log_curves_reformatted_for_d3":well_log_curves_reformatted_for_d3,"curve_names":curve_names,"uwi":uwi}
createDepthArray is a function that takes in a min float, max float, and step float value. and returns an array or depth values from the min to the max value going by the step value each step. This function is used to create a depth array for plotting when only the max, min, and depth is given explicitly in the input data. This might be done to avoid sending the depth curve from the backend to the front-end.
(float)
a float or integer that represents the top depth of an eventual array of depth values that this function creates.
(float)
a float or integer that represents the bottom depth of an array of depth values this function creates.
(float)
a float or integer that represents the interval the depth curve increases as you go from the top to the bottom of the depth curve this function creates.
array
:
returns an array of depth values from the min to the max by the step. AN EXAMPLE =
[10,10.5,11,11.5,12]
takeInArraysAndGetObjectOfCurveDataForPlotting is a function used to reformt arrays of curve values into a form that d3.js likes better, an array of objects. THIS FUNCTION NEEDS CHANGED IT IS TOO EXPLICIT !!!!!!!
(any)
(any)
(any)
convertWellJSONToObjV2 is a function that takes in sparse style JSON and other information and returns an array of that information properly packaged, array of curves names, and a string for UWI and returns the data array of objects that D3.js likes for data used in plotting.
(array)
An array of strings that can be parsed into floats that represents the depth along the well log curves in a curvebox.
(array)
An array of arrays of strings that can be parsed into floats that represents each of the well log curves in a curvebox.
(string)
A string for the well log UWI ID
(array)
An array of strings that represent curvenames, one for each well log curve in curve_data
array
:
An array of objects properly formatted for next step ___.
This function is used to put the incoming sparse style JSON information into the plotting tempalte JSON that is given to curveBox which then handles the plotting.
(object)
This is a JSON object of incoming sparse style data & plotting instructions.
(object)
This is a JSON example template of the type typically given to the curveBox function. The user will use if for defaults and replace the data and formatting options they want to change.
THE FUNCTION putArrayOfLogsIntoSection NEEDS DOCUMENTATION!
(any)
(any)
(any)
(any)
(any)
(any)
(any)
(any)
(any)
(any)
minimumDataIntoTemplateFunc
(any)
(any)
(any)
(any)
(any)
(any)
(any)
(any)
(any)
(any)
(any)
CurveBox is the central function to wellioviz in a lot of ways, not least as it holds the d3.js code. It takes a JSOn template, appends the resulting SVG to a defined DIV.
(any)
(object)
any
:
SVG.node() But its main function is to append this SVG to a DIV given in the template that is the single parameter.
This function is used to quickly plot multiple curves as separate curveboxes and taking into consideration a list of curves to skip and some basic pre-built styles, both given as arguments.
(array)
An array of objects. Each object is a depth point with key:value pairs of curve name and value.
This was likely created by the three_things_2 function and returned like so: well_log_curves_reformatted_for_d3_2 = three_things_2
["well_log_curves_reformatted_for_d3"]
(array)
An array of strings for curve names to skip plotting.
(object)
An object that maps curve names to style and styles to
basic style config like fill color
(any)
(any)
array
:
array_of_jsons_for_what_to_plot - An array of objects for each curve to be plotted in its
curvebox via the curveBox() function or another function that funnels into curvebox.
This function is used to plot multiple curveboxes in a row. AKA makes a cross-section. It calls curveBox multiple times.
(string)
a string that represents the div ID that the multiple curveboxes will be appended to
(object)
An array of CurveBox input templates
(boolean
= true
)
is a boolean value that decides whether or not multiple plots are shown in a multiple log plot div. If show_all is false however, the developer must switch their CSS to be "inline-block" one at a time via some other means. If they don't,none will appear!
(any
= true
)
This function is used to plot a single curveboxe in the div listed in the plotting templates div_id key. When called it removes anything that is a child of the div listed in div_id before appending a new curveBox there.
(string)
A JSON of all the information needed to be plotted using the format of wellioviz exactly.
string
:
curve_box_return - A string representation of the SVG variable called SVG. This can be fiven to the saveSvg function to save the SVG as a file with .svg ending.
This function is used to save a given SVG element with a given name. It creates a download link div which is then used to download the SVG file. In certain environments, this may not work for security reasons.
convertWellJSONToObj is a function that takes in wellio style JSON of all LAS file well log information, array of curves names, and a string for UWI and returns the data array of objects that D3.js likes for data used in plotting.
array
:
returns array of objects that contain key:value pairs of curve name and value at each depth. Depth is also a key:value pair.