petroplots¶
Publication-quality well log plots for matplotlib.
DataFrames in, Figure out. No file parsing,
no petrophysical calculations, no well data model. lasio, welly and
dlisio already do those better.
import petroplots as pp
df = pp.datasets.load_example()
plot = pp.LogPlot(df, top=2000, bottom=2100)
plot.add_depth(interval=10)
gr = plot.add_track()
gr.add_curve("GR", limits=(0, 150), units="API")
nd = plot.add_track()
nd.add_curve("RHOB", limits=(1.9, 2.9), units="g/cm3")
nd.add_curve("NPHI", limits=(0.45, -0.05), units="v/v")
nd.crossover()
plot.add_facies("FACIES", pp.LITHOLOGY_FGDC, style="patches")
fig, axes = plot.render()
The same vocabulary carries across the other plot types, so a facies colour, a curve range and a formation column mean the same thing in each of them:
df = pp.add_tops(df, "field_tops.csv", well="15/9-19 A")
pp.crossplot(df, "NPHI", "RHOB", color="GR", color_steps=6)
pp.crossplot(df, "PHIT", "PERM", by="FORMATION", color="FACIES",
scheme=pp.LITHOLOGY)
pp.histogram(df, "PHIT", by="FORMATION")
The top level holds the entry points above, plus the schemes, swatches, curve conventions and errors shared between plot types. Anything specific to one kind of plot lives in that plot’s package.
Using petroplots
- Getting started
- Building a plot
- Adding tracks: every method and option
plot.add_track(**options)track.add_curve(name, limits=None, **options)plot.add_curves(curves, limits=None, **options)plot.add_fill(curves, limits=None, crossover=False, **options)plot.add_facies(curve, scheme=None, **options)plot.add_flag(condition, **options)plot.add_depth(curve=None, **options)plot.add(track)- Changing options after construction
- Tracks
- Facies schemes
- Lithology swatches
- Crossplots
- Histograms
- Templates
- Loading data
- Styling
- Gallery
Reference
Why this exists¶
Plotting a well log in matplotlib takes roughly 150 lines, and they are much
the same every time: invert the depth axis once on the shared axis, call
tick_top() on every track, build a ListedColormap and BoundaryNorm
so a facies colour means the same thing in every well, add proxy Patch
handles because imshow produces no legend entries, and set gridspec_kw
width ratios to size a narrow facies track beside wide curve tracks.
What it handles that hand-rolled versions get wrong¶
These failures produce a figure that renders without error and reports something incorrect.
A facies colour means the same thing in every well.
FaciesScheme builds its norm from the declared class set,
never from the data. imshow autoscales its norm to whatever array it is
given, so a well that contains no limestone recolours its sandstone.
Legend entries are built for artists that have none. Neither an image nor a fill produces legend handles, so every track builds its own proxies. Patterned swatches get a custom handler, which puts the ornament in the key.
The depth axis is inverted once, on the shared axis, after all tracks have drawn. Two tracks each inverting it leaves it the right way up.
Layer edges sit at sample midpoints, which avoids both a hairline at every contact and an overlap that hides thin beds.
Crossover shading is computed in normalised space. Density and neutron are recorded on incompatible scales, so “where NPHI is left of RHOB” only has a meaning once both are mapped onto their own display limits. Shading computed without that step marks the wrong intervals.
Limits are set after drawing, never during. Matplotlib autoscales as artists are added, so a limit set mid-draw is overridden by the next artist on the same axes.
Install¶
pip install petroplots # core: matplotlib, numpy, pandas
pip install petroplots[las] # + lasio, for pp.io.from_las()
pip install petroplots[yaml] # + PyYAML, for templates
pip install petroplots[test] # + pytest, pytest-mpl
Python 3.10+. import petroplots pulls in nothing heavier than matplotlib,
numpy and pandas. seaborn, scipy, lasio and yaml are all lazy.
Where to go next¶
If you want to… |
Read |
|---|---|
Get a figure in five minutes |
|
Build plots from a loop, a config or a UI |
|
Look up an |
|
Understand track composition |
|
Drive petroplots from a UI |
|
Make facies colours consistent across a field |
|
Add FGDC lithology ornament |
|
Plot two curves against each other |
|
Split a plot into one panel per formation |
|
Look at the distribution of one curve |
|
Get a tops file onto the frame |
|
Apply one plot definition to 40 wells |
|
Get a LAS file into a plottable frame |
Licence¶
MIT. Lithology patterns follow the FGDC Digital Cartographic Standard for Geologic Map Symbolization (USGS, public domain); the geometry is reimplemented parametrically and no artwork is redistributed. Bundled example data is synthetic. See The bundled example.