Durov Diagram
A composite hydrochemical chart that pairs two ternary diagrams with a central rectangular field — extending the Piper diagram with total dissolved solids and pH axes to classify water samples.
// 01 — The chart
What it looks like
A Durov diagram classifying 8 groundwater samples by major ion composition, TDS, and pH.
// 02 — Definition
What is a Durov diagram?
A Durov diagram is a composite hydrochemical plot used to classify natural water samples based on their major ion chemistry. It was introduced by S.A. Durov in 1948 as an extension of the Piper diagram, adding two additional axes — total dissolved solids (TDS) and pH — to provide richer context about water quality.
The diagram consists of two ternary (triangular) plots — one for cations (calcium, magnesium, sodium+potassium) and one for anions (bicarbonate, sulfate, chloride) — that project into a central rectangular field. Each water sample appears as a single point in this central square, with its position determined by the dominant cation and anion proportions.
The central rectangle is then extended by two additional axes along its edges: TDS on the bottom and pH on the right. This lets hydrochemists see not only the water type (based on ion dominance) but also the mineralization level and acidity in a single view — a key advantage over simpler diagrams.
Because the input requires complete major-ion analyses converted to milliequivalents per liter, the chart is squarely a tool for trained hydrochemists and environmental scientists. It is the workhorse plot in groundwater contamination studies, aquifer characterization, and regulatory water-quality assessments worldwide.
Origin: Published by S.A. Durov in 1948, the Durov diagram was developed specifically to address limitations in the Piper diagram by incorporating TDS and pH, two parameters critical for understanding water’s overall quality and geochemical evolution.
// 03 — When to use
When a Durov diagram is the right call
Reach for a Durov diagram when you need a single figure that classifies multiple water samples by ion composition while simultaneously showing TDS and pH context.
- Classifying groundwater, springs, or surface-water samples by hydrochemical type
- Comparing many samples on a single composite figure
- You need ion proportions plus TDS and pH in one view
- Tracking groundwater contamination or saltwater intrusion over time
- Characterizing aquifers in a regional hydrogeology study
- Producing a regulatory water-quality assessment report
- Inferring geochemical evolution along a flow path
// 04 — When not to use
When a Durov diagram is the wrong call
The chart presupposes complete major-ion data and a numerate audience. Outside that, simpler hydrochemistry charts win.
- Your audience is unfamiliar with ternary plots and meq/L units
- You only have one or two samples — a results table is clearer
- Ion data is incomplete (a sample missing one major cation can’t be plotted)
- A simpler Piper diagram answers the same question
- You need per-sample ion fingerprints — use a Stiff diagram instead
- You need absolute concentrations — use a Schoeller diagram instead
- You need a spatial map showing sample locations on a basin map
// 05 — Data requirements
What your data needs to look like
Before building the chart, your dataset needs to fit a specific shape. Use this checklist to confirm yours does.
Shape
One row per water sample. Major ion concentrations in mg/L plus TDS (mg/L) and pH (0–14 scale).
Minimum rows
3 samples. Below that a results table communicates better.
Maximum rows
A few hundred per panel. Above that, color or facet by hydrogeologic group to keep the central rectangle readable.
An identifier for each water sample (well number, sampling station, date code).
Major cation concentrations in milligrams per liter. Converted to meq/L and then to percentages of the cation sum.
Major anion concentrations in milligrams per liter. Converted to meq/L and then to percentages of the anion sum.
Total dissolved solids — used to position the sample on the bottom side axis.
Sample pH — used to position the sample on the right side axis.
| sample_id | Ca | Mg | Na | K | HCO3 | SO4 | Cl | TDS | pH |
|---|---|---|---|---|---|---|---|---|---|
| W1 | 90 | 22 | 18 | 3 | 320 | 25 | 30 | 430 | 7.5 |
| W2 | 75 | 18 | 22 | 4 | 280 | 20 | 35 | 380 | 7.6 |
| W7 | 35 | 9 | 220 | 10 | 80 | 60 | 380 | 1700 | 7.9 |
Tip: the cation–anion charge balance must agree within ~5–10%. If |Σcations − Σanions| / 0.5(Σcations + Σanions) exceeds 0.10, the analysis is suspect and the sample should be flagged.
// 06 — Anatomy
Parts of a Durov diagram
Four pieces define the layout: the cation ternary, the central rectangle, the TDS strip, and the pH strip. The anion ternary mirrors the cation ternary on the opposite side.
// 07 — Step-by-step
Step-by-step: how to build a good Durov diagram
Eight steps that work regardless of tool. The unit conversion and charge-balance check are non-negotiable; everything else is layout.
- 1
Collect a complete major-ion analysis per sample
Every sample must have all six major ions (Ca, Mg, Na+K, HCO3, SO4, Cl), TDS, and pH. Missing any one ion makes the sample unplottable on the ternaries. - 2
Convert mg/L to meq/L
For each ion, divide by atomic weight and multiply by absolute charge: meq/L = mg/L × |valence| / atomic weight. Sum all cations; sum all anions. - 3
Check the cation–anion balance
Total cations and total anions in meq/L should match within ~5–10%. Larger imbalances indicate analytical error and the sample should be flagged or excluded. - 4
Compute percentage compositions
For each cation, divide by the cation sum and multiply by 100. Repeat for anions. The ternaries plot percentages, not raw concentrations. - 5
Project samples into the central rectangle
The cation percentage projects onto the rectangle’s x-axis; the anion percentage projects onto its y-axis. Each sample becomes one point in the central field. - 6
Place samples on TDS and pH side axes
Add the same sample marker on the bottom strip at its TDS value and on the right strip at its pH value. Optional faint lines connect the rectangle position to the side strips. - 7
Color or facet by hydrogeologic group
Use color to encode aquifer, depth zone, or sampling campaign. Direct labels are essential when the legend is in another corner of the figure. - 8
Title the takeaway
Replace “Durov diagram of well samples” with the conclusion: “Wells in the upper aquifer cluster as Ca-HCO3 freshwater; deep wells show Na-Cl signature with elevated TDS.”
// 08 — Real-world examples
Where you’ll see Durov diagrams used
Durov diagrams are standard equipment for hydrogeologists working on groundwater quality, contamination, and aquifer characterization.
Aquifer characterization
Regional hydrogeology studies plot dozens of well samples on a single Durov to identify hydrochemical facies — Ca-HCO3 freshwater near recharge zones, Na-Cl signatures near discharge or saltwater intrusion fronts.
HydrogeologySaltwater intrusion monitoring
Coastal aquifer monitoring networks plot quarterly samples; the migration of points from the freshwater corner toward the Na-Cl corner is the headline of the report.
CoastalMining and industrial site investigations
Site characterization for mines or industrial brownfields uses Durov diagrams to distinguish background groundwater from contaminated samples by ion signature and elevated TDS.
EnvironmentalGeothermal and mineral water classification
Geothermal exploration uses the Durov diagram to classify spring waters by composition and to track changes in source chemistry over time.
Geothermal// 09 — Variations
Variants of the Durov diagram
Several practical variants extend or adapt the base layout to specific use cases.
Expanded Durov
Adds extra side panels for additional parameters (e.g., temperature, electrical conductivity, isotopic ratios) beyond the canonical TDS and pH.
Color-coded Durov
Uses color to encode a fourth variable such as well depth, sampling year, or aquifer unit — making temporal or spatial trends immediately visible.
Density Durov
Replaces individual sample points with hexbin or contour density plots when hundreds of samples would otherwise overplot the central rectangle.
Interactive Durov (web)
Web implementations often add tooltips on hover that show the full ion analysis, charge balance, and any sample metadata.
// 10 — Comparisons
How it compares
Durov sits in the family of standard hydrochemistry diagrams. The three most useful comparisons are with Piper (its parent), Stiff (per-sample fingerprints), and Schoeller (concentration-focused alternative).
Durov vs Piper diagram
Both pair a cation ternary with an anion ternary, but the Piper projects samples into a central diamond rotated 45 degrees, while the Durov uses an axis-aligned rectangle and adds TDS and pH side axes. Durov shows more parameters at the cost of a busier layout.
Durov diagram
Cation + anion ternaries, axis-aligned central rectangle, plus TDS and pH side axes. Five hydrochemical dimensions in one figure.
- Axis-aligned central rectangle
- Includes TDS and pH
- Best for full hydrochemical context
Piper diagram
Cation + anion ternaries projected into a central diamond. Three dimensions; TDS and pH not shown.
- Diamond rotated 45 degrees
- TDS / pH not included
- Cleaner layout for ion classification only
Durov vs Stiff diagram
Stiff diagrams show one figure per sample (a polygon ‘fingerprint’), while Durov diagrams show many samples on a single figure. Use Stiff for per-sample inspection; use Durov for population-level classification.
Durov diagram
All samples on one composite figure. Population-level water-type classification.
- Many samples per figure
- Comparative classification
- Compact for reports
Stiff diagram
One polygon per sample, encoding cation / anion meq/L on opposing axes. Sample-level ion fingerprint.
- One figure per sample
- Polygon shape encodes ion mix
- Best for spatial maps of samples
Durov vs Schoeller diagram
A Schoeller diagram plots ion concentrations on a log scale across multiple parallel axes (one per ion), while a Durov shows ion proportions on ternaries. Schoeller preserves absolute concentration; Durov captures composition.
Durov diagram
Ion proportions (percentages) on ternaries; absolute concentration only via TDS strip.
- Composition focus
- Ternary geometry
- Compact composite
Schoeller diagram
Log-scale parallel axes, one per ion. Preserves absolute concentration of each species.
- Concentration focus
- Linear / log axes per ion
- Multiple samples as overlaid lines
// 11 — Common mistakes
Common Durov diagram mistakes
Most bad Durov diagrams fail on the same handful of issues: skipping unit conversion, ignoring charge balance, or quietly dropping incomplete samples.
Plotting mg/L instead of meq/L percentages
Skipping the unit conversion gives a wrong-shaped distribution. Always convert to meq/L and then to percentages of the cation / anion sums.
Skipping the charge-balance check
If the cation and anion sums don’t agree within ~10%, the sample has analytical error. Plot a flag, exclude it, or document the imbalance.
Silently dropping incomplete samples
Samples missing one major ion can’t be plotted on the ternaries. Document the exclusion in the methods, don’t just delete the row.
Mismatched TDS scales across panels
When comparing aquifers or campaigns, lock the TDS strip to the same range so cloud size is comparable.
Unlabeled ternary corners
Without labels, readers can’t tell which corner is Ca, Mg, Na+K, HCO3, SO4, or Cl. Always label them.
Using a Durov for per-sample analysis
If you need a separate fingerprint per sample, use a Stiff diagram. Durov is for comparing many samples on one figure.
// 12 — Accessibility
Accessibility checklist
Run through this list before publishing. The chart should still communicate its message to readers using assistive technology, color-blind users, keyboard navigation, and reduced-motion settings.
- ✓
Color contrast for sample markers and ternary outlines
WCAG 1.4.3Sample markers must reach 3:1 against the chart background; ternary triangle outlines, the central rectangle border, and the TDS / pH strip borders must reach 4.5:1 so the layout is visible at thumbnail size. - ✓
Don’t encode sample groups by color alone
WCAG 1.4.1When samples are color-coded by aquifer or campaign, also use marker shape and direct labels so color-vision-deficient readers can still distinguish the groups. - ✓
Provide a meaningful text alternative
WCAG 1.1.1An accessible name should describe the takeaway: “Durov diagram of 8 wells: shallow wells cluster as Ca-HCO3 freshwater, deep wells as Na-Cl with TDS above 1500 mg/L.” - ✓
Expose the underlying ion table
WCAG 1.3.1Provide a downloadable CSV or hidden data table with each sample’s Ca, Mg, Na, K, HCO3, SO4, Cl, TDS, pH. The chart’s spatial encoding is essentially impossible to experience without sight. - ✓
Label the axes and ternary corners explicitly
WCAG 3.3.2Every ternary corner must be labeled with its ion (Ca²⁺, Mg²⁺, Na⁺+K⁺, etc.). The bottom and right strips must show their units (mg/L for TDS, the standard 0–14 scale for pH). - ✓
Resizable and zoomable
WCAG 1.4.4Use a responsive viewBox so the layout remains legible at 200% browser zoom. Below a panel width of ~500 px the diagram becomes unreadable; hide it or replace with the data table at narrow widths. - ✓
Keyboard-accessible interactivity
WCAG 2.1.1If samples reveal a tooltip on hover, every sample marker should be reachable with the Tab key and the tooltip should appear on focus, with a visible focus ring.
// 13 — Best practices
Design and craft tips
A short list of dos and don’ts that consistently separate publication-quality Durov diagrams from the demo-grade ones.
Always verify charge balance
Plot mg/L percentages directly
Label each ternary corner clearly
Drop samples with missing ions silently
Use a fixed TDS scale across panels
Combine many small markers without grouping
Connect the rectangle to side axes
Substitute a Durov for a Stiff diagram
// 15 — Tool instructions
How to build it in your tool of choice
Recipes for the libraries and commercial tools that ship a Durov implementation, plus pragmatic D3 / Matplotlib routes when none are available.
Python (Matplotlib)
Code — ~10 min- 01Install Matplotlib, NumPy, and pandas with pip install matplotlib numpy pandas (optionally pip install WQChartPy for a higher-level helper).
- 02Load samples into a pandas DataFrame with columns Ca, Mg, Na, K, HCO3, SO4, Cl, TDS, pH (mg/L for ions and TDS).
- 03Convert ion mg/L to meq/L by dividing by ion-specific equivalent weights, then to percentages.
- 04Use matplotlib.patches.Polygon to draw the cation triangle, anion triangle, and central rectangle on a single subplot.
- 05Project (Ca%, Mg%) onto the cation triangle and (HCO3%, SO4%) onto the anion triangle; project both onto the central rectangle’s x and y axes.
- 06Add two thin axes below and to the right for TDS and pH; place sample markers on each.
WQChartPy (PyPI) is the closest thing to a turn-key implementation — it ships Piper, Durov, Stiff, and Chadha plots with one call from a CSV.
R (smwrGraphs)
Code — ~6 min- 01Install smwrGraphs from the USGS R repository: remotes::install_github('USGS-R/smwrGraphs').
- 02Build a data frame with Ca, Mg, Na, K, HCO3, SO4, Cl in mg/L plus TDS and pH per sample.
- 03Convert with conc2meq() to milliequivalents, then to percentages.
- 04Call piperPlot() for the central composition; pair it with subPlot() panels for TDS and pH to construct the Durov layout.
- 05Use setSweave or pdf() to write the figure at publication resolution.
- 06Add a takeaway-style caption noting the dominant water types found.
smwrGraphs is the de-facto USGS hydrochemistry plotting library; the hydrogeo and hydroTSM packages are alternatives if smwrGraphs install proves difficult.
JavaScript (D3)
Code — ~15 min- 01Install D3 with npm i d3.
- 02Project ternary (a, b, c) coordinates to cartesian: x = b + c/2, y = c × sqrt(3)/2 then scale to pixels.
- 03Draw the cation triangle, anion triangle, and central rectangle with svg <polygon> and <rect>.
- 04Project each sample’s (Ca%, Mg%) onto the cation triangle and (HCO3%, SO4%) onto the anion triangle; place its dot in the rectangle at (cation%, anion%).
- 05Render TDS and pH strips as two thin <g> groups below and to the right with their own scales.
- 06Add a legend explaining marker color / shape and a takeaway-style title.
There is no first-party D3 helper for Durov diagrams — the recipe above is the standard manual implementation. Reuse the geometry as a small React/Vue component once written.
AquaChem
GUI — ~5 min- 01Open AquaChem (Schlumberger Water Services) and import samples from CSV or Excel.
- 02Use the unit-conversion tool to ensure ions are in mg/L; AquaChem handles the meq/L conversion internally.
- 03Switch to the Plots panel and pick ‘Durov’ from the standard hydrochemistry chart list.
- 04Color or symbol-code samples by sample group (aquifer, depth, campaign) using the legend editor.
- 05Export the diagram as PDF or PNG at the report’s required resolution.
- 06Save the project so the same chart configuration can be reopened with refreshed samples.
AquaChem is the leading commercial hydrochemistry suite; it produces the Durov and TDS / pH side axes correctly and saves analysts a lot of plumbing.
WQChartPy (open-source GUI)
Open source — ~5 min- 01Install with pip install WQChartPy.
- 02Prepare a CSV with the columns Sample, Ca, Mg, Na, K, HCO3, SO4, Cl, TDS, pH, plus a Color and Marker column for plotting style.
- 03Load with df = pd.read_csv('samples.csv'); the package expects this exact schema.
- 04Call wqchartpy.durov.plot(df, unit='mg/L', figname='durov', figformat='pdf').
- 05The function automatically projects samples and renders the Durov layout with TDS and pH strips.
- 06Open the resulting PDF and add a manual caption for the takeaway.
WQChartPy is a small open-source helper that replicates Piper, Durov, Stiff, Chadha, and Gibbs diagrams. Useful when AquaChem is unavailable.
// 16 — Code examples
Working code in the most common stacks
Three runnable snippets that produce equivalent Durov diagrams in Python, R, and JavaScript. Each includes the meq/L conversion and projects samples into the central rectangle.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon, Rectangle
# 8 well samples (mg/L)
samples = pd.DataFrame({
"well": ["W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8"],
"Ca": [ 90, 75, 60, 130, 120, 110, 35, 40],
"Mg": [ 22, 18, 15, 35, 28, 30, 9, 10],
"Na": [ 18, 22, 35, 20, 35, 40, 220, 250],
"K": [ 3, 4, 5, 3, 4, 5, 10, 12],
"HCO3": [320, 280, 260, 380, 340, 330, 80, 70],
"SO4": [ 25, 20, 35, 40, 30, 35, 60, 55],
"Cl": [ 30, 35, 40, 45, 50, 55, 380, 420],
"TDS": [430, 380, 360, 540, 480, 480,1700,1850],
"pH": [7.5, 7.6, 7.8, 7.4, 7.5, 7.6, 7.9, 8.0],
})
# meq/L equivalent weights (mg / meq).
ew = {"Ca": 20.04, "Mg": 12.16, "Na": 22.99, "K": 39.10,
"HCO3": 61.02, "SO4": 48.03, "Cl": 35.45}
cat = pd.DataFrame({k: samples[k] / ew[k] for k in ["Ca", "Mg", "Na", "K"]})
an = pd.DataFrame({k: samples[k] / ew[k] for k in ["HCO3", "SO4", "Cl"]})
cat_pct = cat.div(cat.sum(axis=1), axis=0) * 100
an_pct = an.div(an.sum(axis=1), axis=0) * 100
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_xlim(-10, 240); ax.set_ylim(-40, 240); ax.set_aspect("equal"); ax.axis("off")
# Central rectangle
ax.add_patch(Rectangle((40, 40), 160, 160, fill=False, ec="#1a1a18", lw=1))
# Cation ternary above-left
ax.add_patch(Polygon([(40, 200), (200, 200), (120, 200 + 80*np.sqrt(3))],
closed=True, fill=False, ec="#1a1a18", lw=1))
# Anion ternary right (rotated)
ax.add_patch(Polygon([(200, 40), (200, 200), (200 + 80*np.sqrt(3), 120)],
closed=True, fill=False, ec="#1a1a18", lw=1))
# TDS strip below
ax.add_patch(Rectangle((40, 10), 160, 16, fill=False, ec="#1a1a18", lw=0.5))
# pH strip right
ax.add_patch(Rectangle((215, 40), 16, 160, fill=False, ec="#1a1a18", lw=0.5))
# Project samples into central rectangle.
xs = 40 + cat_pct["Na"].values + (cat_pct["K"].values) * 1.6
ys = 40 + an_pct["Cl"].values * 1.6
ax.scatter(xs, ys, c="#c94a2e", alpha=0.85, s=60, edgecolor="white")
# Side axes
tds_x = 40 + (samples["TDS"].clip(0, 2000) / 2000) * 160
ax.scatter(tds_x, np.full(len(samples), 18), c="#c94a2e", alpha=0.85, s=40)
ph_y = 40 + ((samples["pH"] - 6) / 4) * 160
ax.scatter(np.full(len(samples), 223), ph_y, c="#c94a2e", alpha=0.85, s=40)
ax.text(120, 200 + 80*np.sqrt(3) + 8, "Cations (% meq/L)", ha="center", fontsize=10)
ax.text(200 + 80*np.sqrt(3) + 12, 120, "Anions (% meq/L)",
rotation=270, va="center", fontsize=10)
ax.text(120, 3, "TDS (mg/L)", ha="center", fontsize=10)
ax.text(232, 120, "pH", rotation=270, va="center", fontsize=10)
ax.set_title("Wells W1–W6 cluster as Ca-HCO3 freshwater; W7–W8 are Na-Cl with high TDS",
loc="left", fontsize=11)
plt.tight_layout()
plt.savefig("durov.png", dpi=200, bbox_inches="tight")
plt.show()
// 17 — FAQs
Frequently asked questions
What is a Durov diagram?+
A Durov diagram is a composite hydrochemical chart that pairs two ternary diagrams — one for major cations and one for major anions — with a central rectangular field, plus extra TDS and pH axes along the edges. It classifies water samples by ion chemistry, mineralization, and acidity in a single figure.
When should you use a Durov diagram?+
Use a Durov diagram for hydrochemical classification of natural water samples — groundwater, springs, surface water — when you need to combine ion proportions with TDS and pH context. It is the standard plot for hydrogeological reports, contamination tracking, and aquifer characterization.
When should you avoid a Durov diagram?+
Avoid a Durov diagram when your audience is unfamiliar with ternary plots, when you only have one or two samples (a table is clearer), when ion data is incomplete (a sample missing one major cation can’t be plotted), or when a simpler Piper diagram answers the same question.
What’s the difference between a Durov and a Piper diagram?+
Both share the cation + anion ternary pair, but a Piper diagram projects samples into a central diamond rotated 45 degrees, while a Durov diagram uses an axis-aligned central rectangle with two extra strips for TDS and pH. The Durov design adds those two extra parameters at the cost of slightly more complex layout.
What units does a Durov diagram use?+
Major ion concentrations must be converted to milliequivalents per liter (meq/L), then expressed as a percentage so the cation and anion totals each sum to 100. TDS is plotted in mg/L; pH is dimensionless on a standard 0–14 scale.
Is a Durov diagram suitable for dashboards?+
Yes — Durov diagrams work in dashboards as long as the panel is large enough that the two ternaries, central rectangle, and TDS / pH strips remain individually legible. Below ~500 px wide they become unreadable.
What category of chart is a Durov diagram?+
Durov Diagram belongs to the Scientific family of charts. Charts in that family are designed to answer the same kind of question — how to classify a sample by multivariate composition — so they often work as alternatives when one doesn’t quite fit your data.
How do you read a Durov diagram?+
Start with the two ternary diagrams to identify the dominant cation and anion. Project both onto the central rectangle to find the water type. Then read across to the TDS axis (bottom) for mineralization and down to the pH axis (right) for acidity to characterize the sample fully.
What’s the best library for building Durov diagrams?+
There is no single canonical library. In R, the smwrGraphs and hydrogeo packages support related Piper / Durov plots. In Python, custom Matplotlib code or the WQChartPy package handles the layout. For the web, D3 with manual ternary-to-cartesian projection is the standard route.
// 18 — References
References and further reading
Primary sources — Durov 1948 and Piper 1944 — plus the standard hydrogeology reference texts and tools used throughout this guide.
- Durov, S.A. — Classification of natural waters and graphical representation of their composition (1948)Primary sourceThe original publication introducing the Durov diagram. Establishes the cation + anion ternary projection plus TDS and pH side axes that define the chart.https://doi.org/10.2307/210739
- Piper, A.M. — A graphic procedure in the geochemical interpretation of water analyses (1944)Primary sourceEarlier paper that defined the Piper diagram on which the Durov is built. Required reading for understanding the ternary projection.https://doi.org/10.1029/TR025i006p00914
- Reference text covering the standard hydrochemistry plots (Piper, Durov, Stiff, Schoeller) and how to interpret water samples from them.https://www.routledge.com/Water-Quality-Data-Analysis-and-Interpretation/Hounslow/p/book/9781566700429
- USGS — smwrGraphsLibraryUSGS R package implementing piperPlot and related hydrochemistry charts used in the R code sample.https://github.com/USGS-R/smwrGraphs
- WQChartPyLibraryOpen-source Python package that ships Durov, Piper, Stiff, Chadha, and Gibbs diagrams from a single CSV input.https://pypi.org/project/wqchartpy/
- Wikipedia — Durov plotReferenceEncyclopedia entry covering the chart’s construction and interpretation.https://en.wikipedia.org/wiki/Durov_plot
- The leading commercial hydrochemistry analysis suite, used by environmental and water-quality consultants worldwide.https://www.swstechnology.com/groundwater-software/aquachem/
- WAI — Complex Images: Charts and GraphsAccessibilityWeb Accessibility Initiative guidance on text alternatives and data tables for complex scientific figures — directly applicable to multi-panel hydrochemistry plots.https://www.w3.org/WAI/tutorials/images/complex/
- The classic groundwater hydrology textbook. Background on hydrogeochemistry, water-type classification, and the role of TDS and pH.https://www.un-igrac.org/resource/groundwater-freeze-and-cherry-1979