Add some options to obiannotate

This commit is contained in:
2023-02-16 13:32:27 +01:00
parent 6e36b22040
commit 85349668d0
6 changed files with 162 additions and 20 deletions

View File

@ -1,13 +1,16 @@
package obieval
import (
"fmt"
"log"
"git.metabarcoding.org/lecasofts/go/obitools/pkg/goutils"
"github.com/PaesslerAG/gval"
)
func maxIntVector(values []int) float64 {
m := values[0]
for _,v := range values {
for _, v := range values {
if v > m {
m = v
}
@ -16,10 +19,10 @@ func maxIntVector(values []int) float64 {
return float64(m)
}
func maxIntMap(values map[string]int) float64 {
func maxIntMap(values map[string]int) float64 {
var m int
first := true
for _,v := range values {
for _, v := range values {
if first {
first = false
m = v
@ -35,7 +38,7 @@ func maxIntMap(values map[string]int) float64 {
func minIntVector(values []int) float64 {
m := values[0]
for _,v := range values {
for _, v := range values {
if v < m {
m = v
}
@ -44,10 +47,10 @@ func minIntVector(values []int) float64 {
return float64(m)
}
func minIntMap(values map[string]int) float64 {
func minIntMap(values map[string]int) float64 {
var m int
first := true
for _,v := range values {
for _, v := range values {
if first {
first = false
m = v
@ -61,10 +64,9 @@ func minIntMap(values map[string]int) float64 {
return float64(m)
}
func maxFloatVector(values []float64) float64 {
m := values[0]
for _,v := range values {
for _, v := range values {
if v > m {
m = v
}
@ -73,10 +75,10 @@ func maxFloatVector(values []float64) float64 {
return m
}
func maxFloatMap(values map[string]float64) float64 {
func maxFloatMap(values map[string]float64) float64 {
var m float64
first := true
for _,v := range values {
for _, v := range values {
if first {
first = false
m = v
@ -92,7 +94,7 @@ func maxFloatMap(values map[string]float64) float64 {
func minFloatVector(values []float64) float64 {
m := values[0]
for _,v := range values {
for _, v := range values {
if v < m {
m = v
}
@ -101,10 +103,10 @@ func minFloatVector(values []float64) float64 {
return m
}
func minFloatMap(values map[string]float64) float64 {
func minFloatMap(values map[string]float64) float64 {
var m float64
first := true
for _,v := range values {
for _, v := range values {
if first {
first = false
m = v
@ -139,6 +141,34 @@ var OBILang = gval.NewLanguage(
gval.Function("ismap", func(args ...interface{}) (interface{}, error) {
ismap := goutils.IsAMap(args[0])
return ismap, nil
}),
gval.Function("printf", func(args ...interface{}) (interface{}, error) {
text := fmt.Sprintf(args[0].(string), args[1:]...)
return text, nil
}),
gval.Function("int", func(args ...interface{}) (interface{}, error) {
val, err := goutils.InterfaceToInt(args[0])
if err != nil {
log.Fatalf("%v cannot be converted to an integer value", args[0])
}
return val, nil
}),
gval.Function("numeric", func(args ...interface{}) (interface{}, error) {
val, err := goutils.InterfaceToFloat64(args[0])
if err != nil {
log.Fatalf("%v cannot be converted to a numeric value", args[0])
}
return val, nil
}),
gval.Function("bool", func(args ...interface{}) (interface{}, error) {
val, err := goutils.InterfaceToBool(args[0])
if err != nil {
log.Fatalf("%v cannot be converted to a boolan value", args[0])
}
return val, nil
}))
func Expression(expression string) (gval.Evaluable, error) {

View File

@ -1,12 +1,21 @@
package obiiter
import (
"fmt"
"os"
"github.com/schollz/progressbar/v3"
)
func (iterator IBioSequence) Speed(message ...string) IBioSequence {
// If the STDERR is redicted and doesn't end up to a terminal
// No progress bar is printed.
o, _ := os.Stderr.Stat()
if (o.Mode() & os.ModeCharDevice) != os.ModeCharDevice {
return iterator
}
newIter := MakeIBioSequence()
newIter.Add(1)
@ -44,6 +53,7 @@ func (iterator IBioSequence) Speed(message ...string) IBioSequence {
bar.Add(l)
}
fmt.Fprintln(os.Stderr)
newIter.Done()
}()

62
pkg/obiseq/eval.go Normal file
View File

@ -0,0 +1,62 @@
package obiseq
import (
"context"
"fmt"
"git.metabarcoding.org/lecasofts/go/obitools/pkg/obieval"
log "github.com/sirupsen/logrus"
)
func Expression(expression string) func(*BioSequence) (interface{},error) {
exp, err := obieval.OBILang.NewEvaluable(expression)
if err != nil {
log.Fatalf("Error in the expression : %s", expression)
}
f := func(sequence *BioSequence) (interface{},error) {
return exp(context.Background(),
map[string]interface{}{
"annotations": sequence.Annotations(),
"sequence": sequence,
},
)
}
return f
}
func EditIdWorker(expression string) SeqWorker {
e := Expression(expression)
f := func(sequence *BioSequence) *BioSequence {
v,err := e(sequence)
if err != nil {
log.Fatalf("Expression '%s' cannot be evaluated on sequence %s",
expression,
sequence.Id())
}
sequence.SetId(fmt.Sprintf("%v",v))
return sequence
}
return f
}
func EditAttributeWorker(key string, expression string) SeqWorker {
e := Expression(expression)
f := func(sequence *BioSequence) *BioSequence {
v,err := e(sequence)
if err != nil {
log.Fatalf("Expression '%s' cannot be evaluated on sequence %s",
expression,
sequence.Id())
}
sequence.SetAttribute(key,v)
return sequence
}
return f
}

View File

@ -225,3 +225,4 @@ func ExpressionPredicat(expression string) SequencePredicate {
return f
}

View File

@ -5,6 +5,7 @@ import (
"git.metabarcoding.org/lecasofts/go/obitools/pkg/obicorazick"
"git.metabarcoding.org/lecasofts/go/obitools/pkg/obiiter"
"git.metabarcoding.org/lecasofts/go/obitools/pkg/obioptions"
"git.metabarcoding.org/lecasofts/go/obitools/pkg/obiseq"
"git.metabarcoding.org/lecasofts/go/obitools/pkg/obitax"
"git.metabarcoding.org/lecasofts/go/obitools/pkg/obitools/obigrep"
@ -65,6 +66,21 @@ func RenameAttributeWorker(toBeRenamed map[string]string) obiseq.SeqWorker {
return f
}
func EvalAttributeWorker(expression map[string]string) obiseq.SeqWorker {
var w obiseq.SeqWorker
w = nil
for a,e := range expression {
if w == nil {
w = obiseq.EditAttributeWorker(a,e)
} else {
w.ChainWorkers(obiseq.EditAttributeWorker(a,e))
}
}
return w
}
func AddTaxonAtRankWorker(taxonomy *obitax.Taxonomy, ranks ...string) obiseq.SeqWorker {
f := func(s *obiseq.BioSequence) *obiseq.BioSequence {
for _, r := range ranks {
@ -121,6 +137,11 @@ func CLIAnnotationWorker() obiseq.SeqWorker {
annotator = annotator.ChainWorkers(w)
}
if CLIHasSetAttributeExpression() {
w := EvalAttributeWorker(CLISetAttributeExpression())
annotator = annotator.ChainWorkers(w)
}
if CLIHasAhoCorasick() {
patterns := CLIAhoCorazick()
log.Println("Matching : ", len(patterns), " patterns on sequences")
@ -138,7 +159,7 @@ func CLIAnnotationPipeline() obiiter.Pipeable {
worker := CLIAnnotationWorker()
annotator := obiseq.SeqToSliceConditionalWorker(worker, predicate, true)
f := obiiter.SliceWorkerPipe(annotator)
f := obiiter.SliceWorkerPipe(annotator, obioptions.CLIParallelWorkers())
return f
}

View File

@ -16,6 +16,7 @@ var _toBeRenamed = make(map[string]string, 0)
var _toBeDeleted = make([]string, 0)
var _keepOnly = make([]string, 0)
var _taxonAtRank = make([]string, 0)
var _evalAttribute = make(map[string]string, 0)
var _tagList = ""
var _clearAll = false
var _setSeqLength = false
@ -41,6 +42,12 @@ func SequenceAnnotationOptionSet(options *getoptions.GetOpt) {
// options.Description("Forces sequence record ids to be unique."),
// )
options.StringMapVar(&_evalAttribute, "set-tag", 1, 1,
options.Alias("S"),
options.ArgName("KEY=EXPRESSION"),
options.Description("Creates a new attribute named with a key <KEY> "+
"sets with a value computed from <EXPRESSION>."))
options.StringMapVar(&_toBeRenamed, "rename-tag", 1, 1,
options.Alias("R"),
options.ArgName("NEW_NAME=OLD_NAME"),
@ -140,6 +147,17 @@ func CLIHasClearAllFlag() bool {
return _clearAll
}
func CLIHasSetAttributeExpression() bool {
return len(_evalAttribute) > 0
}
func CLISetAttributeExpression() map[string]string {
return _evalAttribute
}
func CLIHasAhoCorasick() bool {
_, err := os.Stat(_ahoCorazick)
return err == nil