diff --git a/CHANGELOG.md b/CHANGELOG.md
index bca9400de92c552b79720ba8f223ec3520dde185..e6604fb047cfd25dd0eb14851fd75edafbd892ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,11 @@ Note that since we don't clearly distinguish between a public and private interf
 
 ## [Unreleased]
 
+- Show histogram in direct volume control point settings
+
+
+## [v3.27.0] - 2022-12-15
+
 - Add an `includeTransparent` parameter to hide/show outlines of components that are transparent
 - Fix 'once' for animations of systems with many frames
 - Better guard against issue (black fringes) with bumpiness in impostors
@@ -17,6 +22,8 @@ Note that since we don't clearly distinguish between a public and private interf
     - Add `solidInterior` parameter
 - Fix `QualityAssessment` assignment bug for structures with different auth vs label sequence numbering
 - Refresh `ApplyActionControl`'s param definition when toggling expanded state
+- Fix `struct_conn` bond assignment for ions
+- Ability to show only polar hydrogens
 
 ## [v3.26.0] - 2022-12-04
 
diff --git a/package-lock.json b/package-lock.json
index a0702acc416d6b0154f572f3becd240936a5bd1a..50e48a7bb1b04bfa471076070d86b274afd134a7 100644
Binary files a/package-lock.json and b/package-lock.json differ
diff --git a/package.json b/package.json
index ab2d6c2187773f76a504515c3aa09294e4fa3a4e..d98c5a7f9aae19b09e4ba840c3c113d5d7a58a50 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "molstar",
-  "version": "3.26.0",
+  "version": "3.27.0",
   "description": "A comprehensive macromolecular library.",
   "homepage": "https://github.com/molstar/molstar#readme",
   "repository": {
diff --git a/src/extensions/cellpack/model.ts b/src/extensions/cellpack/model.ts
index 91ea9c33315343732112fe22b80829545b5edc90..6293d8a729b7eea644f1cda9ca58f684e9c9ff34 100644
--- a/src/extensions/cellpack/model.ts
+++ b/src/extensions/cellpack/model.ts
@@ -585,7 +585,7 @@ export const LoadCellPackModel = StateAction.build({
             ... ctx.managers.structure.component.state.options,
             visualQuality: 'custom',
             ignoreLight: true,
-            showHydrogens: false,
+            hydrogens: 'hide-all',
         });
         ctx.canvas3d?.setProps({
             multiSample: { mode: 'off' },
diff --git a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts
index ab11f3f7b8598817c9c0ed68a1c953c5395e1686..69f51afb6240cc719a83338a62fda29a821b91a0 100644
--- a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts
+++ b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts
@@ -249,13 +249,29 @@ function computeInterUnitBonds(structure: Structure, props?: Partial<InterBondCo
                 (!Unit.isAtomic(a) || mtA[a.residueIndex[a.elements[0]]] !== MoleculeType.Water) &&
                 (!Unit.isAtomic(b) || mtB[b.residueIndex[b.elements[0]]] !== MoleculeType.Water)
             );
-            const notIon = (
-                (!Unit.isAtomic(a) || mtA[a.residueIndex[a.elements[0]]] !== MoleculeType.Ion) &&
-                (!Unit.isAtomic(b) || mtB[b.residueIndex[b.elements[0]]] !== MoleculeType.Ion)
-            );
+
+            const sameModel = a.model === b.model;
+            const notIonA = (!Unit.isAtomic(a) || mtA[a.residueIndex[a.elements[0]]] !== MoleculeType.Ion) || (sameModel && hasStructConnRecord(a));
+            const notIonB = (!Unit.isAtomic(b) || mtB[b.residueIndex[b.elements[0]]] !== MoleculeType.Ion) || (sameModel && hasStructConnRecord(b));
+            const notIon = notIonA && notIonB;
             return Structure.validUnitPair(s, a, b) && (notWater || !p.ignoreWater) && (notIon || !p.ignoreIon);
         }),
     });
 }
 
+function hasStructConnRecord(unit: Unit) {
+    if (!Unit.isAtomic(unit)) return false;
+
+    const elements = unit.elements;
+    const structConn = StructConn.Provider.get(unit.model);
+    if (structConn) {
+        for (let i = 0, _i = elements.length; i < _i; i++) {
+            if (structConn.byAtomIndex.get(elements[i])) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 export { computeInterUnitBonds };
diff --git a/src/mol-plugin-state/builder/structure/representation-preset.ts b/src/mol-plugin-state/builder/structure/representation-preset.ts
index 25f2d1f907f1772b52a9da01ff27d0d91df9bfad..2f5d6d410c7a7caadaee2844e4c6ae52404f61e9 100644
--- a/src/mol-plugin-state/builder/structure/representation-preset.ts
+++ b/src/mol-plugin-state/builder/structure/representation-preset.ts
@@ -37,6 +37,7 @@ export namespace StructureRepresentationPresetProvider {
 
     export const CommonParams = {
         ignoreHydrogens: PD.Optional(PD.Boolean(false)),
+        onlyPolarHydrogens: PD.Optional(PD.Boolean(false)),
         ignoreLight: PD.Optional(PD.Boolean(false)),
         quality: PD.Optional(PD.Select<VisualQuality>('auto', VisualQualityOptions)),
         theme: PD.Optional(PD.Group({
@@ -70,11 +71,13 @@ export namespace StructureRepresentationPresetProvider {
         const builder = plugin.builders.structure.representation;
         const typeParams = {
             quality: plugin.managers.structure.component.state.options.visualQuality,
-            ignoreHydrogens: !plugin.managers.structure.component.state.options.showHydrogens,
+            ignoreHydrogens: plugin.managers.structure.component.state.options.hydrogens === 'hide-all',
+            onlyPolarHydrogens: plugin.managers.structure.component.state.options.hydrogens === 'only-polar',
             ignoreLight: plugin.managers.structure.component.state.options.ignoreLight,
         };
         if (params.quality && params.quality !== 'auto') typeParams.quality = params.quality;
         if (params.ignoreHydrogens !== void 0) typeParams.ignoreHydrogens = !!params.ignoreHydrogens;
+        if (params.onlyPolarHydrogens !== void 0) typeParams.onlyPolarHydrogens = !!params.onlyPolarHydrogens;
         if (params.ignoreLight !== void 0) typeParams.ignoreLight = !!params.ignoreLight;
         const color: ColorTheme.BuiltIn | undefined = params.theme?.globalName ? params.theme?.globalName : void 0;
         const ballAndStickColor: ColorTheme.BuiltInParams<'element-symbol'> = params.theme?.carbonColor !== undefined
diff --git a/src/mol-plugin-state/manager/structure/component.ts b/src/mol-plugin-state/manager/structure/component.ts
index 229ece724ee5a43a85473309cbba47870268bfb3..d8c3f4d4873f0d9f0463067292bf1084e00620b7 100644
--- a/src/mol-plugin-state/manager/structure/component.ts
+++ b/src/mol-plugin-state/manager/structure/component.ts
@@ -70,7 +70,8 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
         return this.plugin.dataTransaction(async () => {
             await update.commit();
             await this.plugin.state.updateBehavior(StructureFocusRepresentation, p => {
-                p.ignoreHydrogens = !options.showHydrogens;
+                p.ignoreHydrogens = options.hydrogens === 'hide-all';
+                p.onlyPolarHydrogens = options.hydrogens === 'only-polar';
                 p.ignoreLight = options.ignoreLight;
                 p.material = options.materialStyle;
                 p.clip = options.clipObjects;
@@ -80,15 +81,17 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
     }
 
     private updateReprParams(update: StateBuilder.Root, component: StructureComponentRef) {
-        const { showHydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
-        const ignoreHydrogens = !showHydrogens;
+        const { hydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
+        const ignoreHydrogens = hydrogens === 'hide-all';
+        const onlyPolarHydrogens = hydrogens === 'only-polar';
         for (const r of component.representations) {
             if (r.cell.transform.transformer !== StructureRepresentation3D) continue;
 
             const params = r.cell.transform.params as StateTransformer.Params<StructureRepresentation3D>;
-            if (!!params.type.params.ignoreHydrogens !== ignoreHydrogens || params.type.params.quality !== quality || params.type.params.ignoreLight !== ignoreLight || !shallowEqual(params.type.params.material, material) || !PD.areEqual(Clip.Params, params.type.params.clip, clip)) {
+            if (!!params.type.params.ignoreHydrogens !== ignoreHydrogens || !!params.type.params.onlyPolarHydrogens !== onlyPolarHydrogens || params.type.params.quality !== quality || params.type.params.ignoreLight !== ignoreLight || !shallowEqual(params.type.params.material, material) || !PD.areEqual(Clip.Params, params.type.params.clip, clip)) {
                 update.to(r.cell).update(old => {
                     old.type.params.ignoreHydrogens = ignoreHydrogens;
+                    old.type.params.onlyPolarHydrogens = onlyPolarHydrogens;
                     old.type.params.quality = quality;
                     old.type.params.ignoreLight = ignoreLight;
                     old.type.params.material = material;
@@ -311,9 +314,10 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
     addRepresentation(components: ReadonlyArray<StructureComponentRef>, type: string) {
         if (components.length === 0) return;
 
-        const { showHydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
-        const ignoreHydrogens = !showHydrogens;
-        const typeParams = { ignoreHydrogens, quality, ignoreLight, material, clip };
+        const { hydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
+        const ignoreHydrogens = hydrogens === 'hide-all';
+        const onlyPolarHydrogens = hydrogens === 'only-polar';
+        const typeParams = { ignoreHydrogens, onlyPolarHydrogens, quality, ignoreLight, material, clip };
 
         return this.plugin.dataTransaction(async () => {
             for (const component of components) {
@@ -348,9 +352,10 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
             const xs = structures || this.currentStructures;
             if (xs.length === 0) return;
 
-            const { showHydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
-            const ignoreHydrogens = !showHydrogens;
-            const typeParams = { ignoreHydrogens, quality, ignoreLight, material, clip };
+            const { hydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
+            const ignoreHydrogens = hydrogens === 'hide-all';
+            const onlyPolarHydrogens = hydrogens === 'only-polar';
+            const typeParams = { ignoreHydrogens, onlyPolarHydrogens, quality, ignoreLight, material, clip };
 
             const componentKey = UUID.create22();
             for (const s of xs) {
@@ -458,9 +463,13 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
 
 namespace StructureComponentManager {
     export const OptionsParams = {
-        showHydrogens: PD.Boolean(true, { description: 'Toggle display of hydrogen atoms in representations' }),
+        hydrogens: PD.Select(
+            'all',
+            [['all', 'Show All'], ['hide-all', 'Hide All'], ['only-polar', 'Only Polar']] as const,
+            { description: 'Determine display of hydrogen atoms in representations' }
+        ),
         visualQuality: PD.Select('auto', VisualQualityOptions, { description: 'Control the visual/rendering quality of representations' }),
-        ignoreLight: PD.Boolean(false, { description: 'Ignore light for stylized rendering of representtions' }),
+        ignoreLight: PD.Boolean(false, { description: 'Ignore light for stylized rendering of representations' }),
         materialStyle: Material.getParam(),
         clipObjects: PD.Group(Clip.Params),
         interactions: PD.Group(InteractionsProvider.defaultParams, { label: 'Non-covalent Interactions' }),
diff --git a/src/mol-plugin-ui/controls/line-graph/line-graph-component.tsx b/src/mol-plugin-ui/controls/line-graph/line-graph-component.tsx
index 654d6733e0d656edf9258fe149197ec1f17f71ac..e7a90cfb673cbd70f9fb7bf554762b5dd0c10b98 100644
--- a/src/mol-plugin-ui/controls/line-graph/line-graph-component.tsx
+++ b/src/mol-plugin-ui/controls/line-graph/line-graph-component.tsx
@@ -1,12 +1,15 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Paul Luna <paulluna0215@gmail.com>
+ * @author David Sehnal <david.sehnal@gmail.com>
  */
 import { PointComponent } from './point-component';
 
 import * as React from 'react';
 import { Vec2 } from '../../../mol-math/linear-algebra';
+import { Grid } from '../../../mol-model/volume';
+import { arrayMax } from '../../../mol-util/array';
 
 interface LineGraphComponentState {
     points: Vec2[],
@@ -76,6 +79,7 @@ export class LineGraphComponent extends React.Component<any, LineGraphComponentS
     public render() {
         const points = this.renderPoints();
         const lines = this.renderLines();
+        const histogram = this.renderHistogram();
 
         return ([
             <div key="LineGraph">
@@ -93,6 +97,7 @@ export class LineGraphComponent extends React.Component<any, LineGraphComponentS
                     onDoubleClick={this.handleDoubleClick}>
 
                     <g stroke="black" fill="black">
+                        {histogram}
                         {lines}
                         {points}
                     </g>
@@ -297,11 +302,11 @@ export class LineGraphComponent extends React.Component<any, LineGraphComponentS
     }
 
     private normalizePoint(point: Vec2) {
-        const min = this.padding / 2;
-        const maxX = this.width + min;
-        const maxY = this.height + min;
-        const normalizedX = (point[0] * (maxX - min)) + min;
-        const normalizedY = (point[1] * (maxY - min)) + min;
+        const offset = this.padding / 2;
+        const maxX = this.width + offset;
+        const maxY = this.height + offset;
+        const normalizedX = (point[0] * (maxX - offset)) + offset;
+        const normalizedY = (point[1] * (maxY - offset)) + offset;
         const reverseY = (this.height + this.padding) - normalizedY;
         const newPoint = Vec2.create(normalizedX, reverseY);
         return newPoint;
@@ -325,6 +330,24 @@ export class LineGraphComponent extends React.Component<any, LineGraphComponentS
         }
     }
 
+    private renderHistogram() {
+        if (!this.props.volume) return null;
+
+        const histogram = Grid.getHistogram(this.props.volume.grid, 40);
+        const bars = [];
+        const N = histogram.counts.length;
+        const w = this.width / N;
+        const offset = this.padding / 2;
+        const max = arrayMax(histogram.counts) || 1;
+        for (let i = 0; i < N; i++) {
+            const x = this.width * i / (N - 1) + offset;
+            const y1 = this.height + offset;
+            const y2 = this.height * (1 - histogram.counts[i] / max) + offset;
+            bars.push(<line key={`histogram${i}`} x1={x} x2={x} y1={y1} y2={y2} stroke="#ded9ca" strokeWidth={w} />);
+        }
+        return bars;
+    }
+
     private renderPoints() {
         const points: any[] = [];
         let point: Vec2;
@@ -352,19 +375,18 @@ export class LineGraphComponent extends React.Component<any, LineGraphComponentS
     private renderLines() {
         const points: Vec2[] = [];
         const lines = [];
-        let min: number;
         let maxX: number;
         let maxY: number;
         let normalizedX: number;
         let normalizedY: number;
         let reverseY: number;
 
+        const o = this.padding / 2;
         for (const point of this.state.points) {
-            min = this.padding / 2;
-            maxX = this.width + min;
-            maxY = this.height + min;
-            normalizedX = (point[0] * (maxX - min)) + min;
-            normalizedY = (point[1] * (maxY - min)) + min;
+            maxX = this.width + o;
+            maxY = this.height + this.padding;
+            normalizedX = (point[0] * (maxX - o)) + o;
+            normalizedY = (point[1] * (maxY - o)) + o;
             reverseY = this.height + this.padding - normalizedY;
             points.push(Vec2.create(normalizedX, reverseY));
         }
diff --git a/src/mol-plugin-ui/controls/parameters.tsx b/src/mol-plugin-ui/controls/parameters.tsx
index 1d7cf96da53279b4e1a714ba289b82eb079ddd9d..3030981e2931859192f2166570d0b8f0abc347b0 100644
--- a/src/mol-plugin-ui/controls/parameters.tsx
+++ b/src/mol-plugin-ui/controls/parameters.tsx
@@ -7,6 +7,7 @@
 
 import * as React from 'react';
 import { Mat4, Vec2, Vec3 } from '../../mol-math/linear-algebra';
+import { Volume } from '../../mol-model/volume';
 import { Script } from '../../mol-script/script';
 import { Asset } from '../../mol-util/assets';
 import { Color } from '../../mol-util/color';
@@ -306,17 +307,32 @@ export class LineGraphControl extends React.PureComponent<ParamProps<PD.LineGrap
         message: `${this.props.param.defaultValue.length} points`,
     };
 
+
+    private pointToLabel(point?: Vec2) {
+        if (!point) return '';
+
+        const volume = this.props.param.getVolume?.() as Volume;
+        if (volume) {
+            const { min, max, mean, sigma } = volume.grid.stats;
+            const v = min + (max - min) * point[0];
+            const s = (v - mean) / sigma;
+            return `(${v.toFixed(2)} | ${s.toFixed(2)}σ, ${point[1].toFixed(2)})`;
+        } else {
+            return `(${point[0].toFixed(2)}, ${point[1].toFixed(2)})`;
+        }
+    }
+
     onHover = (point?: Vec2) => {
         this.setState({ isOverPoint: !this.state.isOverPoint });
         if (point) {
-            this.setState({ message: `(${point[0].toFixed(2)}, ${point[1].toFixed(2)})` });
-            return;
+            this.setState({ message: this.pointToLabel(point) });
+        } else {
+            this.setState({ message: `${this.props.value.length} points` });
         }
-        this.setState({ message: `${this.props.value.length} points` });
     };
 
     onDrag = (point: Vec2) => {
-        this.setState({ message: `(${point[0].toFixed(2)}, ${point[1].toFixed(2)})` });
+        this.setState({ message: this.pointToLabel(point) });
     };
 
     onChange = (value: PD.LineGraph['defaultValue']) => {
@@ -332,9 +348,10 @@ export class LineGraphControl extends React.PureComponent<ParamProps<PD.LineGrap
         const label = this.props.param.label || camelCaseToWords(this.props.name);
         return <>
             <ControlRow label={label} control={<button onClick={this.toggleExpanded} disabled={this.props.isDisabled}>{`${this.state.message}`}</button>} />
-            <div className='msp-control-offset' style={{ display: this.state.isExpanded ? 'block' : 'none' }}>
+            <div className='msp-control-offset' style={{ display: this.state.isExpanded ? 'block' : 'none', marginTop: 1 }}>
                 <LineGraphComponent
-                    data={this.props.param.defaultValue}
+                    data={this.props.value}
+                    volume={this.props.param.getVolume?.()}
                     onChange={this.onChange}
                     onHover={this.onHover}
                     onDrag={this.onDrag} />
diff --git a/src/mol-plugin/behavior/dynamic/selection/structure-focus-representation.ts b/src/mol-plugin/behavior/dynamic/selection/structure-focus-representation.ts
index a53dab23f2b1f6e707186d64713d8e744d01941f..e548d8e8b0117d630ce2bdb6b85d4440e73618e0 100644
--- a/src/mol-plugin/behavior/dynamic/selection/structure-focus-representation.ts
+++ b/src/mol-plugin/behavior/dynamic/selection/structure-focus-representation.ts
@@ -52,6 +52,7 @@ const StructureFocusRepresentationParams = (plugin: PluginContext) => {
         components: PD.MultiSelect(FocusComponents, PD.arrayToOptions(FocusComponents)),
         excludeTargetFromSurroundings: PD.Boolean(false, { label: 'Exclude Target', description: 'Exclude the focus "target" from the surroudings component.' }),
         ignoreHydrogens: PD.Boolean(false),
+        onlyPolarHydrogens: PD.Boolean(false),
         ignoreLight: PD.Boolean(false),
         material: Material.getParam(),
         clip: PD.Group(Clip.Params),
@@ -80,7 +81,7 @@ class StructureFocusRepresentationBehavior extends PluginBehavior.WithSubscriber
             ...reprParams,
             type: {
                 name: reprParams.type.name,
-                params: { ...reprParams.type.params, ignoreHydrogens: this.params.ignoreHydrogens, ignoreLight: this.params.ignoreLight, material: this.params.material, clip: this.params.clip }
+                params: { ...reprParams.type.params, ignoreHydrogens: this.params.ignoreHydrogens, onlyPolarHydrogens: this.params.onlyPolarHydrogens, ignoreLight: this.params.ignoreLight, material: this.params.material, clip: this.params.clip }
             }
         };
     }
diff --git a/src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts b/src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts
index d097587e911fdc6910d6b8bb8e574433a79cce2c..0d9476ce3d49cffac7f03538de7c9e25939c18ca 100644
--- a/src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts
+++ b/src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts
@@ -222,6 +222,7 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex
                 newProps.linkScale !== currentProps.linkScale ||
                 newProps.linkSpacing !== currentProps.linkSpacing ||
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 newProps.linkCap !== currentProps.linkCap ||
                 newProps.aromaticScale !== currentProps.aromaticScale ||
                 newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
@@ -264,6 +265,7 @@ export function InterUnitBondCylinderMeshVisual(materialId: number): ComplexVisu
                 newProps.linkScale !== currentProps.linkScale ||
                 newProps.linkSpacing !== currentProps.linkSpacing ||
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 newProps.linkCap !== currentProps.linkCap ||
                 newProps.aromaticScale !== currentProps.aromaticScale ||
                 newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
diff --git a/src/mol-repr/structure/visual/bond-inter-unit-line.ts b/src/mol-repr/structure/visual/bond-inter-unit-line.ts
index f7cda2e4aac21e0ff604a2ac7ed311a98b85175c..ab6c1436b2bf8e72ea202baf37d17af9fbb73de9 100644
--- a/src/mol-repr/structure/visual/bond-inter-unit-line.ts
+++ b/src/mol-repr/structure/visual/bond-inter-unit-line.ts
@@ -138,6 +138,7 @@ export function InterUnitBondLineVisual(materialId: number): ComplexVisual<Inter
                 newProps.aromaticDashCount !== currentProps.aromaticDashCount ||
                 newProps.dashCount !== currentProps.dashCount ||
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
                 !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
                 newProps.multipleBonds !== currentProps.multipleBonds
diff --git a/src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts b/src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts
index ec837f48eebd89e02b9fbcf1af3095eb6785560e..5e2e95dadf39197bfeb4ec4078b4712e43187573 100644
--- a/src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts
+++ b/src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts
@@ -239,6 +239,7 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi
                 newProps.linkScale !== currentProps.linkScale ||
                 newProps.linkSpacing !== currentProps.linkSpacing ||
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 newProps.linkCap !== currentProps.linkCap ||
                 newProps.aromaticScale !== currentProps.aromaticScale ||
                 newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
@@ -286,6 +287,7 @@ export function IntraUnitBondCylinderMeshVisual(materialId: number): UnitsVisual
                 newProps.linkScale !== currentProps.linkScale ||
                 newProps.linkSpacing !== currentProps.linkSpacing ||
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 newProps.linkCap !== currentProps.linkCap ||
                 newProps.aromaticScale !== currentProps.aromaticScale ||
                 newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
diff --git a/src/mol-repr/structure/visual/bond-intra-unit-line.ts b/src/mol-repr/structure/visual/bond-intra-unit-line.ts
index 68d1ca4f957cdaa27a37a280f6c41cc7823f9eeb..640d93cda7384a7e2ba470aacfb29c2a113b4141 100644
--- a/src/mol-repr/structure/visual/bond-intra-unit-line.ts
+++ b/src/mol-repr/structure/visual/bond-intra-unit-line.ts
@@ -164,6 +164,7 @@ export function IntraUnitBondLineVisual(materialId: number): UnitsVisual<IntraUn
                 newProps.aromaticDashCount !== currentProps.aromaticDashCount ||
                 newProps.dashCount !== currentProps.dashCount ||
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
                 !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
                 newProps.aromaticBonds !== currentProps.aromaticBonds ||
diff --git a/src/mol-repr/structure/visual/element-cross.ts b/src/mol-repr/structure/visual/element-cross.ts
index 557a970feedadcd0090fc661e273dc0d7647df62..d69d80ba3a583ffa01dd3c7106ca245b4ce91f5c 100644
--- a/src/mol-repr/structure/visual/element-cross.ts
+++ b/src/mol-repr/structure/visual/element-cross.ts
@@ -27,6 +27,7 @@ export const ElementCrossParams = {
     ...UnitsLinesParams,
     lineSizeAttenuation: PD.Boolean(false),
     ignoreHydrogens: PD.Boolean(false),
+    onlyPolarHydrogens: PD.Boolean(false),
     traceOnly: PD.Boolean(false),
     crosses: PD.Select('lone', PD.arrayToOptions(['lone', 'all'] as const)),
     crossSize: PD.Numeric(0.35, { min: 0, max: 2, step: 0.01 }),
@@ -85,6 +86,7 @@ export function ElementCrossVisual(materialId: number): UnitsVisual<ElementCross
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementCrossParams>, currentProps: PD.Values<ElementCrossParams>) => {
             state.createGeometry = (
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 newProps.traceOnly !== currentProps.traceOnly ||
                 newProps.crosses !== currentProps.crosses ||
                 newProps.crossSize !== currentProps.crossSize
diff --git a/src/mol-repr/structure/visual/element-point.ts b/src/mol-repr/structure/visual/element-point.ts
index 05dd4740d4e5b9f921511604fa02363f3b0c7454..a50e5fc9cdd5e39f01bccd79b29e7b84dccac7c2 100644
--- a/src/mol-repr/structure/visual/element-point.ts
+++ b/src/mol-repr/structure/visual/element-point.ts
@@ -23,6 +23,7 @@ export const ElementPointParams = {
     ...UnitsPointsParams,
     pointSizeAttenuation: PD.Boolean(false),
     ignoreHydrogens: PD.Boolean(false),
+    onlyPolarHydrogens: PD.Boolean(false),
     traceOnly: PD.Boolean(false),
 };
 export type ElementPointParams = typeof ElementPointParams
@@ -89,6 +90,7 @@ export function ElementPointVisual(materialId: number): UnitsVisual<ElementPoint
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementPointParams>, currentProps: PD.Values<ElementPointParams>) => {
             state.createGeometry = (
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 newProps.traceOnly !== currentProps.traceOnly
             );
         }
diff --git a/src/mol-repr/structure/visual/element-sphere.ts b/src/mol-repr/structure/visual/element-sphere.ts
index e7fc70aa05915aa37240e705ef41c1f265c08e45..909934efd8b6e630921ca1e2126b12f7c27e60d4 100644
--- a/src/mol-repr/structure/visual/element-sphere.ts
+++ b/src/mol-repr/structure/visual/element-sphere.ts
@@ -20,6 +20,7 @@ export const ElementSphereParams = {
     sizeFactor: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
     detail: PD.Numeric(0, { min: 0, max: 3, step: 1 }, BaseGeometry.CustomQualityParamInfo),
     ignoreHydrogens: PD.Boolean(false),
+    onlyPolarHydrogens: PD.Boolean(false),
     traceOnly: PD.Boolean(false),
     tryUseImpostor: PD.Boolean(true),
 };
@@ -41,6 +42,7 @@ export function ElementSphereImpostorVisual(materialId: number): UnitsVisual<Ele
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementSphereParams>, currentProps: PD.Values<ElementSphereParams>) => {
             state.createGeometry = (
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 newProps.traceOnly !== currentProps.traceOnly
             );
         },
@@ -62,6 +64,7 @@ export function ElementSphereMeshVisual(materialId: number): UnitsVisual<Element
                 newProps.sizeFactor !== currentProps.sizeFactor ||
                 newProps.detail !== currentProps.detail ||
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
                 newProps.traceOnly !== currentProps.traceOnly
             );
         },
diff --git a/src/mol-repr/structure/visual/gaussian-density-volume.ts b/src/mol-repr/structure/visual/gaussian-density-volume.ts
index 21deb9c37678c56fec7d16ba6d2996180a3d2323..e347f81433bc9acec7f99bc23a1fb2f9a0d7bd93 100644
--- a/src/mol-repr/structure/visual/gaussian-density-volume.ts
+++ b/src/mol-repr/structure/visual/gaussian-density-volume.ts
@@ -43,6 +43,7 @@ export const GaussianDensityVolumeParams = {
     ...ComplexDirectVolumeParams,
     ...GaussianDensityParams,
     ignoreHydrogens: PD.Boolean(false),
+    onlyPolarHydrogens: PD.Boolean(false),
     includeParent: PD.Boolean(false, { isHidden: true }),
 };
 export type GaussianDensityVolumeParams = typeof GaussianDensityVolumeParams
@@ -59,6 +60,7 @@ export function GaussianDensityVolumeVisual(materialId: number): ComplexVisual<G
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
         },
@@ -99,6 +101,7 @@ export const UnitsGaussianDensityVolumeParams = {
     ...UnitsDirectVolumeParams,
     ...GaussianDensityParams,
     ignoreHydrogens: PD.Boolean(false),
+    onlyPolarHydrogens: PD.Boolean(false),
     includeParent: PD.Boolean(false, { isHidden: true }),
 };
 export type UnitsGaussianDensityVolumeParams = typeof UnitsGaussianDensityVolumeParams
@@ -115,6 +118,7 @@ export function UnitsGaussianDensityVolumeVisual(materialId: number): UnitsVisua
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
         },
diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts
index b8223d3a42185024d59922bd4976c790e9be0321..06e2116850896ac4603e87c509e2731448396bd2 100644
--- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts
+++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts
@@ -34,6 +34,7 @@ const SharedParams = {
     ...GaussianDensityParams,
     ...ColorSmoothingParams,
     ignoreHydrogens: PD.Boolean(false),
+    onlyPolarHydrogens: PD.Boolean(false),
     tryUseGpu: PD.Boolean(true),
     includeParent: PD.Boolean(false, { isHidden: true }),
 };
@@ -127,6 +128,7 @@ export function GaussianSurfaceMeshVisual(materialId: number): UnitsVisual<Gauss
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
             if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
@@ -193,6 +195,7 @@ export function StructureGaussianSurfaceMeshVisual(materialId: number): ComplexV
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
                 state.updateColor = true;
@@ -264,6 +267,7 @@ export function GaussianSurfaceTextureMeshVisual(materialId: number): UnitsVisua
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
             if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
@@ -339,6 +343,7 @@ export function StructureGaussianSurfaceTextureMeshVisual(materialId: number): C
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
             if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
diff --git a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts
index aa5cddb98437596aeb3d70dab436cf1448524d81..59eb1bc9cd1f924d947c3a88a868597a3ee361fe 100644
--- a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts
+++ b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts
@@ -41,6 +41,7 @@ export const GaussianWireframeParams = {
     sizeFactor: PD.Numeric(3, { min: 0, max: 10, step: 0.1 }),
     lineSizeAttenuation: PD.Boolean(false),
     ignoreHydrogens: PD.Boolean(false),
+    onlyPolarHydrogens: PD.Boolean(false),
     includeParent: PD.Boolean(false, { isHidden: true }),
 };
 export type GaussianWireframeParams = typeof GaussianWireframeParams
@@ -57,6 +58,7 @@ export function GaussianWireframeVisual(materialId: number): UnitsVisual<Gaussia
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
         }
diff --git a/src/mol-repr/structure/visual/molecular-surface-mesh.ts b/src/mol-repr/structure/visual/molecular-surface-mesh.ts
index d30c6d4ee499bb239587182177d6916da47f471f..5e0608039b102033f7f1754abd0a4c4dd1c77590 100644
--- a/src/mol-repr/structure/visual/molecular-surface-mesh.ts
+++ b/src/mol-repr/structure/visual/molecular-surface-mesh.ts
@@ -83,6 +83,7 @@ export function MolecularSurfaceMeshVisual(materialId: number): UnitsVisual<Mole
             if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true;
             if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
 
@@ -151,6 +152,7 @@ export function StructureMolecularSurfaceMeshVisual(materialId: number): Complex
             if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true;
             if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
 
diff --git a/src/mol-repr/structure/visual/molecular-surface-wireframe.ts b/src/mol-repr/structure/visual/molecular-surface-wireframe.ts
index f3a2c07788a8676a98933609e2ae2b0057840d7c..45b93917a3c66a3aeca9a00e968e0d50c06aa97d 100644
--- a/src/mol-repr/structure/visual/molecular-surface-wireframe.ts
+++ b/src/mol-repr/structure/visual/molecular-surface-wireframe.ts
@@ -57,6 +57,7 @@ export function MolecularSurfaceWireframeVisual(materialId: number): UnitsVisual
             if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true;
             if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
+            if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
         }
     }, materialId);
diff --git a/src/mol-repr/structure/visual/util/bond.ts b/src/mol-repr/structure/visual/util/bond.ts
index 61086d2585c30e9da0ba80ce8ec7338581bdac45..4fc89d01935a742bceaebb76e6c962ff18681ce2 100644
--- a/src/mol-repr/structure/visual/util/bond.ts
+++ b/src/mol-repr/structure/visual/util/bond.ts
@@ -2,6 +2,7 @@
  * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author David Sehnal <david.sehnal@gmail.com>
  */
 
 import { BondType } from '../../../../mol-model/structure/model/types';
@@ -14,11 +15,13 @@ import { PickingId } from '../../../../mol-geo/geometry/picking';
 import { EmptyLoci, Loci } from '../../../../mol-model/loci';
 import { Interval, OrderedSet, SortedArray } from '../../../../mol-data/int';
 import { isH, isHydrogen, StructureGroup } from './common';
+import { hasPolarNeighbour } from '../../../../mol-model-props/computed/chemistry/functional-group';
 
 export const BondParams = {
     includeTypes: PD.MultiSelect(ObjectKeys(BondType.Names), PD.objectToOptions(BondType.Names)),
     excludeTypes: PD.MultiSelect([] as BondType.Names[], PD.objectToOptions(BondType.Names)),
     ignoreHydrogens: PD.Boolean(false),
+    onlyPolarHydrogens: PD.Boolean(false),
     aromaticBonds: PD.Boolean(true, { description: 'Display aromatic bonds with dashes' }),
     multipleBonds: PD.Select('symmetric', PD.arrayToOptions(['off', 'symmetric', 'offset'] as const)),
 };
@@ -51,7 +54,7 @@ export function makeIntraBondIgnoreTest(structure: Structure, unit: Unit.Atomic,
     const { a, b, edgeProps } = bonds;
     const { flags: _flags } = edgeProps;
 
-    const { ignoreHydrogens, includeTypes, excludeTypes } = props;
+    const { ignoreHydrogens, onlyPolarHydrogens, includeTypes, excludeTypes } = props;
 
     const include = BondType.fromNames(includeTypes);
     const exclude = BondType.fromNames(excludeTypes);
@@ -61,14 +64,31 @@ export function makeIntraBondIgnoreTest(structure: Structure, unit: Unit.Atomic,
     const childUnit = child?.unitMap.get(unit.id);
     if (child && !childUnit) throw new Error('expected childUnit to exist if child exists');
 
-    if (allBondTypes && !ignoreHydrogens && !child) return;
+    if (allBondTypes && !onlyPolarHydrogens && !ignoreHydrogens && !child) return;
 
     return (edgeIndex: number) => {
-        return (
-            (!!childUnit && !SortedArray.has(childUnit.elements, elements[a[edgeIndex]])) ||
-            (ignoreHydrogens && (isH(atomicNumber, elements[a[edgeIndex]]) || isH(atomicNumber, elements[b[edgeIndex]]))) ||
-            (!allBondTypes && ignoreBondType(include, exclude, _flags[edgeIndex]))
-        );
+        const aI = a[edgeIndex];
+        const bI = b[edgeIndex];
+
+        if ((!!childUnit && !SortedArray.has(childUnit.elements, elements[aI]))) {
+            return true;
+        }
+
+        if (!allBondTypes && ignoreBondType(include, exclude, _flags[edgeIndex])) {
+            return true;
+        }
+
+        if (!ignoreHydrogens && !onlyPolarHydrogens) return false;
+        if (isH(atomicNumber, elements[aI])) {
+            if (ignoreHydrogens) return true;
+            if (onlyPolarHydrogens && !hasPolarNeighbour(structure, unit, aI)) return true;
+        }
+        if (isH(atomicNumber, elements[bI])) {
+            if (ignoreHydrogens) return true;
+            if (onlyPolarHydrogens && !hasPolarNeighbour(structure, unit, bI)) return true;
+        }
+
+        return false;
     };
 }
 
@@ -76,7 +96,7 @@ export function makeInterBondIgnoreTest(structure: Structure, props: BondProps):
     const bonds = structure.interUnitBonds;
     const { edges } = bonds;
 
-    const { ignoreHydrogens, includeTypes, excludeTypes } = props;
+    const { ignoreHydrogens, onlyPolarHydrogens, includeTypes, excludeTypes } = props;
 
     const include = BondType.fromNames(includeTypes);
     const exclude = BondType.fromNames(excludeTypes);
@@ -84,7 +104,7 @@ export function makeInterBondIgnoreTest(structure: Structure, props: BondProps):
 
     const { child } = structure;
 
-    if (allBondTypes && !ignoreHydrogens && !child) return;
+    if (allBondTypes && !onlyPolarHydrogens && !ignoreHydrogens && !child) return;
 
     return (edgeIndex: number) => {
         if (child) {
@@ -104,6 +124,18 @@ export function makeInterBondIgnoreTest(structure: Structure, props: BondProps):
             if (isHydrogen(uA, uA.elements[b.indexA]) || isHydrogen(uB, uB.elements[b.indexB])) return true;
         }
 
+        if (onlyPolarHydrogens) {
+            const b = edges[edgeIndex];
+            const uA = structure.unitMap.get(b.unitA);
+            if (isHydrogen(uA, uA.elements[b.indexA]) && !hasPolarNeighbour(structure, uA as Unit.Atomic, b.indexA)) {
+                return true;
+            }
+            const uB = structure.unitMap.get(b.unitB);
+            if (isHydrogen(uB, uB.elements[b.indexB]) && !hasPolarNeighbour(structure, uB as Unit.Atomic, b.indexB)) {
+                return true;
+            }
+        }
+
         if (!allBondTypes) {
             if (ignoreBondType(include, exclude, edges[edgeIndex].props.flag)) return true;
         }
diff --git a/src/mol-repr/structure/visual/util/common.ts b/src/mol-repr/structure/visual/util/common.ts
index 50d3f2659866cf41cfea42ed9147cb4a90dcc6b4..e2e9aa0156e51c1a612d79494d4afbfa46565d00 100644
--- a/src/mol-repr/structure/visual/util/common.ts
+++ b/src/mol-repr/structure/visual/util/common.ts
@@ -2,6 +2,7 @@
  * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author David Sehnal <david.sehnal@gmail.com>
  */
 
 import { Unit, Structure, ElementIndex, StructureElement, ResidueIndex } from '../../../../mol-model/structure';
@@ -16,6 +17,7 @@ import { AssignableArrayLike } from '../../../../mol-util/type-helpers';
 import { getBoundary } from '../../../../mol-math/geometry/boundary';
 import { Box3D } from '../../../../mol-math/geometry';
 import { SizeTheme } from '../../../../mol-theme/size';
+import { hasPolarNeighbour } from '../../../../mol-model-props/computed/chemistry/functional-group';
 
 /** Return a Loci for the elements of a whole residue the elementIndex belongs to. */
 export function getResidueLoci(structure: Structure, unit: Unit.Atomic, elementIndex: ElementIndex): Loci {
@@ -139,6 +141,7 @@ export function getConformation(unit: Unit) {
 
 export const CommonSurfaceParams = {
     ignoreHydrogens: PD.Boolean(false, { description: 'Whether or not to include hydrogen atoms in the surface calculation.' }),
+    onlyPolarHydrogens: PD.Boolean(false, { description: 'Whether or not to include polar hydrogen atoms in the surface calculation.' }),
     traceOnly: PD.Boolean(false, { description: 'Whether or not to only use trace atoms in the surface calculation.' }),
     includeParent: PD.Boolean(false, { description: 'Include elements of the parent structure in surface calculation to get a surface patch of the current structure.' }),
 };
@@ -166,7 +169,7 @@ function filterUnitId(id: AssignableArrayLike<number>, elements: SortedArray, in
 }
 
 export function getUnitConformationAndRadius(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: CommonSurfaceProps) {
-    const { ignoreHydrogens, traceOnly, includeParent } = props;
+    const { ignoreHydrogens, onlyPolarHydrogens, traceOnly, includeParent } = props;
     const rootUnit = includeParent ? structure.root.unitMap.get(unit.id) : unit;
     const differentRoot = includeParent && rootUnit !== unit;
 
@@ -179,12 +182,13 @@ export function getUnitConformationAndRadius(structure: Structure, unit: Unit, s
     let indices: SortedArray<ElementIndex>;
     let id: AssignableArrayLike<number>;
 
-    if (ignoreHydrogens || traceOnly || differentRoot) {
+    if (ignoreHydrogens || onlyPolarHydrogens || traceOnly || differentRoot) {
         const _indices: number[] = [];
         const _id: number[] = [];
         for (let i = 0, il = elements.length; i < il; ++i) {
             const eI = elements[i];
             if (ignoreHydrogens && isHydrogen(rootUnit, eI)) continue;
+            if (onlyPolarHydrogens && isHydrogen(rootUnit, eI) && Unit.isAtomic(rootUnit) && !hasPolarNeighbour(structure, rootUnit, SortedArray.indexOf(rootUnit.elements, eI) as StructureElement.UnitIndex)) continue;
             if (traceOnly && !isTrace(rootUnit, eI)) continue;
             if (differentRoot && squaredDistance(x[eI], y[eI], z[eI], center) > radiusSq) continue;
 
@@ -215,7 +219,7 @@ export function getUnitConformationAndRadius(structure: Structure, unit: Unit, s
 }
 
 export function getStructureConformationAndRadius(structure: Structure, sizeTheme: SizeTheme<any>, props: CommonSurfaceProps) {
-    const { ignoreHydrogens, traceOnly, includeParent } = props;
+    const { ignoreHydrogens, onlyPolarHydrogens, traceOnly, includeParent } = props;
     const differentRoot = includeParent && !!structure.parent;
     const l = StructureElement.Location.create(structure.root);
 
@@ -230,7 +234,7 @@ export function getStructureConformationAndRadius(structure: Structure, sizeThem
     let id: AssignableArrayLike<number>;
     let indices: OrderedSet<number>;
 
-    if (ignoreHydrogens || traceOnly || differentRoot) {
+    if (ignoreHydrogens || onlyPolarHydrogens || traceOnly || differentRoot) {
         const { getSerialIndex } = structure.serialMapping;
         const units = differentRoot ? structure.root.units : structure.units;
 
@@ -249,6 +253,7 @@ export function getStructureConformationAndRadius(structure: Structure, sizeThem
             for (let j = 0, jl = elements.length; j < jl; ++j) {
                 const eI = elements[j];
                 if (ignoreHydrogens && isHydrogen(unit, eI)) continue;
+                if (onlyPolarHydrogens && isHydrogen(unit, eI) && Unit.isAtomic(unit) && !hasPolarNeighbour(structure, unit, SortedArray.indexOf(unit.elements, eI) as StructureElement.UnitIndex)) continue;
                 if (traceOnly && !isTrace(unit, eI)) continue;
 
                 const _x = x(eI), _y = y(eI), _z = z(eI);
diff --git a/src/mol-repr/structure/visual/util/element.ts b/src/mol-repr/structure/visual/util/element.ts
index 2c51b20c6eac4deaef9d914ec4761106f875a3a7..a55a776bec0fa596c5cadff9fdd2e30510fe93c8 100644
--- a/src/mol-repr/structure/visual/util/element.ts
+++ b/src/mol-repr/structure/visual/util/element.ts
@@ -21,12 +21,14 @@ import { Spheres } from '../../../../mol-geo/geometry/spheres/spheres';
 import { SpheresBuilder } from '../../../../mol-geo/geometry/spheres/spheres-builder';
 import { isTrace, isH, StructureGroup } from './common';
 import { Sphere3D } from '../../../../mol-math/geometry';
+import { hasPolarNeighbour } from '../../../../mol-model-props/computed/chemistry/functional-group';
 
 // avoiding namespace lookup improved performance in Chrome (Aug 2020)
 const v3add = Vec3.add;
 
 type ElementProps = {
     ignoreHydrogens: boolean,
+    onlyPolarHydrogens: boolean,
     traceOnly: boolean,
 }
 
@@ -36,7 +38,7 @@ export type ElementSphereMeshProps = {
 } & ElementProps
 
 export function makeElementIgnoreTest(structure: Structure, unit: Unit, props: ElementProps): undefined | ((i: ElementIndex) => boolean) {
-    const { ignoreHydrogens, traceOnly } = props;
+    const { ignoreHydrogens, onlyPolarHydrogens, traceOnly } = props;
 
     const { atomicNumber } = unit.model.atomicHierarchy.derived.atom;
     const isCoarse = Unit.isCoarse(unit);
@@ -45,14 +47,26 @@ export function makeElementIgnoreTest(structure: Structure, unit: Unit, props: E
     const childUnit = child?.unitMap.get(unit.id);
     if (child && !childUnit) throw new Error('expected childUnit to exist if child exists');
 
-    if (!child && !ignoreHydrogens && !traceOnly) return;
+    if (!child && !ignoreHydrogens && !traceOnly && !onlyPolarHydrogens) return;
 
     return (element: ElementIndex) => {
-        return (
-            (!!childUnit && !SortedArray.has(childUnit.elements, element)) ||
-            (!isCoarse && ignoreHydrogens && isH(atomicNumber, element)) ||
-            (traceOnly && !isTrace(unit, element))
-        );
+        if (!!childUnit && !SortedArray.has(childUnit.elements, element)) {
+            return true;
+        }
+
+        if (traceOnly && !isTrace(unit, element)) {
+            return true;
+        }
+
+        if (isCoarse) return false;
+
+        if (!isH(atomicNumber, element)) return false;
+        if (ignoreHydrogens) return true;
+        if (onlyPolarHydrogens) {
+            return !hasPolarNeighbour(structure, unit, SortedArray.indexOf(unit.elements, element) as StructureElement.UnitIndex);
+        }
+
+        return false;
     };
 }
 
diff --git a/src/mol-repr/volume/direct-volume.ts b/src/mol-repr/volume/direct-volume.ts
index 72d3840884b03b68e38b1095441bf06b66db9f5d..24a69b3a2c87049b9490ba8690c910840507ee78 100644
--- a/src/mol-repr/volume/direct-volume.ts
+++ b/src/mol-repr/volume/direct-volume.ts
@@ -129,7 +129,9 @@ export const DirectVolumeParams = {
 };
 export type DirectVolumeParams = typeof DirectVolumeParams
 export function getDirectVolumeParams(ctx: ThemeRegistryContext, volume: Volume) {
-    return PD.clone(DirectVolumeParams);
+    const params = PD.clone(DirectVolumeParams);
+    params.controlPoints.getVolume = () => volume;
+    return params;
 }
 export type DirectVolumeProps = PD.Values<DirectVolumeParams>
 
diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts
index 5516f909767c683b15f454206eae413ea082d4c0..59aee99dd0f770dfac1c40adf65bf74e901c964e 100644
--- a/src/mol-util/param-definition.ts
+++ b/src/mol-util/param-definition.ts
@@ -216,10 +216,13 @@ export namespace ParamDefinition {
     }
 
     export interface LineGraph extends Base<Vec2Data[]> {
-        type: 'line-graph'
+        type: 'line-graph',
+        getVolume?: () => unknown
     }
-    export function LineGraph(defaultValue: Vec2Data[], info?: Info): LineGraph {
-        return setInfo<LineGraph>({ type: 'line-graph', defaultValue }, info);
+    export function LineGraph(defaultValue: Vec2Data[], info?: Info & { getVolume?: (binCount?: number) => unknown }): LineGraph {
+        const ret = setInfo<LineGraph>({ type: 'line-graph', defaultValue }, info);
+        if (info?.getVolume) ret.getVolume = info.getVolume;
+        return ret;
     }
 
     export interface Group<T> extends Base<T> {