Skip to content

Commit

Permalink
First panther download function
Browse files Browse the repository at this point in the history
  • Loading branch information
fredericlemoine committed Jan 29, 2020
1 parent 7d4cb69 commit e684546
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 0 deletions.
2 changes: 2 additions & 0 deletions download/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"github.com/evolbioinfo/gotree/tree"
)

// ImageDownloader defines function to download an image
type ImageDownloader interface {
Download(id string, format int) ([]byte, error) // Downdload a tree image from a server
}

// TreeDownloader defines function to download an Tree
type TreeDownloader interface {
Download(id string) (*tree.Tree, error) // Download a tree from a server
}
166 changes: 166 additions & 0 deletions download/panther.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package download

import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"

"github.com/evolbioinfo/gotree/tree"
)

// PantherTreeDownloader allows to download trees from Panther
// using a family ID
type PantherTreeDownloader struct {
server string
path string
}

// NewPantherTreeDownloader initializes a new Panther tree downloader
func NewPantherTreeDownloader() *PantherTreeDownloader {
return &PantherTreeDownloader{
server: "http://pantherdb.org/",
path: "services/oai/pantherdb/treeinfo",
}
}

// Download a tree from Panther
func (p *PantherTreeDownloader) Download(id string) (t *tree.Tree, err error) {
geturl := fmt.Sprintf("%s/%s?family=%s", p.server, p.path, id)
var getresponse *http.Response
var responsebody []byte
var answer *PantherAnswer

if getresponse, err = http.Get(geturl); err != nil {
return
}
defer getresponse.Body.Close()

if responsebody, err = ioutil.ReadAll(getresponse.Body); err != nil {
return
}

if err = json.Unmarshal(responsebody, answer); err != nil {
err = fmt.Errorf("%s (%s)", err.Error(), string(responsebody))
return
}

if answer.Error != "" {
err = errors.New(string(answer.Error))
return
}

if t, err = p.treeFromPantherAnswer(answer); err != nil {
return
}

return
}

// PantherAnswer is the root of Panther JSON answer
type PantherAnswer struct {
Search PantherAnswerSearch `json:"search"`
TreeTopology PantherAnswerTreeTopology `json:"tree_topology"`
Error string `json:"error"`
SearchType string `json:"search_type"`
}

// PantherAnswerSearch defines information on answer search
type PantherAnswerSearch struct {
Product PantherAnswerProduct `json:"product"`
SearchType string `json:"search_type"`
Parameters PantherAnswerParameters `json:"parameters"`
}

// PantherAnswerProduct defines information version and source of the answer
type PantherAnswerProduct struct {
Source string `json:"source"`
Version float64 `json:"version"`
}

// PantherAnswerParameters defines information about family
type PantherAnswerParameters struct {
Family string `json:"family"`
}

// PantherAnswerTreeTopology defines information on node
type PantherAnswerTreeTopology struct {
AnnotationNode PantherAnswerAnnotationNode `json:"annotation_node"`
}

// PantherAnswerAnnotationNode defines information about the node
type PantherAnswerAnnotationNode struct {
SfID string `json:"sf_id"`
PersistentID string `json:"persistent_id"`
BranchLength float64 `json:"branch_length"`
PropSfID string `json:"prop_sf_id"`
EventType string `json:"event_type"`
Species string `json:"species"`
TreeNodeType string `json:"tree_node_type"`
TaxonomicRange string `json:"taxonomic_range"`
SfName string `json:"sf_name"`
GeneSymbol string `json:"gene_symbol"`
NodeName string `json:"node_name"`
Organism string `json:"organism"`
Children PantherAnswerChildren `json:"children"`
}

// PantherAnswerChildren defines the children type
type PantherAnswerChildren struct {
TreeNodeType string `json:"tree_node_type"`
TaxonomicRange string `json:"taxonomic_range"`
SfName string `json:"sf_name"`
AnnotationNode []PantherAnswerAnnotationNode `json:"annotation_node"`
}

func (p *PantherTreeDownloader) treeFromPantherAnswer(answer *PantherAnswer) (t *tree.Tree, err error) {
var nedges, nnodes int = 0, 0

t = tree.NewTree()
err = p.annotationNodeToTree(&answer.TreeTopology.AnnotationNode, t, nil, &nedges, &nnodes)
return
}

func (p *PantherTreeDownloader) annotationNodeToTree(an *PantherAnswerAnnotationNode, t *tree.Tree, parent *tree.Node, nedges, nnodes *int) (err error) {
newNode := t.NewNode()
newNode.SetId(*nnodes)
(*nnodes)++
if parent == nil {
t.SetRoot(newNode)
} else {
e := t.ConnectNodes(parent, newNode)
e.SetId(*nedges)
(*nedges)++
if an.BranchLength != 0 {
e.SetLength(an.BranchLength)
}
}
if an.Species != "" {
newNode.SetName(an.Species)
}

if an.EventType != "" {
newNode.AddComment(an.EventType)
}

if an.Organism != "" {
newNode.AddComment(an.Organism)
}

if an.PersistentID != "" {
newNode.AddComment(an.PersistentID)
}

for _, cl := range an.Children.AnnotationNode {
if err = p.annotationNodeToTree(&cl, t, newNode, nedges, nnodes); err != nil {
return
}
}

if len(an.Children.AnnotationNode) == 0 && an.GeneSymbol == "" {
err = fmt.Errorf("One tip has no gene symbol")
}

return
}

0 comments on commit e684546

Please sign in to comment.