Start with Libraries
- Open Python, or open Python editor in Log Viewer, Crossplot or Histogram.
- Choose the Libraries tab below the editor. Viewing the catalogue does not start Python or download packages.
- Find a package and choose Load. This starts the kernel if needed, then downloads the package and its dependencies. A LAS is not required. Alternatively, put the package's ordinary import statement in your script and press Run.
- Insert import inserts the suggested code at the editor cursor; Copy import copies it. These actions do not execute the code.
- The card reports Available, Loading…, Loaded with the installed version, or Could not load with the error. Use Retry after a failed load.
Only NumPy and the website's local petrophysics module load at kernel startup. The other scientific packages load when requested; opening the editor does not preload the whole catalogue. The Python standard library is part of the runtime. A first run or package download needs an Internet connection. Browser caching can reduce subsequent downloads, but offline availability is not guaranteed.
Package loading keeps editor text, committed curves, output and figures. Run, New script and Reset kernel are disabled while the dedicated loader is busy; Stop cancels the operation by resetting the worker. Loading packages does not run your analysis script. New script keeps the current kernel and packages. Reset kernel, Stop, source removal, loading another LAS and switching LAS datasets create a fresh kernel: optional packages must be loaded again, either from their imports or with Load. Each tool page has its own kernel; Lock dock shares the LAS and selected dataset, not installed packages or variables.
Catalogue and import syntax
v23 uses the pinned Pyodide 314.0.7 distribution. Package versions come from that distribution and appear in Libraries after loading. lasio is separately pinned to 0.32. A package's distribution name and Python import name can differ: choose scikit-learn in Libraries but write import sklearn; choose PyWavelets but write import pywt.
| Library | Python import | Typical use here | Loading |
|---|---|---|---|
| NumPy | import numpy as np | Curve arrays, masks, numerical calculations | Kernel startup |
| pandas | import pandas as pd | Well/table DataFrames, grouping, missing values | Load or import |
| SciPy | import scipy | Fitting, interpolation, statistics, signal processing | Load or import |
| Matplotlib | import matplotlib.pyplot as plt | Figures in the Python Plots tab | Load or import |
| scikit-learn | import sklearn | Regression, clustering, preprocessing | Load or import |
| statsmodels | import statsmodels.api as sm | Statistical regression and diagnostics | Load or import |
| SymPy | import sympy as sp | Symbolic equations and derivatives | Load or import |
| XGBoost | import xgboost as xgb | CPU gradient boosting on tabular data | Load or import |
| PyWavelets | import pywt | Wavelet transforms of sampled curves | Load or import |
| xarray | import xarray as xr | Arrays with named dimensions and coordinates | Load or import |
| NetworkX | import networkx as nx | Graph relationships and paths | Load or import |
| uncertainties | from uncertainties import ufloat | Propagate measurement uncertainties | Load or import |
| micropip | import micropip | Install additional compatible Python wheels | Load or import |
| lasio 0.32 | import lasio | Optional Python LAS reading/writing | Load or static import; installed through micropip |
| petrophysics | import petrophysics | Website curve/dataset API; well is supplied for each run | Local module at kernel startup |
| Python standard library | import math, json, datetime, statistics, etc. | Ordinary Python utilities | Part of the runtime |
Static imports such as from scipy.optimize import curve_fit also trigger package loading. A dynamically constructed import such as importlib.import_module(package_name) may not be detected in advance: use Libraries → Load first. Dependencies can appear as loaded even if you did not request them separately. The catalogue covers these 14 external packages, rather than every module in Python or every package published on PyPI.
First script: arrays, tables and a figure
This example needs no LAS. Printed output appears in Output; the figure appears in Plots after the run succeeds.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
depth = np.arange(1000.0, 1010.0, 0.5)
gr = 65 + 18 * np.sin(np.arange(depth.size) / 3)
frame = pd.DataFrame({"Depth": depth, "GR": gr})
print(frame.describe())
fig, ax = plt.subplots(figsize=(6, 3))
ax.plot(depth, gr)
ax.set(xlabel="Depth, m", ylabel="GR, API", title="Synthetic example")
fig.tight_layout()
SciPy: fit a numerical model
No LAS is needed. This fits a simple synthetic exponential, then prints the fitted parameters and their approximate standard errors.
import numpy as np
from scipy.optimize import curve_fit
def model(x, amplitude, rate):
return amplitude * np.exp(-rate * x)
x = np.linspace(0, 5, 30)
rng = np.random.default_rng(7)
y = model(x, 2.5, 0.7) + rng.normal(0, 0.025, x.size)
parameters, covariance = curve_fit(model, x, y, p0=(2.0, 0.5))
print("Amplitude, rate:", parameters)
print("Approximate standard errors:", np.sqrt(np.diag(covariance)))
scikit-learn: regression and clustering
Run this example without a LAS. A fitted cluster number is only a mathematical label; interpreting it as lithology or a rock type requires your own geological calibration.
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
x = np.arange(12.0).reshape(-1, 1)
y = 3.0 + 2.0 * x[:, 0]
regression = LinearRegression().fit(x, y)
print("Slope:", regression.coef_, "Intercept:", regression.intercept_)
print("Prediction at 12:", regression.predict([[12.0]]))
features = np.array([[20, 2.20], [25, 2.23], [30, 2.25],
[100, 2.60], [105, 2.63], [110, 2.66]])
scaled = StandardScaler().fit_transform(features)
clusters = KMeans(n_clusters=2, random_state=7, n_init=10).fit_predict(scaled)
print("Synthetic cluster labels:", clusters)
statsmodels and symbolic mathematics
These are separate examples and need no LAS. OLS receives an explicit constant column for its intercept.
import numpy as np
import statsmodels.api as sm
x = np.arange(20.0)
y = 4 + 1.5 * x + 0.2 * np.sin(x)
fit = sm.OLS(y, sm.add_constant(x)).fit()
print("Intercept, slope:", fit.params)
print("R squared:", fit.rsquared)
print("Parameter standard errors:", fit.bse)
import sympy as sp
phi, a, rw, rt, m, n = sp.symbols("phi a rw rt m n", positive=True)
sw = (a * rw / (rt * phi**m)) ** (1 / n)
print("Symbolic Archie Sw:", sw)
print("Derivative with respect to porosity:", sp.diff(sw, phi))
XGBoost on the CPU
This is a small, synthetic regression example without a LAS. Use CPU settings and small training sets to begin; browser Python does not provide CUDA/GPU training.
import numpy as np
from xgboost import XGBRegressor
rng = np.random.default_rng(7)
features = rng.normal(size=(64, 2))
target = 2 * features[:, 0] - features[:, 1]
model = XGBRegressor(n_estimators=8, max_depth=2, tree_method="hist",
device="cpu", n_jobs=1, random_state=7)
model.fit(features, target)
print("First three predictions:", model.predict(features[:3]))
Wavelets, named arrays, graphs and uncertainty
Each example is independent and needs no LAS.
import numpy as np
import pywt
signal = np.sin(np.linspace(0, 4 * np.pi, 32))
approximation, detail = pywt.dwt(signal, "db2")
print("Wavelet coefficient sizes:", approximation.size, detail.size)
import xarray as xr
curve = xr.DataArray([30.0, 45.0, 70.0], dims=["depth"],
coords={"depth": [1000.0, 1000.5, 1001.0]}, name="GR")
print(curve)
print("Mean:", float(curve.mean()))
import networkx as nx
graph = nx.Graph()
graph.add_edges_from([("Well A", "Layer 1"), ("Layer 1", "Well B")])
print(nx.shortest_path(graph, "Well A", "Well B"))
from uncertainties import ufloat
rho_matrix = ufloat(2.65, 0.02)
rho_bulk = ufloat(2.35, 0.01)
rho_fluid = ufloat(1.00, 0.01)
porosity = (rho_matrix - rho_bulk) / (rho_matrix - rho_fluid)
print("Porosity with propagated uncertainty:", porosity)
The example uncertainties are illustrative. Their interpretation depends on how the input uncertainties and correlations were estimated. well.add_curve() accepts numeric values, so publish nominal values or a separate standard-deviation curve rather than uncertainty objects themselves.
Work with your loaded LAS
The website supplies well automatically at each run. With no LAS, well is None. Use the existing snapshot directly; installing lasio is not required to calculate curves.
import numpy as np
import pandas as pd
if well is None:
print("Load a LAS to inspect its tables.")
else:
print(well.name, well.las_version, well.dataset_id)
frame = well.to_dataframe()
print(frame.head())
print(frame.attrs["units"])
for table in well.datasets:
print(table.id, table.name, table.row_count)
another_table = well.dataset(well.datasets[-1].id)
print(another_table.to_dataframe().head())
For a model, clean missing samples before fitting, and put predictions back into an array with the original row count before publishing. This example requires unique numeric GR and RHOB curves. Its regression is a coding demonstration; calibrate and validate any model before interpreting predicted density.
import numpy as np
from sklearn.linear_model import LinearRegression
if well is None:
raise ValueError("Load a LAS with GR and RHOB first.")
gr = well["GR"]
rhob = well["RHOB"]
training = np.isfinite(gr) & np.isfinite(rhob)
if training.sum() < 3:
raise ValueError("Need at least three valid GR/RHOB pairs.")
model = LinearRegression().fit(gr[training, None], rhob[training])
predicted = np.full(well.row_count, np.nan)
usable = np.isfinite(gr)
predicted[usable] = model.predict(gr[usable, None])
well.add_curve("RHOB_REG", predicted, unit=well.curve("RHOB").unit,
description="Illustrative linear prediction from GR")
print("Training samples:", training.sum())
Only the active table receives published curves. Accessing another table through well.dataset(...) does not switch the site's selection. Numeric plots use numeric data; LAS 3.0 text/date fields remain typed object arrays in Python. Convert dates explicitly with a known format if needed. See LAS formats and datasets and the Python workspace API.
Optional lasio 0.32
Use Libraries → lasio → Load, or a static import lasio statement. v23 installs the pinned compatible wheel through micropip before the script runs. This is an additional Python utility; the website continues to use its shared JavaScript LAS reader for uploads, table selection, Lock dock and export. lasio documents complete LAS 1.2/2.0 support and partial LAS 3.0 support, so it does not replace the site's multiple-table/typed LAS 3.0 handling.
This self-contained example reads LAS text in memory and needs no uploaded LAS:
import io
import lasio
text = """~Version
VERS. 2.0 : LAS version
WRAP. NO : Unwrapped
~Well
STRT.M 1000 : Start
STOP.M 1001 : Stop
STEP.M 1 : Step
NULL. -999.25 : Missing
WELL. SYNTHETIC : Well
~Curve
DEPT.M : Depth
GR.API : Gamma ray
~ASCII
1000 30
1001 75
"""
las = lasio.read(io.StringIO(text))
print("lasio version:", lasio.__version__)
print(las["GR"])
An uploaded LAS is supplied as well and its tables; it is not automatically mounted as a Python file at well.filename. Do not use lasio.read("C:/Users/.../well.las") to access your computer. For routine calculations, use well.to_dataframe() or well.curve(...). When you already have LAS text in a Python variable, use io.StringIO as above. The website's Download original LAS and Export LAS buttons provide actual browser downloads.
micropip and additional wheels
The normal loader already installs lasio. An explicit equivalent, useful when learning micropip, is:
import micropip
await micropip.install("lasio==0.32")
import lasio
print(lasio.__version__)
The editor supports top-level await. micropip can install pure-Python wheels and compatible Pyodide/WebAssembly wheels. A Linux, Windows or macOS native wheel is not compatible just because it works in desktop Python. A custom wheel URL must permit browser cross-origin access (CORS); package repositories and download hosts also need to be reachable from your network. Shell pip install ... commands are not Python code for this editor. Additional packages are outside the curated catalogue; their compatibility must be checked separately. Installation affects the current worker kernel and does not add files to your GitHub repository or Render server.
Browser limits and saved work
- Python and calculations run in a browser Web Worker, not a Python process on Render. Available memory and CPU depend on the user's device. Large DataFrame copies, large models and expensive fitting can exhaust browser resources.
- The workspace does not provide an OS shell, subprocesses, desktop GUI windows or CUDA/GPU computing. Packages may have individual functions that depend on facilities unavailable in browser Python.
- Python file paths refer to its browser virtual filesystem, not your computer's folders. Temporary files disappear with kernel reset/reload unless downloaded explicitly through a supported workflow. Save .py downloads your code; Save project retains code/results with a loaded LAS. Installing packages does not save Python variables or trained models.
- Matplotlib uses the non-interactive Agg backend. Successful runs collect up to four PNG figures of at most 8 MiB each in Plots. Do not close a figure before collection if you want to see it. There is no desktop Matplotlib window.
- Run time limits, output limits and result-curve validation still apply. Published curves must be 1D real numeric arrays with one value per active source row; missing values may be NaN, infinities cannot be published. Save work before changing source or resetting the kernel.
- Run initialization has a separate 180-second limit; a manual Libraries load has 300 seconds. The selected script execution limit starts after its required packages have loaded. Stop remains available if an operation stalls.
- Package versions are pinned through the chosen Pyodide distribution, with lasio fixed at 0.32. Installing a different version manually may conflict with these dependencies. Libraries shows the versions detected in the current kernel; consult the release's validation notes for the packages actually exercised in its checks.
JavaScript / agent access
const catalogue = Petrophysics.get_python_libraries();
console.log(catalogue.runtimeReady, catalogue.packages);
await Petrophysics.load_python_libraries({
packageIds: ["scikit-learn", "pywavelets", "lasio"]
});
const after = Petrophysics.get_python_libraries();
console.log(after.packages);
await Petrophysics.run_python({code: "import lasio\nprint(lasio.__version__)"});
Reading the catalogue does not start Python. Loading uses distribution IDs from that catalogue; it does not run a script. get_python_status().loadingLibraries distinguishes library work, while running reports that the Python workspace is busy. Wait for loading to finish before running an analysis or changing the source. These commands are available in all four tools.
Official references
The website-specific instructions above describe v23's loader and snapshot API. General package behavior is documented by the package maintainers:
- Pyodide package catalogue, package loading, browser Python constraints, and micropip usage.
- SciPy curve_fit, scikit-learn LinearRegression, KMeans, and statsmodels OLS.
- SymPy calculus, XGBoost Python API, PyWavelets DWT, and xarray DataArray.
- NetworkX paths, uncertainties guide, and lasio documentation.