File:Animal hearing frequency range logarithmic.svg

Original file (SVG file, nominally 512 × 410 pixels, file size: 23 KB)

Summary

Description
English: English: Lin-log graph of the hearing ranges of some animals based. This is remake of File:Animal hearing frequency range.svg, see its description for more details.
Date
Source Own work
Author Pengo
Other versions

File:Animal hearing frequency range logarithmic-es.svg

Licensing

I, the copyright holder of this work, hereby publish it under the following licenses:
w:en:Creative Commons
attribution share alike
This file is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license.
You are free:
  • to share – to copy, distribute and transmit the work
  • to remix – to adapt the work
Under the following conditions:
  • attribution – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
  • share alike – If you remix, transform, or build upon the material, you must distribute your contributions under the same or compatible license as the original.
GNU head Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled GNU Free Documentation License.
You may select the license of your choice.

Source code

"""Generate an Animal Hearing Frequency Range SVG.

Changes to the original:
- Animals grouped by taxonomic class (Fish, Amphibians, Birds, Land mammals, Marine mammals)
  with section headers, sorted within each group by upper hearing limit.
- Visible title and color legend inside the SVG.
- Cleaner typography: no horizontal squish, no negative letter-spacing.
- Human hearing range highlighted as a faint vertical band across the whole chart,
  so any other animal can be visually compared to "what humans hear".
- Removed C-note grid.
- Tweaked colors
- Octave count moved to the right of the bar (eye reads name -> range -> bar -> octaves).

Note: Python source code for the original version (File:Animal hearing frequency range.svg) is embeded as a comment in its svg.
"""
import math

# Layout constants
W = 1000
H = 800
CHART_LEFT = 290        # x of 10 Hz tick
DECADE_W = 100
CHART_TOP = 110
ROW_H = 16
HDR_H = 20
BAR_THICK = 9

NAME_X = 12
LO_NUM_X = 168          # right-anchor x for low number (always Hz)
LO_UNIT_X = 172         # left-anchor x for "Hz"
DASH_X = 210            # centered x for the en-dash separator
HI_INT_X = 245          # right-anchor x for high integer part (decimal point lands here)
HI_FRAC_X = 245         # left-anchor x for ".X" so decimals line up vertically
HI_UNIT_X = 260         # left-anchor x for "kHz"
OCT_X = 802             # left-anchor x for "(N.N oct)" text


def hz2x(hz):
    return CHART_LEFT - DECADE_W + DECADE_W * math.log10(hz)


def fmt_lo(hz):
    """Low bound: always Hz, integer."""
    return (str(int(hz)), 'Hz')


def fmt_hi(hz):
    """High bound: always kHz, split into integer / fractional parts so decimals align."""
    s = '%g' % (hz / 1000.0)
    if '.' in s:
        int_part, frac_part = s.split('.')
        return (int_part, '.' + frac_part, 'kHz')
    return (s, '', 'kHz')


# Colors (muted but with enough saturation to read clearly)
C_FISH = '#3d6fb8'    # slate blue
C_AMPH = '#5a9a3d'    # forest green
C_BIRD = '#4a5e75'    # deeper slate blue-gray (more contrast against background tints)
C_MAMM = '#d6712b'    # terracotta
C_HUMAN = '#9c4ea5'   # plum
C_MARINE = '#8a5e2e'  # sienna

# (label, lo, hi)
fish = [
    ('Tuna',     50, 1100),
    ('Goldfish', 20, 3000),
    ('Catfish',  50, 4000),
]
amph = [
    ('Bullfrog',  100, 3000),
    ('Tree frog',  50, 4000),
]
birds = [
    ('Chicken',   125, 2000),
    ('Canary',    250, 8000),
    ('Cockatiel', 250, 8000),
    ('Parakeet',  200, 8500),
    ('Owl',       200, 12000),
]
# Land mammals (human flagged separately); sort by hi then lo
mammals = [
    ('Elephant',         17, 10500),
    ('Human',            31, 19000),   # purple
    ('Chinchilla',       52, 33000),
    ('Horse',            55, 33500),
    ('Cow',              23, 35000),
    ('Raccoon',         100, 40000),
    ('Sheep',           125, 42500),
    ('Ferret',           16, 44000),
    ('Dog',              64, 44000),
    ('Hedgehog',        250, 45000),
    ('Guinea pig',       47, 49000),
    ('Rabbit',           96, 49000),
    ('Gerbil',           56, 60000),
    ('Opossum',         500, 64000),
    ('Albino rat',      390, 72000),
    ('Hooded rat',      530, 75000),
    ('Cat',              55, 77000),
    ('Mouse',           900, 79000),
    ('Little brown bat',10300,115000),
]
marine = [
    ('Sea lion',           200, 50000),
    ('Beluga whale',      1000,123000),
    ('Bottlenose dolphin', 150,150000),
    ('Porpoise',            75,150000),
]

sections = [
    ('Fish',           C_FISH,   fish),
    ('Amphibians',     C_AMPH,   amph),
    ('Birds',          C_BIRD,   birds),
    ('Land mammals',   C_MAMM,   mammals),
    ('Marine mammals', C_MARINE, marine),
]

out = []
out.append(f'<?xml version="1.0" encoding="UTF-8"?>')
out.append(f'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" '
           f'xmlns:xlink="http://www.w3.org/1999/xlink" '
           f'width="100%" height="100%" viewBox="0 0 {W} {H}" font-family="sans-serif">')
out.append('<title>Animal hearing frequency ranges</title>')
out.append('<desc>Approximate audible frequency ranges of selected vertebrates, grouped by '
           'taxonomic class. Logarithmic frequency scale. Sources: RR Fay 1988 (Hearing in '
           'Vertebrates: a Psychophysics Databook); D Warfield 1973; RR Fay and AN Popper '
           '1994; CD West 1985; EA Lipman and JR Grassi 1942; HE Heffner 1983.</desc>')

# Background
out.append(f'<rect width="{W}" height="{H}" fill="#ffffff"/>')

# Title and subtitle
out.append('<text x="500" y="30" font-size="22" font-weight="bold" text-anchor="middle" fill="#000">'
           'Animal hearing frequency ranges</text>')
out.append('<text x="500" y="50" font-size="11" text-anchor="middle" fill="#555">'
           'Approximate audible frequencies of selected vertebrates &#183; '
           '<tspan font-weight="bold">logarithmic scale</tspan></text>')

# Legend
legend_y = 78
out.append(f'<g font-size="12" fill="#000" transform="translate(0,{legend_y})">')
legend_items = [
    (140, C_FISH,   'Fish'),
    (200, C_AMPH,   'Amphibians'),
    (305, C_BIRD,   'Birds'),
    (370, C_MAMM,   'Land mammals'),
    (490, C_HUMAN,  'Human'),
    (560, C_MARINE, 'Marine mammals'),
]
for lx, col, lbl in legend_items:
    out.append(f'  <rect x="{lx}" y="0" width="14" height="11" fill="{col}"/>'
               f'<text x="{lx+20}" y="10">{lbl}</text>')
# Human-range band swatch
lx = 700
out.append(f'  <rect x="{lx}" y="0" width="14" height="11" fill="{C_HUMAN}" '
           f'fill-opacity="0.10" stroke="{C_HUMAN}" stroke-opacity="0.5"/>'
           f'<text x="{lx+20}" y="10">Human range (reference band)</text>')
out.append('</g>')

# Frequency axis labels (top of chart)
out.append('<g font-size="11" fill="#000" text-anchor="middle">')
for i, lbl in enumerate(['10 Hz', '100 Hz', '1 kHz', '10 kHz', '100 kHz', '1 MHz']):
    x = CHART_LEFT + i * DECADE_W
    out.append(f'  <text x="{x}" y="104">{lbl}</text>')
out.append('</g>')

# Compute total chart height to know bottom for grid lines
n_total_rows = sum(len(s[2]) for s in sections)
n_sections = len(sections)
chart_bottom = CHART_TOP + n_sections * HDR_H + n_total_rows * ROW_H

# Sub-decade minor grid
sub_offsets = [DECADE_W * math.log10(k) for k in range(2, 10)]
sub_paths = []
for d in range(5):
    base_x = CHART_LEFT + d * DECADE_W
    for off in sub_offsets:
        x = base_x + off
        sub_paths.append(f'M {x:.1f},{CHART_TOP} V {chart_bottom}')
out.append(f'<path d="{" ".join(sub_paths)}" stroke="#eeeeee" fill="none"/>')

# Decade major grid
dec_paths = []
for i in range(6):
    x = CHART_LEFT + i * DECADE_W
    dec_paths.append(f'M {x},{CHART_TOP} V {chart_bottom}')
out.append(f'<path d="{" ".join(dec_paths)}" stroke="#bbbbbb" fill="none"/>')

# Chart border
out.append(f'<rect x="{CHART_LEFT}" y="{CHART_TOP}" '
           f'width="{5*DECADE_W}" height="{chart_bottom - CHART_TOP}" '
           f'fill="none" stroke="#888888"/>')

# Human range band
hx_lo = hz2x(31)
hx_hi = hz2x(19000)
out.append(f'<rect x="{hx_lo:.1f}" y="{CHART_TOP}" width="{hx_hi - hx_lo:.1f}" '
           f'height="{chart_bottom - CHART_TOP}" fill="{C_HUMAN}" fill-opacity="0.12"/>')
# Subtle "Human range" label on the band, just below the top
out.append(f'<text x="{(hx_lo + hx_hi) / 2:.1f}" y="{CHART_TOP + 10}" '
           f'font-size="9" fill="{C_HUMAN}" fill-opacity="0.7" text-anchor="middle" '
           f'font-style="italic">human range</text>')

# Sections
y = CHART_TOP
for sec_name, sec_color, items in sections:
    # Section header band
    out.append(f'<rect x="0" y="{y}" width="{CHART_LEFT}" height="{HDR_H}" '
               f'fill="{sec_color}" fill-opacity="0.18"/>')
    out.append(f'<text x="{NAME_X}" y="{y + 14}" font-size="13" font-weight="bold" '
               f'fill="{sec_color}">{sec_name}</text>')
    y += HDR_H

    for i, (label, lo, hi) in enumerate(items):
        cy = y + ROW_H // 2
        ty = cy + 4
        bar_color = sec_color
        is_human = (label == 'Human')
        if is_human:
            bar_color = C_HUMAN
            # Subtle row highlight
            out.append(f'<rect x="0" y="{y}" width="{W}" height="{ROW_H}" '
                       f'fill="{C_HUMAN}" fill-opacity="0.05"/>')

        x_lo = hz2x(lo)
        x_hi = hz2x(hi)
        n_oct = math.log(hi / lo, 2)
        lo_num, lo_unit = fmt_lo(lo)
        hi_int, hi_frac, hi_unit = fmt_hi(hi)

        weight = ' font-weight="bold"' if is_human else ''
        out.append(f'  <text x="{NAME_X}" y="{ty}" font-size="12" fill="#000"{weight}>{label}</text>')
        out.append(f'  <text x="{LO_NUM_X}" y="{ty}" font-size="11" fill="#444" text-anchor="end">{lo_num}</text>')
        out.append(f'  <text x="{LO_UNIT_X}" y="{ty}" font-size="11" fill="#444">{lo_unit}</text>')
        out.append(f'  <text x="{DASH_X}" y="{ty}" font-size="11" fill="#888" text-anchor="middle">&#8211;</text>')
        out.append(f'  <text x="{HI_INT_X}" y="{ty}" font-size="11" fill="#444" text-anchor="end">{hi_int}</text>')
        if hi_frac:
            out.append(f'  <text x="{HI_FRAC_X}" y="{ty}" font-size="11" fill="#444">{hi_frac}</text>')
        out.append(f'  <text x="{HI_UNIT_X}" y="{ty}" font-size="11" fill="#444">{hi_unit}</text>')
        out.append(f'  <path d="M {x_lo:.1f},{cy} H {x_hi:.1f}" '
                   f'stroke="{bar_color}" stroke-width="{BAR_THICK}"/>')
        out.append(f'  <text x="{OCT_X}" y="{ty}" font-size="11" fill="#444">'
                   f'{n_oct:.1f} oct</text>')
        y += ROW_H

# Source / data note
out.append(f'<text x="{W // 2}" y="{H - 18}" font-size="10" text-anchor="middle" fill="#777">'
           'Data: Fay 1988; Warfield 1973; Fay &amp; Popper 1994; West 1985; '
           'Lipman &amp; Grassi 1942; Heffner 1983.</text>')

out.append('</svg>')

with open('Animal_hearing_frequency_range_logarithmic.svg', 'w', encoding='utf-8') as f:
    f.write('\n'.join(out))

print(f'Wrote SVG. Chart bottom: {chart_bottom}, total rows: {n_total_rows}, sections: {n_sections}')

Captions

English: Lin-log graph of the hearing ranges of some animals based

Items portrayed in this file

depicts

3 May 2026

image/svg+xml

File history

Click on a date/time to view the file as it appeared at that time.

Date/TimeThumbnailDimensionsUserComment
current03:04, 4 May 2026Thumbnail for version as of 03:04, 4 May 2026512 × 410 (23 KB)PengoUploaded own work with UploadWizard

The following 2 pages use this file:

Global file usage

The following other wikis use this file:

Metadata