Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Goalign
[![build](https://github.com/evolbioinfo/goalign/actions/workflows/go.yml/badge.svg)](https://github.com/evolbioinfo/goalign/actions) [![Anaconda-Server Badge](https://anaconda.org/bioconda/goalign/badges/installer/conda.svg)](https://anaconda.org/bioconda/goalign) [![Docker hub](https://img.shields.io/docker/cloud/build/evolbioinfo/goalign)](https://hub.docker.com/r/evolbioinfo/goalign/builds/)
[![DOI:10.1093/nargab/lqab075](https://zenodo.org/badge/DOI/10.1093/nargab/lqab075.svg)](https://doi.org/10.1093/nargab/lqab075)

![Goalign Logo](images/logo.png)

Expand Down Expand Up @@ -144,6 +145,7 @@ You may go to the [doc](docs/index.md) for a more detailed documentation of the
* divide: Divide an input alignment in several output files (one per alignment)
* draw: Draw alignments
* biojs: Display an input alignment in an html file using [BioJS](http://msa.biojs.net/)
* png: Display an input alignment in a png file, one sequence per line and one pixel per character
* extract: Extract several sub-alignments, potentially composed of several blocks, from an input alignment, using an coordinate file
* identical: Tell whether two alignments are identical
* mask: Replace positions by N (of nucleotides) or X (if amino-acids)
Expand Down
69 changes: 69 additions & 0 deletions cmd/draw_png.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cmd

import (
"bufio"
"fmt"
"os"
"path/filepath"

"github.com/evolbioinfo/goalign/align"
"github.com/evolbioinfo/goalign/draw"
"github.com/evolbioinfo/goalign/io"
"github.com/spf13/cobra"
)

// pngCmd represents the png command
var pngCmd = &cobra.Command{
Use: "png",
Short: "Draw alignments in a png file",
Long: `Draw alignments in a png file

One line per sequence, one pixel per character.
Color schemes are specific to the alphabet of sequences:
- The nucleotide colors are from bioSyntax (doi.org/10.1186/s12859-018-2315-y).
- The amino acid colors are adapted from "Shapely colours"
(http://acces.ens-lyon.fr/biotic/rastop/help/colour.htm)
`,
RunE: func(cmd *cobra.Command, args []string) (err error) {
var l draw.AlignLayout
var aligns *align.AlignChannel
var f *os.File

if aligns, err = readalign(infile); err != nil {
io.LogError(err)
return
}

nalign := 0
for al := range aligns.Achan {
fname := drawOutput
// Add an index to file output name
// if there are several alignments to draw
if nalign > 0 {
ext := filepath.Ext(fname)
fname = fmt.Sprintf("%s_%d.%s", fname[0:len(fname)-len(ext)], nalign, ext)
}
if f, err = openWriteFile(fname); err != nil {
io.LogError(err)
return
}
al.CleanNames(nil)
w := bufio.NewWriter(f)
l = draw.NewPngLayout(w)
l.DrawAlign(al)
w.Flush()
f.Close()
nalign++
}

if aligns.Err != nil {
err = aligns.Err
io.LogError(err)
}
return
},
}

func init() {
drawCmd.AddCommand(pngCmd)
}
23 changes: 22 additions & 1 deletion docs/commands/draw.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Commands

### draw
This command draws alignments with basic functionalities. So far, output format is html, using [BioJS](http://msa.biojs.net/) library.
This command draws alignments with basic functionalities. So far, output format is html, using [BioJS](http://msa.biojs.net/) library, and PNG displaying one sequence per line and one pixel per character.

If the input file contains several alignments, it will write several output files.

Expand All @@ -15,6 +15,7 @@ Usage:

Available Commands:
biojs Draw alignments in html file using msaviewer from biojs
png Draw alignments in a png file

Flags:
-o, --output string Alignment draw output file (default "stdout")
Expand Down Expand Up @@ -42,6 +43,19 @@ Global Flags:
-p, --phylip Alignment is in phylip? default fasta
```

* png subcommand
```
Usage:
goalign draw png [flags]

Global Flags:
-i, --align string Alignment input file (default "stdin")
--auto-detect Auto detects input format (overrides -p and -x)
--input-strict Strict phylip input format (only used with -p)
-x, --nexus Alignment is in nexus? default fasta
-o, --output string Alignment draw output file (default "stdout")
-p, --phylip Alignment is in phylip? default fasta
```
#### Examples

* Generating a random alignment and displaying it in html
Expand All @@ -50,3 +64,10 @@ goalign random -l 10 --seed 10 | goalign draw biojs -o al.html
```
Should give the following alignment:
![HTML Display](draw.png)

* Generating a random nucleotide alignment and displaying it in png
```
goalign random -l 10 --seed 10 | goalign draw png -o al.png
```
Should give the following image:
![HTML Display](drawPng.png)
Binary file added docs/commands/drawPng.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ Command | Subcommand |
[divide](commands/divide.md) ([api](api/divide.md)) | | Divide an input alignment in several output files
[draw](commands/draw.md) ([api](api/draw.md)) | | Draws an input alignment
-- | biojs | Displays an input alignment in an html file using biojs
-- | png | Displays an input alignment in a png file
[identical](commands/identical.md) ([api](api/identical.md))| | Tells whether two alignments are identical
[mask](commands/mask.md) ([api](api/mask.md)) | | Mask (with N or X) positions of input alignment
[mutate](commands/mutate.md) ([api](api/mutate.md)) | | Adds substitutions (~sequencing errors), or gaps, uniformly in an input alignment
Expand Down
66 changes: 66 additions & 0 deletions draw/png.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package draw

import (
"bufio"
"image"
"image/color"
"image/png"

"github.com/evolbioinfo/goalign/align"
)

// Colors from bioSyntax (doi.org/10.1186/s12859-018-2315-y)
var nucleotideColors = map[rune]color.RGBA{
'A': {71, 255, 25, 255}, 'C': {255, 70, 65, 255}, 'G': {240, 144, 0, 255}, 'T': {65, 146, 255, 255},
'R': {255, 254, 128, 255}, 'Y': {225, 128, 255, 255}, 'S': {255, 155, 128, 255}, 'W': {128, 255, 242, 255},
'K': {144, 184, 44, 255}, 'M': {206, 136, 52, 255}, 'B': {248, 193, 192, 255}, 'D': {199, 255, 185, 255},
'H': {191, 216, 249, 255}, 'V': {255, 227, 185, 255}, 'N': {230, 230, 230, 255}, '-': {255, 255, 255, 255},
'X': {230, 230, 230, 255}, '.': {255, 255, 255, 255},
}

// Colors adapted from "Shapely" color scheme http://acces.ens-lyon.fr/biotic/rastop/help/colour.htm
var aminoAcidColors = map[rune]color.RGBA{
'A': {140, 255, 140, 255}, 'G': {255, 255, 255, 255}, 'L': {69, 94, 69, 255}, 'S': {255, 112, 66, 255},
'V': {255, 140, 255, 255}, 'T': {184, 76, 0, 255}, 'K': {71, 71, 184, 255}, 'D': {160, 0, 66, 255},
'I': {0, 76, 0, 255}, 'N': {255, 124, 112, 255}, 'E': {102, 0, 0, 255}, 'P': {82, 82, 82, 255},
'R': {0, 0, 124, 255}, 'F': {83, 76, 66, 255}, 'Q': {255, 76, 76, 255}, 'Y': {140, 112, 76, 255},
'H': {112, 112, 255, 255}, 'C': {255, 255, 112, 255}, 'M': {184, 160, 66, 255}, 'W': {79, 70, 0, 255},
'B': {255, 0, 255, 255}, 'Z': {255, 0, 255, 255}, 'X': {184, 184, 184, 255}, '-': {0, 0, 0, 255},
'.': {0, 0, 0, 255},
}

type pngLayout struct {
writer *bufio.Writer
}

func NewPngLayout(writer *bufio.Writer) AlignLayout {
return &pngLayout{writer}
}

func (layout *pngLayout) DrawAlign(a align.Alignment) (err error) {

colors := nucleotideColors
if a.Alphabet() == align.AMINOACIDS {
colors = aminoAcidColors
}

height := a.NbSequences()
width := a.Length()

img := image.NewRGBA(image.Rect(0, 0, width, height))

for j, seq := range a.Sequences() {
for i, char := range seq.Sequence() {
c, ok := colors[char]
if !ok {
// Set unkown character to black
c = color.RGBA{0, 0, 0, 0}
}
img.Set(i, j, c)
}
}

png.Encode(layout.writer, img)

return nil
}