Print-ready Code 128 barcode label sheets for high-throughput screening, generated as a PDF you can run through any office laser printer.
The sheets are laid out for Premium Label Supply PLS339 stock: 1.75" x 0.5" labels, 4 columns x 20 rows = 80 labels per US Letter sheet. Each label carries a Code 128 barcode with the human-readable ID printed beneath it.
These labels are sized for 96- and 384-well microplates: they fit the skirt of a standard SBS/ANSI-footprint plate and are readable by the barcode readers built into many microscopes and plate readers, as well as by an ordinary handheld wedge (keyboard-emulation) scanner.
A ready-made sample sheet is included at examples/DEMO-0001.pdf —
print it on plain paper to check alignment against your label stock before generating your own.
pls339_barcodes.py— the generator. Prompts you for a prefix, a starting number, a sheet count, and a zero-padding width, then writes a PDF such asJZS-0001.pdf.examples/DEMO-0001.pdf— one generated sheet (DEMO-0001…DEMO-0080) so you can print a test page before generating your own.
Codes are a simple prefix + zero-padded counter, e.g. JZS-0001, JZS-0002, … Use a distinct
prefix per person, project, or experiment so IDs stay unique across the lab.
You need Python 3.9 or newer and the reportlab PDF library.
1. Check Python
python3 --version # macOS / Linux
python --version # WindowsIf Python is missing, install it from python.org/downloads (on Windows, tick "Add Python to PATH" in the installer).
2. Get this repository
git clone https://github.com/SextonLab/HTS-barcode-generator.git
cd HTS-barcode-generatorNo Git? Use the green Code → Download ZIP button on GitHub, unzip it, and cd into the folder.
3. Install ReportLab
Recommended — install into a virtual environment so it does not touch your system Python:
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txtOr install it directly:
pip install reportlabConda users:
conda create -n barcodes python=3.11 reportlab
conda activate barcodespython3 pls339_barcodes.pyYou will be prompted for four values:
| Prompt | Meaning | Example |
|---|---|---|
Prefix |
Text before the number | JZS- |
Start number |
First number in the run (default 1) |
1 |
Number of sheets |
80 labels each (default 1) |
2 |
Zero-padding digits |
Width of the number (default 4) |
4 |
The example above produces 160 labels, JZS-0001 through JZS-0160, saved as JZS-0001.pdf
in the current directory — the file is always named after its first code, so you can tell at a
glance which block of IDs a PDF contains.
Every prompt has a matching flag:
python3 pls339_barcodes.py --prefix JZS- --start 1 --sheets 2 --digits 4
python3 pls339_barcodes.py --prefix PLT --start 501 --sheets 1 --digits 5 --output sheets/PLT00501.pdf
python3 pls339_barcodes.py --helpAny flag you leave out is still asked for interactively.
The PDF is drawn at exact physical dimensions, so scaling must be turned off or the barcodes will not line up with the die-cut labels.
- Open the PDF in Adobe Acrobat Reader, Preview, or your browser's PDF viewer.
- Paper size: US Letter (8.5" x 11").
- Scaling: Actual size / 100% — not "Fit to page", "Shrink oversized pages", or "Scale to fit".
- Orientation: Portrait. No headers, footers, or duplex.
- Print one test page on plain paper first, hold it against a label sheet up to the light, and confirm the barcodes sit inside the die cuts.
- Feed the label sheets one pass at a time through a laser printer if you can. Laser toner is fused and resists solvents, condensation, and repeated handling far better than inkjet ink, which smears in the cold room and on plates coming out of an incubator.
Some printers consistently offset the whole page a millimeter or two. Correct it without touching
the code using --offset-x / --offset-y, in inches (positive = right / up):
python3 pls339_barcodes.py --prefix JZS- --start 1 --sheets 1 --digits 4 --offset-x 0.03 --offset-y -0.02Re-run the plain-paper test after each adjustment. To make an offset permanent, edit OFFSET_X
and OFFSET_Y near the top of pls339_barcodes.py.
- Apply to the long side skirt of the plate, below the well area and above the base flange, so the label stays clear of the deck seat and the plate hotel rails.
- Keep the label flat and unwrinkled — a bar deformed around a corner will not decode.
- Apply to a clean, dry, room-temperature plate; adhesive that goes on cold or wet lifts later.
- Keep a quiet zone (blank margin) at each end of the barcode. The generator already leaves one; do not trim into it or cover it with tape.
- Label lids and bases separately if lids are swapped during a workflow — the barcode identifies whatever it is stuck to, not the plate as a concept.
The symbology is Code 128 (auto-selected subset), which nearly every scanner supports out of the box and which encodes the full ASCII set:
- Integrated readers on microscopes and plate readers usually read a plate ID from a fixed position as the plate loads. Check your instrument's manual for which side and edge it expects, and place labels consistently across all plates.
- Handheld wedge scanners emulate a keyboard: click into a spreadsheet cell or a LIMS field, pull the trigger, and the ID is typed for you followed by Enter.
Keep IDs short. The barcode is scaled to fit a 1.75" label, so longer strings print narrower bars:
| Total characters | Narrow-bar width | Notes |
|---|---|---|
up to ~9 (e.g. JZS-0001) |
7.5 mil | Full size; reads reliably on essentially any scanner |
| ~10–13 | 6–7 mil | Fine for most integrated readers and modern imagers |
| 14+ | under 6 mil | Only for good imagers; test before committing to a scheme |
Purely numeric IDs are more compact than mixed letters and digits, because Code 128 packs digits two per symbol. If your instrument struggles, shorten the prefix before anything else.
Designed for Premium Label Supply PLS339 — 1.75" x 0.5", 80 labels per US Letter sheet. Any 4 x 20 sheet with the same die cut and margins will work.
To adapt the script to different stock, edit the geometry block at the top of
pls339_barcodes.py:
COLS, ROWS = 4, 20
LABEL_W, LABEL_H = 1.75*inch, 0.5*inch
MARGIN_L = 0.33*inch # outer left margin
MARGIN_R = 0.33*inch # outer right margin
H_GAP = 0.28*inch # gap between columns
MARGIN_T = 0.5*inch # top margin
MARGIN_B = 0.5*inch # bottom marginThe vertical gap between rows is computed from the page height, so top and bottom margins stay exact. Always verify a new stock with a plain-paper test print.
| Symptom | Fix |
|---|---|
ModuleNotFoundError: No module named 'reportlab' |
Activate your virtual environment, then pip install reportlab. |
python: command not found |
Try python3; on Windows re-run the installer with "Add Python to PATH". |
| Barcodes print off the label edges | Scaling is on in the print dialog — set it to Actual size / 100%. |
| Everything is shifted the same small amount | Use --offset-x / --offset-y as above. |
| Scanner will not read the labels | ID is too long (narrow bars), toner is low, the label is wrinkled, or the quiet zone is covered. |
| Numbers repeat between PDFs | Track your last-used number per prefix and set --start past it. |
MIT — see LICENSE.