Skip to main content

Write scientific articles in Markdown and convert them to journal-ready LaTeX/PDF (Copernicus, Science, AMS, ...)

Project description

texmark

pypi python tests

Write scientific articles in markdown — and submit them to any journal.

  • Instant preview. Markdown renders live in most editors (VS Code, Cursor, JetBrains, vim) and on GitHub itself, so you see your draft as you type. No more wait-on-pdflatex cycles every time you change a sentence.
  • Git + GitHub as a paper backend. Branches, pull requests, issues, blame, and diffs work the way they were designed to. Collaborators review changes with the same tooling they already use for code.
  • One source, any journal. texmark compiles your markdown to any of the supported LaTeX templates. Start writing first, decide on a target journal later, and switch mid-way (or after rejection) by flipping a single yaml field — no rewriting needed.
  • No lock-in. The intermediate .tex is right there next to the PDF. Unplug texmark whenever you want and continue the manuscript in plain LaTeX — useful for the final polish that journals usually demand.

Installation

pip install texmark

External dependencies

texmark itself is pure Python, but it shells out to a few external tools to produce the final PDF. Install them via your system package manager.

  • pandoc — the markdown → tex engine (the pypandoc PyPI dependency is a wrapper, the binary is not installable via pip).
  • A LaTeX distribution providing pdflatex and bibtex plus the standard package set (hyperref, natbib, amsmath, graphicx, geometry, microtype, booktabs, caption, mathptmx, newtxtext, newtxmath, apacite, draftwatermark, mdframed, tikz, xcolor, appendix, lineno, epstopdf, …).

On Debian / Ubuntu:

sudo apt install pandoc \
    texlive-latex-extra texlive-bibtex-extra \
    texlive-publishers texlive-fonts-extra

…or just texlive-full for the easy answer.

On macOS (Homebrew):

brew install pandoc
brew install --cask mactex     # or basictex + tlmgr install <packages>

A handful of LaTeX packages that aren't in TeX Live's smaller installs (notably trackchanges, algorithm / algorithmicx, jabbrv) are bundled with texmark under texmark/templates/<journal>/ and copied into the build directory automatically, so you don't need to install them separately.

Example

See example.md for a sample markdown file with yaml metadata in the header.

The command to convert the markdow to tex is:

texmark example.md

And to convert to PDF

texmark example.md --pdf

For another journal, it is enough to change the journal -> template' field in the yaml metadata. For testing it is also possible to pass -jfor--journal-template`:

texmark example.md --pdf -j science -o build/example-science.pdf --tex build/example-science.tex

See the example tex and pdf results in build

Journal templates

Pick the template that matches your target journal and add it to the yaml header of your markdown:

journal:
    template: ametsoc          # template name, see table below
    options: twocol            # optional, per-template — see the docs page
template covers example docs
copernicus (aliases cp, esd, ...) Copernicus / EGU: ACP, BG, CP, ESD, HESS, NHESS, TC, ... PDF docs
science AAAS Science, Science Advances PDF docs
ametsoc (aliases jclim, jas, mwr, bams, ...) AMS: J. Climate, JAS, MWR, BAMS, ... PDF docs
arxiv (alias preprint) arXiv preprint, generic article-class PDF docs
elsarticle (alias elsevier) Elsevier: QSR, EPSL, GPC, Earth-Science Reviews, Cell, Lancet, ... PDF docs
agujournal (aliases agu, jgr, grl, james, wrr, ...) AGU: JGR family, GRL, Earth's Future, JAMES, ... PDF docs
springernature (aliases nature, naturecomms, natclimchange, natgeoscience, scirep) Springer Nature: Nature, Nature Communications, Nature Climate Change, Nature Geoscience, Scientific Reports, ... PDF docs
pnas PNAS PDF docs

Each template ships a default journal.options value chosen to produce a publication-style PDF (typeset 2-column journal look, no draft watermarks). For peer-review submission you usually want to switch to the publisher's submission options (e.g. preprint,12pt for Elsevier, draft for AGU, the empty default for AMS 1.5-spacing). The per-journal docs page lists the alternatives.

Partial support only. Before submitting, you will likely need to hand-edit the final LaTeX — appendix structure, special sections (Methods Online, Extended Data, Significance, …) and journal-specific cross-reference macros are not all wired up automatically. Use the example PDF to confirm the layout looks reasonable, then run texmark --tex out.tex and finish the manuscript in LaTeX directly.

Common yaml fields (all templates)

title: "Paper title"
authors:
  - firstname: Mahé
    lastname: Perrette
    affiliation: 1              # integer index into `affiliations` (most templates)
    email: mahe.perrette@gmail.com
  - firstname: Co
    lastname: Author
    affiliation: 2
affiliations:
  - "Alfred Wegener Institute, ..."
  - "Another Institution"
date: "2026-05-26"
bibliography: references.bib
journal:
    template: <name>            # required: picks the journal template + filters
    options: <str or list>      # optional: class options (per-template default)
collect_figures_and_tables: true       # optional: see section below
figure-width: 80%                      # optional: pandoc figure default
figure-span: full                      # optional: wraps in figure* (full text width)
                                       #   per-figure override: ![cap](https://github.com/perrette/texmark/raw/v0.8.0/img){figure-span=full}
copy_figures: false                    # optional: see "Figure paths" below
figure_folders: [images, ../shared]    # optional: see "Figure paths" below

Section-style metadata can also be given as markdown # ... headings. Any of # Abstract, # Acknowledgments, # Data Availability, # Appendix, # Supplementary Material, # Significance, # Capsule, # Key Points, # Plain Language Summary, # Author Contributions, # Competing Interests, # Materials and Methods, # Funding, # Highlights, # Keywords will be extracted out of the body and injected into the right LaTeX command for the target journal. The exact list each template recognises is in texmark/filters/main.py.

Figure paths

By default texmark resolves each ![](https://github.com/perrette/texmark/raw/v0.8.0/path) URL against the markdown file's directory and rewrites it in the generated .tex to be relative to the build directory. The figure files stay where they are on disk; nothing is copied.

If you would rather have short paths in the .tex (e.g. eof.png instead of ../images/eof.png), pass --figure-folders <dir> [<dir> ...] on the CLI (yaml: figure_folders: [<dir>, ...]). Each folder is interpreted relative to the current working directory and feeds LaTeX's \graphicspath. Figures that live under any of these folders get short URLs in the .tex; figures elsewhere keep the relative-to-build-dir form. Folder search order is respected (first match wins, matching pdflatex's own resolution).

For a self-contained build (e.g. to hand the .tex + figures to a journal portal), pass --copy-figures on the CLI (yaml: copy_figures: true). In that mode every referenced figure is copied flat into <build>/figures/:

  • Files keep their basename when unique.
  • When two figures share a basename but have different contents, both are renamed to <stem>-<short-content-hash><ext> for disambiguation.
  • Same file referenced from multiple paths collapses to a single bundled copy.
  • A .texmark-figures manifest in <build>/figures/ records which files texmark wrote, so the next build can delete only files it owns; files you put there by hand are preserved.

--figure-folders is ignored when --copy-figures is set (every figure ends up in <build>/figures/ either way).

Remote (http(s)://) figure URLs are always downloaded into <build>/figures/<hash>/<basename> by the texmark-download-images filter, regardless of these settings.

Collect figures and tables at the end of the document

Just add

collect_figures_and_tables: true

to your markdown yaml metadata.

Advanced: latex template

The templates are written in jinja2.

Just copy from e.g. texmark/templates/science/template.tex to your own, e.g. custom_template.tex And run again with:

texmark example.md --pdf -j science -o build/example-science.pdf --tex build/example-science.tex --template custom_template.tex

The -j journal template option (here science) is still used to set custom filters (e.g. only \cite for Science, no \citet ; extract specific sections as metadata to be injected as {{section}} instead of {{body}} etc). The machinery is defined in texmark/filters.py and can in principle be extended or copied. Two approaches are possible:

  • just add more filters via the --filters command or in the yaml metadata.
  • extend the existing filters in a module, e.g. custom_filter.py, that extends the filters dict from the texmark.filters module (see the source code to check the details). And then pass it via --filters-module custom_filter parameter (or custom_filter in the metadata) to prompt the texmark filter to load that module and make it available via -j your-custom-name. Note that will require you to explicitly pass --template as well. Unless you overwrite an existing filter.

Ackowledgements

This project benefited greatly from AI support to extend the initial list of supported journals and further extend this package capability.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

texmark-0.8.0.tar.gz (386.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

texmark-0.8.0-py3-none-any.whl (390.5 kB view details)

Uploaded Python 3

File details

Details for the file texmark-0.8.0.tar.gz.

File metadata

  • Download URL: texmark-0.8.0.tar.gz
  • Upload date:
  • Size: 386.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for texmark-0.8.0.tar.gz
Algorithm Hash digest
SHA256 279d023b8545a4b5b251c4ca4e021e291da07ebc6aafa61d1a9d896d77e6d082
MD5 ea5db524bb2f39354197f149d3cfc49c
BLAKE2b-256 2e3888a3fbca49cf098370732cc93e1436d20f23040e4715bd80de5d551c2aaa

See more details on using hashes here.

Provenance

The following attestation bundles were made for texmark-0.8.0.tar.gz:

Publisher: tests.yml on perrette/texmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file texmark-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: texmark-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 390.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for texmark-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eab73ba3c59918f407e98e1d2acd72c6963653abcbf87921510d7799b97e7981
MD5 10f0cea329c275483c8a27b9c888678e
BLAKE2b-256 23f2a4c3bd7e69b2a67ab505d2fb2eafc7b91c58c85a1091d9bc92b6b052137c

See more details on using hashes here.

Provenance

The following attestation bundles were made for texmark-0.8.0-py3-none-any.whl:

Publisher: tests.yml on perrette/texmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page