Skip to content

Conversation

@ewels
Copy link
Contributor

@ewels ewels commented Aug 31, 2025

I recently saw @barreiro-r's work with fastqcviz and was impressed, and I felt inspired to have a go at modernising the FastQC HTML report a little.

To keep things manageable, I've split what I've done into two PRs. This first one doesn't change the layout of the report or alter the plots at all, but focusses on trying to modernise the HTML and CSS for the report whilst staying true to the original essence of FastQC reports.

CleanShot 2025-08-31 at 20 44 19@2x
CleanShot 2025-08-31 at 20 44 34@2x

The key features I've done in this PR are:

  • Removed the floating header & footer, to prioritise vertical space
  • Mobile friendly / responsive design
    • Mobile-only navigation, images now resize to fit window.
    • Used a pure CSS solution, so there's still no javascript in report
  • Switched all PNG icons for inline SVG
    • Crisper display on modern screens and (slightly) smaller filesize
    • Switched check / warn / cross icons for Material Icons
  • Updated styling for sidebar
    • Includes using more verbose pass / warn / fail labels, taken directly from fastqcviz 🙏🏻
  • Refreshed and slightly redesigned the FastQC logo
    • I drew this by hand, linking the Q and the C.
    • The font for the text in the logotype version is Urbanist
  • Updated the Readme slighlty
    • Included the FastQC logo (automatically uses correct version for both light / dark mode)
    • Included mention of Babraham bioinformatics, with logo
  • Standardised section titles to all use sentence case (rather than a mixture)

One totally new feature is that I embedded the existing module help text into a toggle-able accordion dropdown for each module. Again this is CSS-only, so no javascript needed.

Example reports: ENCSR000COQ1_1_fastqc_original.html, ENCSR000COQ1_1_fastqc_navigation.html.

Video comparing original report vs. modified from this PR, in both desktop and mobile resolutions:

CleanShot.2025-08-31.at.20.37.50.mp4

I tried to keep the code diff as minimal as possible as I went, but some whitespace-only changes did creep in unfortunately (my IDE tries really hard to remove trailing whitespace). I can attempt to remove this if you like, or alternatively I could put in a separate PR that only does this which could be merged first, to make the diff smaller.

I also ended up doing a little code restructuring to make it easier to edit the report HTML and CSS. Essentially I moved some of the more static report out of the Java XML building into static template fragments with string replacement. I also renamed the CSS template file so that syntax highlighting etc works. Finally I found one or two files that I think are orphaned, which I removed.

Risks to backwards compatability

To the best of my knowledge / testing, the interactive Java application remains unchanged.

Comparing the outputs of all files in the zip file:

summary.txt - changes in capitilisation
1c1
< PASS	Basic Statistics	ENCSR000COQ1_1.fastq.gz
---
> PASS	Basic statistics	ENCSR000COQ1_1.fastq.gz
8,9c8,9
< PASS	Sequence Length Distribution	ENCSR000COQ1_1.fastq.gz
< WARN	Sequence Duplication Levels	ENCSR000COQ1_1.fastq.gz
---
> PASS	Sequence length distribution	ENCSR000COQ1_1.fastq.gz
> WARN	Sequence duplication levels	ENCSR000COQ1_1.fastq.gz
11c11
< PASS	Adapter Content	ENCSR000COQ1_1.fastq.gz
---
> PASS	Adapter content	ENCSR000COQ1_1.fastq.gz
fastqc_data.txt - changes in capitilisation
2c2
< >>Basic Statistics	pass
---
> >>Basic statistics	pass
5459c5459
< >>Sequence Length Distribution	pass
---
> >>Sequence length distribution	pass
5463c5463
< >>Sequence Duplication Levels	warn
---
> >>Sequence duplication levels	warn
5492c5492
< >>Adapter Content	pass
---
> >>Adapter content	pass
fastqc.po - changes in capitilisation
3c3
<             <fo:inline wrap-option="no-wrap"/></fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Basic Statistics</fo:block><fo:table><fo:table-column column-width="200pt"/><fo:table-column column-width="200pt"/><fo:table-body><fo:table-row><fo:table-cell><fo:block>Filename</fo:block></fo:table-cell><fo:table-cell><fo:block>ENCSR000COQ1_1.fastq.gz</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>File type</fo:block></fo:table-cell><fo:table-cell><fo:block>Conventional base calls</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Encoding</fo:block></fo:table-cell><fo:table-cell><fo:block>Illumina 1.5</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Total Sequences</fo:block></fo:table-cell><fo:table-cell><fo:block>27816</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Total Bases</fo:block></fo:table-cell><fo:table-cell><fo:block>2.1 Mbp</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Sequences flagged as poor quality</fo:block></fo:table-cell><fo:table-cell><fo:block>0</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Sequence length</fo:block></fo:table-cell><fo:table-cell><fo:block>76</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>%GC</fo:block></fo:table-cell><fo:table-cell><fo:block>51</fo:block></fo:table-cell></fo:table-row></fo:table-body></fo:table><fo:block font-size="48pt" page-break-before="always" text-align="center">Per base sequence quality</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per tile sequence quality</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per sequence quality scores</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per base sequence content</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per sequence GC content</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per base N content</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Sequence Length Distribution</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Sequence Duplication Levels</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Overrepresented sequences</fo:block><fo:table><fo:table-column column-width="200pt"/><fo:table-column column-width="200pt"/><fo:table-column column-width="200pt"/><fo:table-column column-width="200pt"/><fo:table-body><fo:table-row><fo:table-cell><fo:block>GCACACGCCCCACACCTGTGACGCCCTCCTGTGAGCTTACCGGCCTTCGA</fo:block></fo:table-cell><fo:table-cell><fo:block>44</fo:block></fo:table-cell><fo:table-cell><fo:block>0.15818234109864826</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>CTGGGATTGTAGACGCCTGTACACACCAGGATGGAGATGCAGCTCTGGCT</fo:block></fo:table-cell><fo:table-cell><fo:block>36</fo:block></fo:table-cell><fo:table-cell><fo:block>0.12942191544434856</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>GTGCGATGGCGTGTGATCGAAGGCCGGTAAGCTCACAGGAGGGCGTCACA</fo:block></fo:table-cell><fo:table-cell><fo:block>34</fo:block></fo:table-cell><fo:table-cell><fo:block>0.12223180903077366</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>GCTTACCGGCCTTCGATCACACGCCATCGCACACGCCCCACACCTGTGAC</fo:block></fo:table-cell><fo:table-cell><fo:block>31</fo:block></fo:table-cell><fo:table-cell><fo:block>0.11144664941041128</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>CGTCACAGGTGTGGGGCGTGTGCGATGGCGTGTGATCGAAGGCCGGTAAG</fo:block></fo:table-cell><fo:table-cell><fo:block>30</fo:block></fo:table-cell><fo:table-cell><fo:block>0.10785159620362382</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>GTGAGCTTACCGGCCTTCGATCACACGCCATCGCACACGCCCCACACCTG</fo:block></fo:table-cell><fo:table-cell><fo:block>29</fo:block></fo:table-cell><fo:table-cell><fo:block>0.10425654299683634</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row></fo:table-body></fo:table><fo:block font-size="48pt" page-break-before="always" text-align="center">Adapter Content</fo:block></fo:flow></fo:page-sequence></fo:root>
\ No newline at end of file
---
>             <fo:inline wrap-option="no-wrap"/></fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Basic statistics</fo:block><fo:table><fo:table-column column-width="200pt"/><fo:table-column column-width="200pt"/><fo:table-body><fo:table-row><fo:table-cell><fo:block>Filename</fo:block></fo:table-cell><fo:table-cell><fo:block>ENCSR000COQ1_1.fastq.gz</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>File type</fo:block></fo:table-cell><fo:table-cell><fo:block>Conventional base calls</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Encoding</fo:block></fo:table-cell><fo:table-cell><fo:block>Illumina 1.5</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Total Sequences</fo:block></fo:table-cell><fo:table-cell><fo:block>27816</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Total Bases</fo:block></fo:table-cell><fo:table-cell><fo:block>2.1 Mbp</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Sequences flagged as poor quality</fo:block></fo:table-cell><fo:table-cell><fo:block>0</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>Sequence length</fo:block></fo:table-cell><fo:table-cell><fo:block>76</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>%GC</fo:block></fo:table-cell><fo:table-cell><fo:block>51</fo:block></fo:table-cell></fo:table-row></fo:table-body></fo:table><fo:block font-size="48pt" page-break-before="always" text-align="center">Per base sequence quality</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per tile sequence quality</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per sequence quality scores</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per base sequence content</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per sequence GC content</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Per base N content</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Sequence length distribution</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Sequence duplication levels</fo:block><fo:block font-size="48pt" page-break-before="always" text-align="center">Overrepresented sequences</fo:block><fo:table><fo:table-column column-width="200pt"/><fo:table-column column-width="200pt"/><fo:table-column column-width="200pt"/><fo:table-column column-width="200pt"/><fo:table-body><fo:table-row><fo:table-cell><fo:block>GCACACGCCCCACACCTGTGACGCCCTCCTGTGAGCTTACCGGCCTTCGA</fo:block></fo:table-cell><fo:table-cell><fo:block>44</fo:block></fo:table-cell><fo:table-cell><fo:block>0.15818234109864826</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>CTGGGATTGTAGACGCCTGTACACACCAGGATGGAGATGCAGCTCTGGCT</fo:block></fo:table-cell><fo:table-cell><fo:block>36</fo:block></fo:table-cell><fo:table-cell><fo:block>0.12942191544434856</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>GTGCGATGGCGTGTGATCGAAGGCCGGTAAGCTCACAGGAGGGCGTCACA</fo:block></fo:table-cell><fo:table-cell><fo:block>34</fo:block></fo:table-cell><fo:table-cell><fo:block>0.12223180903077366</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>GCTTACCGGCCTTCGATCACACGCCATCGCACACGCCCCACACCTGTGAC</fo:block></fo:table-cell><fo:table-cell><fo:block>31</fo:block></fo:table-cell><fo:table-cell><fo:block>0.11144664941041128</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>CGTCACAGGTGTGGGGCGTGTGCGATGGCGTGTGATCGAAGGCCGGTAAG</fo:block></fo:table-cell><fo:table-cell><fo:block>30</fo:block></fo:table-cell><fo:table-cell><fo:block>0.10785159620362382</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row><fo:table-row><fo:table-cell><fo:block>GTGAGCTTACCGGCCTTCGATCACACGCCATCGCACACGCCCCACACCTG</fo:block></fo:table-cell><fo:table-cell><fo:block>29</fo:block></fo:table-cell><fo:table-cell><fo:block>0.10425654299683634</fo:block></fo:table-cell><fo:table-cell><fo:block>No Hit</fo:block></fo:table-cell></fo:table-row></fo:table-body></fo:table><fo:block font-size="48pt" page-break-before="always" text-align="center">Adapter content</fo:block></fo:flow></fo:page-sequence></fo:root>
\ No newline at end of file

Hopefully these are acceptable and won't break too many people's automation. Alternatively I can revert the case changes (could probably apply them at just the HTML report level perhaps).


Thanks for the inspiration @barreiro-r and happy to hear what you think @s-andrews - if there are parts you like and parts you don't, just shout and I can update the PR accordingly 🙏🏻 Equally, if you'd rather not mess with the reports at all then it's no problem to close this PR, I was really just having fun and won't take offence, promise! 😁

Copy link
Contributor Author

@ewels ewels Aug 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where the bulk of the changes happened. Despite promising you that I'd try to learn Java ~12 years ago, I'm afraid I'm still pretty terrible at it - so apologies if there's some crud in here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file wasn't used anywhere that I can see, so I guess it's an artefact left over from a previous refactoring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant