Conversation
…rithm When mel scale is active and no step override is set, yValues() now calls generateMelScaleFrequencyValues() which: 1. Finds the finest 'nice' Hz step (100, 200, 500... Hz) that provides adequate pixel spacing at the low-frequency end of the mel scale 2. Generates all candidate ticks at that step 3. Filters out candidates whose canvas positions are too close together, naturally pruning the compressed high-frequency end Result: ~32 well-spaced ticks for a typical 600px/0-11kHz mel spectrogram vs the previous 11 ticks at 1kHz intervals. Agent-Logs-Url: https://github.com/ecoacoustics/web-components/sessions/2f19bd2a-f093-43c4-9f41-6168d03b8437 Co-authored-by: atruskie <1452968+atruskie@users.noreply.github.com>
…pnpm) Agent-Logs-Url: https://github.com/ecoacoustics/web-components/sessions/2f19bd2a-f093-43c4-9f41-6168d03b8437 Co-authored-by: atruskie <1452968+atruskie@users.noreply.github.com>
|
|
||
| // Generate all candidate tick values at the fine step. | ||
| const candidates: Hertz[] = []; | ||
| for (let freq = lowFrequency; freq < highFrequency; freq += fineStep) { |
There was a problem hiding this comment.
Fixed in 7279635 — both loops now use candidateFrequency.
Agent-Logs-Url: https://github.com/ecoacoustics/web-components/sessions/04a75c34-a06a-455a-ba7a-dff88b1aa73e Co-authored-by: atruskie <1452968+atruskie@users.noreply.github.com>
Done in 7279635: Abbreviation: renamed Tests added in
Two new fixture methods were added: Screenshots at various sizes:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot it looks a bit dense. Try doubling the height of the overlap check. Produce spectrograms for mel and non mel variations at different sizes and show in your response in GitHub |
…ce label density Agent-Logs-Url: https://github.com/ecoacoustics/web-components/sessions/01ee6873-70e5-48c3-b997-94c5fe8fd589 Co-authored-by: atruskie <1452968+atruskie@users.noreply.github.com>
Done in 91dca73. Doubled the base label height in the overlap threshold: // Before
const minPixelSpacing = fontSize.height + fontSize.height * AxesComponent.labelPadding * 2;
// After
const minPixelSpacing = fontSize.height * 2 + fontSize.height * AxesComponent.labelPadding * 2;Effect on fine-step selection: a 500 px canvas no longer fits 100 Hz at the low-frequency end (~23.6 px gap < 27.5 px threshold), so it steps up to 200 Hz. A 1000 px canvas retains 100 Hz (~47 px gap > threshold). Below is a side-by-side at four heights (linear left, mel right): Labels are now well-spaced and readable at all tested sizes. The mel-scale still carries significantly more low-frequency reference lines than the coarse 1 kHz linear grid. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Axes now generate steps progressively for mel-scales, jumping up magnitudes as we cross base 10 magnitude boundaries. This results in much nicer automated mel scale axes.
There was a problem hiding this comment.
Pull request overview
This PR aims to improve y-axis tick/grid density when rendering spectrograms with mel scaling, so the expanded low-frequency region gets more useful reference labels while still preventing label overlap toward the compressed high-frequency end.
Changes:
- Refactors axis tick generation in
oe-axesto use stepper functions (basic + mel-aware) and updates label spacing/padding calculations. - Adds Playwright E2E fixture helpers and new tests covering mel-scale y-axis tick density and step behavior across canvas sizes.
- Updates the local dev demo page interactions (event listeners + valid
window-size) and bumps the pinned pnpm version.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/components/axes/axes.ts | Refactors tick generation (stepper-based), adjusts label padding, and introduces mel-aware stepping logic. |
| src/tests/axes-spectrogram/axes-spectrogram.e2e.fixture.ts | Adds fixture helpers to create mel-scale spectrograms and mel-scale + y-step override cases. |
| src/tests/axes-spectrogram/axes-spectrogram.e2e.spec.ts | Adds mel-scale y-axis grid line tests and adjusts some size-based expectations. |
| dev/full-spectrogram.html | Improves demo UI wiring (removes inline handlers, uses module script, fixes window-size). |
| package.json | Updates the pinned packageManager pnpm version. |
| const step = | ||
| this.yStepOverride ?? | ||
| this.calculateStep( | ||
| this.unitConverter.frequencyDomain.value, | ||
| this.unitConverter.frequencyRange.value, | ||
| this.unitConverter.scaleY.value, | ||
| "height", | ||
| labelLength, | ||
| ); | ||
|
|
||
| const stepper = this.unitConverter.melScale.value | ||
| ? this.melStepper(step, labelLength, this.unitConverter.scaleY.value) | ||
| : this.basicStepper(step, labelLength, this.unitConverter.scaleY.value); |
| const stepper = this.unitConverter.melScale.value | ||
| ? this.melStepper(step, labelLength, this.unitConverter.scaleY.value) | ||
| : this.basicStepper(step, labelLength, this.unitConverter.scaleY.value); |


Mel-scale spectrograms were rendering y-axis grid lines at fixed 1 kHz intervals regardless of scale — leaving the visually dominant low-frequency region (which the mel scale expands) with almost no reference lines, while the compressed high-frequency region was relatively dense.
Root cause
calculateStep()derived the initial step from the mel-valuedfrequencyDomainmidpoint, andwillFitStep()only checked overlap at the highest-frequency pair (the most compressed). This correctly prevented overlap at the top but forced a 1 kHz step even though the expanded lower region had ample room for finer ticks.Changes —
src/components/axes/axes.tsNew
generateMelScaleFrequencyValues()— two-pass adaptive tick generator:[100, 200, 500, 1000, 2000, 5000, 10000]Hz and picks the smallest that produces ≥minPixelSpacingseparation at the low-frequency end of the scale. Steps are restricted to multiples of 100 Hz to keep 1-decimal-place kHz labels unambiguous.minPixelSpacingof the previously kept tick. Because the mel scale compresses high frequencies, this naturally prunes the top end while preserving the dense low-frequency labels.minPixelSpacinguses double the label height as its base (fontSize.height * 2 + fontSize.height * labelPadding * 2) to keep labels readable without crowding. This means a 500 px canvas selects a 200 Hz fine step, while a 1000 px canvas still fits a 100 Hz fine step.yValues()updated — routes togenerateMelScaleFrequencyValues()when mel scale is active andyStepOverrideis not set; existingcalculateStep/generateAxisValuespath unchanged otherwise.Typical result (500 px canvas, 0–11 kHz):
Step count and density auto-scale with canvas height — a 500 px canvas gets ~15 ticks at a 200 Hz fine step; a 1000 px canvas gets ~25 ticks at a 100 Hz fine step.
Changes —
src/tests/axes-spectrogram/axes-spectrogram.e2e.fixture.ts: addedcreateWithMelScaleAndSize()andcreateWithMelScaleStepOverrideAndSize()fixture helpers.axes-spectrogram.e2e.spec.ts: addedmel-scale y-axis grid linesdescribe block with tests verifying:y-stepattribute on<oe-axes>still bypasses the adaptive algorithm and applies the user-specified step exactly, even whenmel-scaleis active.