Accessibility Roadmap for Avogadro

tldr. We’re working to make Avogadro as accessible as possible. Comments welcome on priorities, defaults, and anything we’ve missed — especially from people who use screen readers, keyboard-only input, magnification, or have color-vision deficiencies.

Why

Avogadro is used in teaching as well as research, so students and instructors with disabilities need to be able to use it. Today, several parts of the app are hard or impossible to use:

  • without a mouse
  • with a screen reader
  • for users with color-vision deficiency (CVD) — about 8% of men and 0.5% of women
  • with limited dexterity, or with a one-button pointer
  • for users who are sensitive to on-screen motion

Guiding principles

  1. Color is never the only cue. Selection, errors, interaction types, and similar states also need a shape, line style, label, or text.
  2. Every action is reachable from the keyboard, and the key bindings can be discovered from inside the app.
  3. Scientific conventions stay the default. CPK/Jmol element colors and red/blue orbital lobes remain the defaults. Accessible alternatives are opt-in presets, not silent changes.
  4. Follow the platform. Use standard key sequences and accessibility methods, rather than custom one-offs.

What already works well (Good News)

I ran some accessibility checks.

  • Orbitals: the red/blue lobe default stays distinct under every type of CVD.
  • Colormaps: Viridis, Cividis, Magma and Balance are already available for surfaces and color-by-property.
  • Labels in the 3D view: the measure and draw tools pick a label colour that contrasts with the background.
  • High-DPI: high-DPI scaling is handled in rendering
  • Camera: the camera can be fully controlled from the keyboard:
    • arrows or HJKL/WASD rotate
    • Shift+arrows tilt and zoom
    • Ctrl+arrows pan
    • Alt makes each step 6× larger.
    • Ctrl+arrows drive the camera from anywhere in the main window, except text fields.
  • Tools: the first nine tools have Ctrl+1 to Ctrl+9 shortcuts, and switching tools moves keyboard focus to the 3D view.
  • Draw and Template tools: you can type element symbols, bond orders, formal charges, coordination numbers and ligand/group codes.
  • Moving atoms: the manipulator moves and rotates the selection with arrows, Shift and Ctrl+Shift.
  • Selecting without a mouse:
    • the Select menu (Select by Atom Index, by Element, by Residue, Enlarge/Shrink);
    • selecting rows in the property tables selects the matching atoms.
  • Periodic table dialog: full arrow-key navigation and typed symbols.
  • One-button navigation: Shift+drag zooms and tilts, Ctrl/Cmd+drag pans, and Alt+drag gives trackball rotation, so you don’t need a middle or right button.
  • 3D-mouse support: 3Dconnexion devices are supported in avogadroapp (on Mac and Windows), giving another input option.
  • Plugin forms: forms generated from Python-plugin JSON use QFormLayout::addRow(label, widget) (jsonwidget.cpp:506), which links each label to its field automatically.
  • Tactile output: PLY, VRML and POV-Ray export already make 3D-printed and other physical models possible.

Findings

tldr We really need a “Settings” dialog that includes accessibility options, e.g. alternate element colors.

1. Color and color-vision deficiency

Default element colors: As a rough guide, pairs below about 15 are hard to tell apart on small shaded spheres.

As a rough guide, pairs below about 15 are hard to tell apart on small shaded spheres.

Pair Normal Protan Deutan Tritan
P / Cl 124 34 11 118
S / Cl 62 14 23 58
S / Mg 45 6 13 42
O / P 40 26 14 41
F / H 25 5 10 32
O / Cl 163 60 22 149

Other colour problems

  • Selection is shown by colour only, and the colour is hard-coded.
    • Ball-and-stick draws a pure blue halo (ballandstick.cpp:233), which nearly vanishes on nitrogen (48,80,255).
    • The selection tool uses a separate hard-coded yellow (selectiontool.cpp:246).
  • Default colormap is Turbo (applycolors.cpp:137, 208). It is not perceptually uniform and creates false bands under CVD.
  • Non-covalent interaction lines default to green for halogen bonds and orange for chalcogen bonds (noncovalent.cpp:66-72). These look the same to deutans, and the interaction type is shown only by colour.
  • Errors shown only as red text: filebrowsewidget.cpp:149 and unitcelldialog.cpp:344.
  • Hard-coded text colours with poor contrast or no dark-mode support. Contrast is measured as \frac{L_1 + 0.05}{L_2 + 0.05}, and WCAG AA asks for at least 4.5:1.
    • Comments in the GAMESS input highlighter use Qt::green about 1.4:1 on white.
    • The measure warning colour (200,120,0) is about 3.4:1 on white.
  • Labels and the contrast helper:
    • The label plugin defaults to white, so labels are invisible on light backgrounds.
    • contrastColor() inverts each RGB channel separately rather than using luminance, so contrast can be weak on some mid-tone backgrounds.

2. Low vision

  • Label size is set separately in each display plugin. There is no global minimum font size or “large text” setting for the 3D view. (Ideally this can be set via the operating system default)
  • There is no high-contrast preset for the 3D scene that sets background, label and selection colours together.

3. Keyboard control

  1. No keyboard way to point at an atom or bond. Every tool that works on a specific atom or bond needs a mouse: Draw, Template, Bond-centric, Measure, Align, Label. This is the biggest gap, and it also blocks screen-reader use.
  2. Align and Label tools have no shortcut. The app only assigns Ctrl+1 to Ctrl+9 by tool priority (avogadroapp mainwindow.cpp:3745).
    • Each plugin also hard-codes its own “Ctrl+N” string in its tooltip (for example navigator.cpp:47), so the tooltips will be wrong if the tool order changes.
  3. The 3D view can’t be reached with Tab. GLWidget uses Qt::ClickFocus (glwidget.cpp:32). Keyboard users can only get there by switching tools (Ctrl+N), and nothing shows that the view has focus.
  4. The Draw and Template tools swallow every printable key (editor.cpp:353, templatetool.cpp:224). They accept the event even when the key isn’t a valid symbol or digit, and even when the layer is locked.
    • As a result, the HJKL/WASD camera keys don’t work while these tools are active; only the arrows do.
    • Changing this is probably not right, because H and S are element symbols, but it should be documented.
  5. Step sizes are inconsistent.
    • Auto-optimize uses a fixed 0.1 Å step and ignores Alt.
    • Manipulator uses 0.1 Å, or 0.5 Å with Alt.
    • Auto-optimize also emits a molecule-changed signal even for keys it ignores (autoopt.cpp:851).
  6. Escape does nothing. No tool handles it: there is no way to cancel a drawing drag, clear a measurement, or abandon a label edit from the keyboard.
  7. Key bindings can’t be discovered from the app. None of the tool keys (camera keys, typing symbols, [/], Space in the animation tool) are shown in the tool panels or tooltips.
  8. Docks: There is no shortcut to move between the main docks (Tool, Display Types, Display Type Settings, Files, Layers), such as F6 or Ctrl+F6.
  9. The Layers dock’s icon columns (visibility, lock, delete) are probably not reachable by keyboard. The tree uses SelectRows, so ←/→ don’t move between columns, and activated fires for whichever column is current.
  10. Charts (qtgui/chartwidget, JKQTPlotter) zoom and pan only with the mouse. Spectra dialogs have axis-range fields as a workaround. We should confirm the chart’s context menu (copy data, export) can be opened with the keyboard.

4. Screen Readers

  • No accessibility APIs are used: there is no setAccessibleName, accessibleDescription or QAccessible* anywhere in avogadrolibs.
  • Dialogs: of 46 .ui files, only about 7 link their labels to their input fields with “buddies”, and none set accessible names. Many spin boxes and combo boxes will be announced with no label.
  • The 3D view is a plain QOpenGLWidget with no accessible description. A screen reader hears nothing about the molecule. What should it say?
  • The property tables (atoms, bonds, angles, …) are standard Qt item views. They are the most practical non-visual view of a structure, and they already sync their selection with the 3D view.

5. Motor and dexterity

This section covers pointer users with limited precision, strength or endurance: trackpad, one-button mouse, head or eye pointer, switch access, and voice control.

  • Typing has a 2-second limit. The draw tool, template tool and periodic table only keep typed characters for 2 seconds (editor.cpp:360, templatetool.cpp:245, periodictableview.cpp:71). Users of sticky keys, switch scanning or on-screen keyboards may not finish typing “Cl” in time. WCAG 2.2.1 asks for time limits to be adjustable.
  • Some actions can only be done by dragging: WCAG 2.5.7 asks for a single-pointer, non-drag alternative.
    • bonding two existing atoms;
    • rubber-band selection;
    • bond-centric rotation and stretching;
    • dragging atoms in the manipulator and auto-optimize tools.
  • Deleting one atom in the draw tool is right-click only. Selecting it and pressing Delete works but takes more steps:
    • On macOS this relies on the system’s Ctrl+click → right-click emulation.
    • Three tools still have /// @todo Use modifier keys on mac (editor.cpp:426, navigator.cpp:384, templatetool.cpp:398).
  • Small click targets. Clicking casts a single ray through one pixel (GLRenderer::hits, glrenderer.cpp:282) with no tolerance. Small atoms, thin bonds and wireframe or line displays are hard to hit. WCAG 2.5.8 sets a minimum target size.
  • Voice control (Dragon, macOS Voice Control, Windows Voice Access) finds controls by their accessible names, so the dialog fixes in section 4 help voice users too.

Open questions for the community

  1. Color-blind-safe element scheme. Which palette should we use? Options include an Okabe–Ito-based scheme for common organic and biological elements (C, H, N, O, S, P, halogens), or adjusting only the pairs that collide (P/Cl, S/Cl, O/P, F/H).
  2. Colormap default. Should we change it (Turbo → Viridis) for everyone, or only for new installs? Have a better suggestion? (I’d personally prefer a different default.)
  3. Selection highlight. What should the new default look like: an outline, a different color, or both?
  4. Atom-cursor keys. Which keys? Tab/Shift+Tab conflicts with normal focus movement out of the view; ,/. or [/] are possible alternatives.
  5. Missing workflows. Are there workflows we’ve missed, such as building peptides or DNA, crystal tools, or input generators, that need keyboard or screen-reader review?
  6. Typing timeout. Should the 2-second limit become a setting, or should typed input simply end with Enter or Escape?
  7. Reduce motion. Should vibrations start paused by default, or only when reduce-motion is on?
  8. Describe molecule. What should a text description contain to be useful in teaching? We’d especially like input from blind chemists and their instructors.
  9. Conformance target. WCAG 2.2 AA (adapted), EN 301 549, or something informal to start with?

Phew. A bunch of those things are fairly quick tasks (e.g., adding more keyboard shortcuts, adding a Settings dialog to customize default colors).

A few things are a bit less clear: how do we describe a 3D molecule (possibly including orbitals or surfaces) to a screen reader?

I’m also not entirely sure how we balance “chemistry default” for element colors with color-safe concepts.

Great initiative!

Also another colour-related one, that I don’t think i saw listed, is this one: that the x/y/z axes aren’t labelled explicitly.

Yes, the same thing is true for the a / b / c axes in the unit cell. I added that to the list of sub-tasks on GitHub: Improve accessibility (roadmap) · Issue #3186 · OpenChemistry/avogadrolibs · GitHub

Some thoughts on colours.

For element colours, I don’t think we need to stress excessively about changing the defaults, a better course of action is to provide better accessibility settings and a greater ability to customize colours.

Don’t get me wrong, accessibility is of very high importance and making it easier for people with different colour-blindnesses to work with Avogadro should absolutely be a priority – but at the end of the day the majority of users have “normal” vision, and it’s also an important part of accessibility and UI/UX design to match user expectations.

As such, I think the elements should retain colours that are typically used. That doesn’t necessarily mean the exact colours we have now, there is still room for variation within “typical colours”, but I don’t think a scheme like Okabe-Ito is the best option here, they’re better for graphs, surfaces etc.

Not to mention that schemes like Okabe-Ito comprise a relatively small set and they are not sufficient to cover all elements. Indeed, with 118 elements it is impossible to choose unique colours without any poorly distinguishable pairs.

Moreover, atom labelling is available to help distinguish elements. Taking the maxim of “never rely solely on colour”, no one should be preparing graphics without labels anyway! A small nudge in this direction, and a help to new users with colour-blindness, might be to have element labels turned on by default. :slight_smile:

With regard to the listed common pairs that are hard to distinguish, to a large extent it is clear (to everyone other than complete novices) from chemical context which element an atom is based on valency. I don’t think we need to worry too much about people confusing Cl with P, S, or O.

Size is an additional helpful cue. I’d be less worried about O/P as a pair than S/P, for example.

Slight tweaks to the colours might still be useful though, and could be helpful for everyone, even for people with normal vision – when images are projected or printed the colours often end up washed out.

The most problematic one is F/H: very similar colours and sizes, and the same valency and typical location in organic molecules, making them very easily confused, yet substitution of H for F has a massive effect on chemical behaviour and is important to be able to easily spot. The colours are difficult to distinguish even with normal vision.

For selections, some outline is definitely needed. White might be better than blue for the shading so that it doesn’t hide the underlying element colours like it does now? The outline could still have varying colours to show different kinds of selection. But I don’t think the blue shading is a big issue, the bigger issue is just that the selection marking is overall quite subtle, and a border might do enough to help with that.

For the default colourmap, a perceptually uniform would be a better choice for the default, not just for the accessibility arguments but also on scientific grounds, since non-uniform scales/maps visually emphasize some values disproportionately. Personally, I would prefer Plasma to Viridis, it feels more chemically/physicsy, and goes from cold to hot colours as a value increases.

For values either side of 0 we’d still want to use a diverging map though, probably with red and blue. matplotlib offers several, I’m not sure how perceptually uniform they are. The default would probably be white or light grey at 0, but I think it’d be nice to also offer the “Berlin” one in case a user wants/needs black at 0.

Yeah, I think the default F color can be tweaked - I’m taking some suggestions. Seems like Jmol switched to a greenish color: https://jmol.sourceforge.net/jscolors/

Hmm. Good point. Maybe it’s possible for a dashed circle or something.

As for the colormaps we have a variety of perceptually uniform options. I think the problem is the combination of the accessibility / perceptual uniform arguments on one side and the match user expectations side. For example, partial charge / electrostatic maps usually use a divergent red to blue structure. coolwarm and bwr are the most common.

A few of the other rendering types currently static colors (e.g., non-covalent and close-contact) and I think the Okabe-Ito make sense for defaults there - we already use blue, yellow, purple for some of those. Other discrete colormaps would be welcome. (And yes, before 2.2 is released, I want to make sure the static colors can be changed.)