Drillhole creation and quick visualisation#

In this notebook we use the GeoLime library to create our Drillhole objects and produce some interactive visualisations of the data.

We also use the library pyproj to handle Coordinates Reference Systems (CRS) and help us display data on a map with a background.

The library pyvista is used to visualise data in 3D.

Again, the pandas library is utilised to read the assay file obtained in the cleaning previous notebooks.

import geolime as geo
from pyproj import CRS
import pyvista as pv
import pandas as pd

pv.set_jupyter_backend('html')
geo.Project().set_crs(CRS("EPSG:20350"))

GeoLime Drillholes Creation#

This section uses the GeoLime library to draw an interactive map of the iron concentration.

First we need to import the collar and survey file to have all the spatial information about the drillholes.

Note

Survey File Survey File was created as it is not provided by the CSIRO. In this case of vertical drillholes, a survey file is optionnal as GeoLime will consider it automatically. For the purpose of this a survey file is however created in order to behave like most cases.

survey = geo.datasets.load("rocklea_dome/survey.csv")
collar = geo.datasets.load("rocklea_dome/collar.csv")
assay = pd.read_csv("../data/assay_hyper.csv")

Project CRS Definition#

The CRS can be set using the geo.Project().set_crs method, allowing the user to define CRS parameters on a project scale, eliminating the need to set CRS for all individual objects.

geo.Project().set_crs(CRS("EPSG:20350"))

Drillholes Creation#

Drillholes are a specific type of GeoLime object which encapsulate all the information which defines a drillhole, including the collar, assay, and survey files.

We can create a drillhole using the geo.create_drillholes() method, giving a name, and pointing at our collar, assay and survey files.

dh = geo.create_drillholes(
    name="rck_assay", 
    collar=collar, 
    assays=assay, 
    survey=survey
)
2025-09-25 12:02:51,133 [INFO] GeoLime Project - |GEOLIME|.drillholes_api.py : Following mapping has been identified: {
    "HOLEID": "Hole_ID",
    "X_COLLAR": "X",
    "Y_COLLAR": "Y",
    "Z_COLLAR": "RL_AHD",
    "AZIMUTH": "Azi_mag",
    "DEPTH_SURVEY": "Distance",
    "DIP": "Dip",
    "FROM": "From",
    "TO": "To"
}

Like Pandas library, GeoLime uses the describe method to quickly access to the aggregated statistics of an object.

dh.describe()
__TOPO_LEVEL__ __TOPO_TYPE__ __TOPO_ELEMENT_V1__ __TOPO_ELEMENT_V2__ FROM TO X_COLLAR Y_COLLAR Z_COLLAR X_M ... SiO2 MnO Mn CaO K2O MgO Na2O TiO2 LOI_100 Depth
count 7108.0 7108.0 7108.000000 7108.000000 7108.000000 7108.000000 7108.000000 7.108000e+03 7108.000000 7108.000000 ... 7036.000000 7036.0 7036.000000 7036.000000 7036.000000 7036.000000 7036.000000 7036.000000 7036.000000 7108.000000
mean 2.0 1.0 3649.240293 3650.240293 20.568655 21.568655 547413.687521 7.475481e+06 458.500774 547413.687521 ... 20.022739 0.0 0.058710 1.061883 0.130430 0.885746 0.001279 0.448157 0.000007 42.645751
std 0.0 0.0 2111.443717 2111.443717 13.834178 13.834178 685.729896 1.587386e+03 7.467718 685.729896 ... 21.012233 0.0 0.133017 3.609818 0.491768 1.982652 0.107295 0.537459 0.000608 11.275263
min 2.0 1.0 0.000000 1.000000 0.000000 1.000000 545494.900000 7.472793e+06 441.000000 545494.900000 ... 0.000000 0.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 7.000000
25% 2.0 1.0 1816.750000 1817.750000 9.000000 10.000000 546904.700000 7.474003e+06 453.800000 546904.700000 ... 0.000000 0.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 36.000000
50% 2.0 1.0 3650.500000 3651.500000 19.000000 20.000000 547586.100000 7.475604e+06 458.200000 547586.100000 ... 12.735000 0.0 0.010000 0.110000 0.025000 0.310000 0.000000 0.267000 0.000000 46.000000
75% 2.0 1.0 5479.250000 5480.250000 31.000000 32.000000 547947.600000 7.476004e+06 463.600000 547947.600000 ... 33.555000 0.0 0.090000 0.300000 0.082000 0.720000 0.000000 0.692000 0.000000 51.000000
max 2.0 1.0 7298.000000 7299.000000 60.000000 61.000000 548498.100000 7.479595e+06 478.600000 548498.100000 ... 92.810000 0.0 6.160000 40.820000 21.250000 20.010000 9.000000 10.000000 0.051000 61.000000

8 rows × 51 columns

The basic properties of a drillholes object already have unit specify.

dh.property("X_M").unit
meter

Unit can also be specified in the Project for each property.

Property units are managed using the Pint python package (Pint). Default unit are already available (Pint Units) and other can be added to a GeoLime project.

This will allow to specify the percent property to each property of a GeoLime object.

geo.Project().unit_registry.define("percent = 1e-2 frac = pct")

Using the percent unit defined, we can now specify it to all other related property, especially the ones with _pct in their names.

for prop in dh.properties():
    if "_pct" in dh.property(prop).name:
        dh.property(prop).unit = geo.Project().unit_registry.pct
dh.property("Fe_pct").unit
percent

Graphic representations#

Most GeoLime objects are 3D objects (Drillholes, BlockModels) and their values must be “aggregated” in order to easily visualise them on 2D map. Drillholes are aggregated along the hole and BlockModels are aggregated within a “column” of Blocks, this being the blocks with the same X and Y coordinates.

For the following 2d plot, we use a mean average aggregation method to aggregate the average Iron concentration and display it on our interactive 2d map.

dh.plot_2d(property="Fe", agg_method="mean", interactive_map=True)
Make this Notebook Trusted to load map: File -> Trust Notebook

Points with no value can be hidden using extra keywords from the folium library: Folium

Here the fillColor keyword is used to assign no colour fill to all drillhole locations. Only holes with Fe percentages are now visible.

dh.plot_2d(property="Fe_pct", agg_method="mean", interactive_map=True, style_kwds={"fillColor": "none"})
Make this Notebook Trusted to load map: File -> Trust Notebook

Aggregation along axes can be plotted using the scatter function. Unlike a cross section where only a slice is viewed, here all data are visualised.

In drillholes objects there are 3 coordinates availables for each composite :

  • the coordinates of the begininng of the composites (X_B, Y_B and Z_B)

  • the coordinates of the midpoint of the composites (X_M, Y_M and Z_M)

  • the coordinates of the end of the composites (X_E, Y_E and Z_E)

Midpoints are the coordinates used in most of the algorithms.

geo.scatter(geo_object=dh, property_x="X_M", property_y="Z_M")
geo.scatter(geo_object=dh, property_x="Y_M", property_y="Z_M")

Exploratory Analysis#

Data can be visualised in 3D using the pyvista library. Any Object can be converted to a pyvista object using the to_pyvista method.

First, a drillhole is converted to a pyvista object

df_pv = dh.to_pyvista('Fe_pct')

Using the pyvista library scene creation we can then visualise data in 3D. A vertical exageration is applied for easier visualisation of the drillholes (set_scale(zscale=20))

pl = pv.Plotter()
pl.add_mesh(df_pv.tube(radius=10))
pl.set_scale(zscale=20)

pl.show()

Geological section#

scatter function can also be used to view a cross section by using the region parameter and providing spatial thresholds (X or Y coordinate limits) in order to define a specific section for visualisation.

Here, the Y coordinate is used to define a slice through the data.

geo.scatter(
    geo_object=dh, 
    property_x="X_M", 
    property_y="FROM", 
    region="(Y_M > 7475791.8 - 400) &  (Y_M < 7475791.8 + 400)"
)

Scatter function takes also into account all layout properties from plotly : https://plotly.com/python/reference/layout/.

As GeoLime plotting functions returns Plotly Figure, they can be stored in a variable.

f = geo.scatter(
    geo_object=dh, 
    property_x="X_M", 
    property_y="FROM", 
    region="(Y_M > 7475791.8 - 20) &  (Y_M < 7475791.8 + 20)", 
    yaxis_autorange="reversed"
)

Plotly figures can then be exported to

  • standard image format (PNG, PDF, JPEG) for static export

  • HTML format for interactive export and sharing only figure without code

  • JSON format to be used in other software or in a Web Application

  • python dictionnary to understand figure architecture and modify every elements

f.write_image("../data/dh_section.png")

Using the plotly figure properties we can change the color of the plot by setting a property from the drillholes. Here we colour the points using the Iron content (Fe_Pct)

First, we specify the property to be used as our drillhole colour, and a region bounded by Y coordinates

We then choose a line width of 0 for easy visualisation

We then define the Fe percentage as our colorbar reference property

And finally we select a perceptually uniform colourscale ‘cividis’

f["data"][0]["marker"]["color"] = dh.data("Fe_pct", "(Y_M > 7475791.8 - 20) & (Y_M < 7475791.8 + 20)")
f["data"][0]["marker"]["line"]["width"] = 0
f["data"][0]["marker"]["colorbar"] = dict(title = 'Fe_pct')
f["data"][0]["marker"]["colorscale"] = "cividis"
f

Correlations between elements#

GeoLime includes the capability to create correlation heatmaps between elements. Here, various mineral properties from the drillhole are correlated in an interactive heatmap display.

geo.correlation_heatmap(
    geo_object=dh, 
    properties=[
        "Mn_pct", "P_pct", "Fe_pct", "CaO_pct", "MgO_pct", "S_pct", "Al2O3", "TiO2_pct", "SiO2_pct", "K2O_pct"
    ]
)

Several minerals show strong correlation. Relationships can be further established using scatterplots and Histogram displays.

Here we use a scatterplot with an associated histogram to visualise any potential relationship between the Aluminium Oxide (Al2O3) and Iron (Fe_pct) concentrations.

geo.scatter(geo_object=dh, property_x="Al2O3", property_y="Fe_pct", marginal_plot=geo.ScatterMethod.HISTOGRAM)

We see a strong negative correlation between the AL2O3 and Iron concentration.

Histograms#

geo.histogram_plot(data=[{"object": dh, "property": "Fe_pct"}])

Bin number can also be specified.

geo.histogram_plot(data=[{"object": dh, "property": "Al2O3"}], nbins=30)

Here we can see a bimodal distribution of Fe_pct, with a cluster around 5-10m, and a second around 50m depth.

Multiple histograms can also be shown on the same figure. Here using the region parameter it is possible to visualise the histogram of the iron values where silica values are lower and higher than 20 %.

geo.histogram_plot(
    data=[
        {"object": dh, "property": "Fe_pct", "region":"SiO2 < 20"},
        {"object": dh, "property": "Fe_pct", "region":"SiO2 >= 20"} 
    ], 
    nbins=30
)

A strong negative correlation is seen between the SiO2 and Fe concentration.

Export File#

For faster import/export and ease of use, instead of exporting the drillholes into csv, GeoLime has its own format. To export an object, use the to_file method.

Files are saved with a .geo extension

dh.to_file("../data/dh_hyper")

Conclusions#

The analysis shown in this notebook indicates the main element of interest in this area is Iron, mainly as an oxide (likely Hematite/Goethite).

Secondly, the geological sections and various scatterplots show us that the iron is concentrated in two distinct deposits, at approximately 10m and 50m depth.

Strongly negative correlations are seen between Fe concentration and SiO2, typical of a paleochannel iron deposit in this region.

In the next notebook we will look at domaining workflows, where we will use our drillholes to divide the deposit into various domains based on geology, geochemistry, mineralogy, grade etc.