diff --git a/src/app/components/fixedvar-results/results.component.ts b/src/app/components/fixedvar-results/results.component.ts
index d5282b1b15c54e4225068332b8adb43ca6e839d3..355a28b3193eb978f220e79bd5f2b04d194ef3b1 100644
--- a/src/app/components/fixedvar-results/results.component.ts
+++ b/src/app/components/fixedvar-results/results.component.ts
@@ -68,6 +68,22 @@ export class ResultsComponent {
         ];
     }
 
+    /** the 10 different point styles available in Chart.js, ordered in a way that seems nice to me */
+    public static get distinctPointStyles(): string[] {
+        return [
+            "circle",
+            "rect",
+            "triangle",
+            "cross",
+            "star",
+            "rectRot",
+            "crossRot",
+            "dash",
+            "rectRounded",
+            "line"
+        ];
+    }
+
     /**
      * Formats (rounds) the given number (or the value of the given parameter) with the
      * number of decimals specified in app preferences; if given number is too low and
diff --git a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts
index aa4e3f40705ae051d18b301e93f995d1cfcf5b7e..7651912936e4ece70d94cba60909bfc3342f8154 100644
--- a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts
+++ b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts
@@ -9,7 +9,9 @@ import { IYSeries } from "../../results/y-series";
 import { fv } from "../../util";
 import { AppComponent } from "../../app.component";
 
-import { CloisonAval, Cloisons } from "jalhyd";
+import { CloisonAval, Cloisons, LoiDebit } from "jalhyd";
+
+import { sprintf } from "sprintf-js";
 
 @Component({
     selector: "pab-profile-chart",
@@ -112,6 +114,15 @@ export class PabProfileChartComponent extends ResultsComponent {
                 }
             }
         };
+        // format numbers in tooltips
+        this.graph_options["tooltips"] = {
+            displayColors: false,
+            callbacks: {
+                label: (tooltipItem, data) => {
+                    return "(" + fv(Number(tooltipItem.xLabel)) + ", " + fv(Number(tooltipItem.yLabel)) + ")";
+                }
+            }
+        };
     }
 
     public set results(r: PabResults) {
@@ -172,7 +183,8 @@ export class PabProfileChartComponent extends ResultsComponent {
                 data: ys.data,
                 borderColor: ys.color, // couleur de la ligne
                 backgroundColor: "rgba(0,0,0,0)",  // couleur de remplissage sous la courbe : transparent
-                showLine: "true"
+                showLine: "true",
+                pointStyle: ys.pointStyle
             });
         }
     }
@@ -219,9 +231,14 @@ export class PabProfileChartComponent extends ResultsComponent {
         const xs = this.getXSeries(); // abscissae
         const pabLength = xs[xs.length - 1] - xs[0];
         const pabLength5Pct = (pabLength * 5) / 100;
+        const dw = (this._results.cloisonAvalResults.sourceNub as CloisonAval);
+        const ZRAMdw = dw.prms.ZRAM.singleValue;
 
         // 1. radier (cotes amont et mi-bassin)
         const dataF: { x: number, y: number }[] = [];
+        const pointStyles: string[] = [];
+        // one data series for one device repeated throughout the basins
+        const ddSeries: { x: number, y: number }[][] = [];
         // extend upstream
         dataF.push({
             x: xs[0] - pabLength5Pct,
@@ -234,33 +251,99 @@ export class PabProfileChartComponent extends ResultsComponent {
             const ZRAM = cr.resultElement.getValue("ZRAM"); // any ResultElement will do
             const ZRMB = cr.resultElement.getValue("ZRMB"); // any ResultElement will do
             const halfLB = c.prms.LB.singleValue / 2;
+            // ZRAM
             dataF.push({
                 x: xs[i],
                 y: ZRAM
             });
+            // ZDV of each device…
+            for (let sti = 0; sti < c.structures.length; sti ++) {
+                const st = c.structures[sti];
+                // init device series if it does not exist yet
+                if (ddSeries[sti] === undefined) {
+                    ddSeries[sti] = [];
+                }
+                // orifices have no relevant ZDV
+                if (st.properties.getPropValue("loiDebit") !== LoiDebit.OrificeSubmerged) {
+                    // 2 points, to draw a segment
+                    ddSeries[sti].push({
+                        x: xs[i],
+                        y: ZRAM
+                    });
+                    ddSeries[sti].push({
+                        x: xs[i],
+                        y: st.prms.ZDV.v
+                    });
+                    // 1 null point, to disjoin segments
+                    ddSeries[sti].push({
+                        x: xs[i],
+                        y: null
+                    });
+                }
+            }
+            // ZRMB
             dataF.push({
                 x: xs[i] + halfLB,
                 y: ZRMB
             });
         }
         // downwall
-        const dw = (this._results.cloisonAvalResults.sourceNub as CloisonAval);
-        const ZRAMdw = dw.prms.ZRAM.singleValue;
         dataF.push({
             x: xs[ xs.length - 1 ],
             y: ZRAMdw
         });
+        // ZDV of each device…
+        for (let sti = 0; sti < dw.structures.length; sti ++) {
+            const st = dw.structures[sti];
+            // init device series if it does not exist yet
+            if (ddSeries[sti] === undefined) {
+                ddSeries[sti] = [];
+            }
+            // orifices have no relevant ZDV; lift gate will be drawn later for each series
+            if (! [ LoiDebit.OrificeSubmerged, LoiDebit.VanLevLarinier, LoiDebit.VanLevVillemonte ]
+                .includes(st.properties.getPropValue("loiDebit"))
+            ) {
+                // 2 points, to draw a segment
+                ddSeries[sti].push({
+                    x: xs[ xs.length - 1 ],
+                    y: ZRAMdw
+                });
+                ddSeries[sti].push({
+                    x: xs[ xs.length - 1 ],
+                    y: st.prms.ZDV.v
+                });
+                // 1 null point, to disjoin segments
+                ddSeries[sti].push({
+                    x: xs[ xs.length - 1 ],
+                    y: null
+                });
+            }
+        }
         // extend downstream
         dataF.push({
             x: xs[xs.length - 1] + pabLength5Pct,
             y: ZRAMdw
         });
-        // add series
+        // add bottom series
         ret.push({
             data: dataF,
             label: this.intlService.localizeText("INFO_LIB_RADIER"),
             color: "#808080"
         });
+        // add devices series with a different point style for each
+        const psPalette = ResultsComponent.distinctPointStyles;
+        for (let ddi = 0; ddi < ddSeries.length; ddi++) {
+            const ds = ddSeries[ddi];
+            // series might have no eligible device, thus no point at all
+            if (ds.length > 0) {
+                ret.push({
+                    data: ds,
+                    label: sprintf(this.intlService.localizeText("INFO_LIB_PAB_CHART_SEUILS"), ddi + 1),
+                    color: "#808080", // same as bottom line
+                    pointStyle: psPalette[ddi]
+                });
+            }
+        }
 
         // 2. séries
         const nbSeries = this._results.cloisonsResults[0].resultElements.length;
@@ -287,6 +370,7 @@ export class PabProfileChartComponent extends ResultsComponent {
             for (const x of xs) {
                 let Z1: number;
                 let nextZ1: number;
+                let isLastAbscissa = false;
                 if (i < xs.length - 2) {
                     // regular walls
                     Z1 = this._results.cloisonsResults[i].resultElements[n].vCalc;
@@ -299,6 +383,7 @@ export class PabProfileChartComponent extends ResultsComponent {
                     // downwall
                     Z1 = this._results.cloisonAvalResults.resultElements[n].vCalc;
                     nextZ1 = this._results.Z2[n];
+                    isLastAbscissa = true;
                 }
 
                 // 2 points for each abscissa
@@ -311,6 +396,38 @@ export class PabProfileChartComponent extends ResultsComponent {
                     y: nextZ1
                 });
 
+                // draw lift gate if any
+                if (isLastAbscissa) {
+                    for (const st of dw.structures) {
+                        if ([ LoiDebit.VanLevLarinier, LoiDebit.VanLevVillemonte ].includes(st.properties.getPropValue("loiDebit"))) {
+                            // skip a point to disjoin line
+                            dataN.push({
+                                x: x,
+                                y: null
+                            });
+                            // draw gate between bottom and ZDV
+                            dataN.push({
+                                x: x,
+                                y: ZRAMdw
+                            });
+                            dataN.push({
+                                x: x,
+                                y: this._results.cloisonAvalResults.resultElements[n].getValue("ZDV")
+                            });
+                            // skip a point to disjoin line
+                            dataN.push({
+                                x: x,
+                                y: null
+                            });
+                            // back to last water line point
+                            dataN.push({
+                                x: x,
+                                y: nextZ1
+                            });
+                        }
+                    }
+                }
+
                 i++;
             }
 
diff --git a/src/app/results/y-series.ts b/src/app/results/y-series.ts
index 1a8f4e7718e27a6c98f3cbd2d276f67b1ee023a9..4f66a927816f56c4edaeeddbc89ce53cdbaf3187 100644
--- a/src/app/results/y-series.ts
+++ b/src/app/results/y-series.ts
@@ -8,4 +8,8 @@ export interface IYSeries {
     label: string;
     /** line color */
     color: string;
+    /** points colors, might be an array */
+    pointBackgroundColor?: any;
+    /** points styles (shape or image), might be an array */
+    pointStyle?: any;
 }
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 4a632d1cd0cda03869acce1af46264414a78bbc3..1666eb9645efa306307362740aa9a1e9515ffa9b 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -289,6 +289,7 @@
     "INFO_LIB_ZRAM": "Upstream apron elevation",
     "INFO_LIB_ZRMB": "Downstream basin bottom elevation",
     "INFO_LIB_ZT": "Triangle top elevation",
+    "INFO_LIB_PAB_CHART_SEUILS": "Weirs (%s)",
     "INFO_LINKED_VALUE_CHILD": "%s (%s, %s %s)",
     "INFO_LINKED_VALUE_EXTRA_RESULT_OF": "%s (%s)",
     "INFO_LINKED_VALUE_EXTRA_RESULT": "%s (%s)",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 4d86f3a4af2edc11134c82fbdce48681d7278843..79440de701238ee7adebd5e7fffdc1e50524c1af 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -288,6 +288,7 @@
     "INFO_LIB_ZRAM": "Cote du radier amont",
     "INFO_LIB_ZRMB": "Cote de radier mi-bassin",
     "INFO_LIB_ZT": "Cote haute du triangle",
+    "INFO_LIB_PAB_CHART_SEUILS": "Seuils (%s)",
     "INFO_LINKED_VALUE_CHILD": "%s (%s, %s %s)",
     "INFO_LINKED_VALUE_EXTRA_RESULT_OF": "%s (%s)",
     "INFO_LINKED_VALUE_EXTRA_RESULT": "%s (%s)",