Add progress bar configuration and conditional display

This commit introduces a new configuration module `obidefault` to manage progress bar settings, allowing users to disable progress bars via a `--no-progressbar` option. It updates various packages to conditionally display progress bars based on this new configuration, improving user experience by providing control over progress bar output. The changes also include improvements to progress bar handling in several packages, ensuring they are only displayed when appropriate (e.g., when stderr is a terminal and stdout is not piped).
This commit is contained in:
Eric Coissac
2026-02-08 16:13:27 +01:00
parent b2d16721f0
commit 1a28d5ed64
11 changed files with 193 additions and 125 deletions

View File

@@ -27,22 +27,26 @@ func AhoCorazickWorker(slot string, patterns []string) obiseq.SeqWorker {
npar := min(obidefault.ParallelWorkers(), nmatcher) npar := min(obidefault.ParallelWorkers(), nmatcher)
mutex.Add(npar) mutex.Add(npar)
pbopt := make([]progressbar.Option, 0, 5) var bar *progressbar.ProgressBar
pbopt = append(pbopt, if obidefault.ProgressBar() {
progressbar.OptionSetWriter(os.Stderr), pbopt := make([]progressbar.Option, 0, 5)
progressbar.OptionSetWidth(15), pbopt = append(pbopt,
progressbar.OptionShowCount(), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowIts(), progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("Building AhoCorasick matcher..."), progressbar.OptionShowCount(),
) progressbar.OptionShowIts(),
progressbar.OptionSetDescription("Building AhoCorasick matcher..."),
)
bar := progressbar.NewOptions(nmatcher, pbopt...) bar = progressbar.NewOptions(nmatcher, pbopt...)
bar.Add(0) }
builder := func() { builder := func() {
for i := range ieme { for i := range ieme {
matchers[i] = ahocorasick.CompileStrings(patterns[i*sizebatch:min((i+1)*sizebatch,len(patterns))]) matchers[i] = ahocorasick.CompileStrings(patterns[i*sizebatch:min((i+1)*sizebatch,len(patterns))])
bar.Add(1) if bar != nil {
bar.Add(1)
}
} }
mutex.Done() mutex.Done()
} }

View File

@@ -0,0 +1,19 @@
package obidefault
var __no_progress_bar__ = false
func ProgressBar() bool {
return !__no_progress_bar__
}
func NoProgressBar() bool {
return __no_progress_bar__
}
func SetNoProgressBar(b bool) {
__no_progress_bar__ = b
}
func NoProgressBarPtr() *bool {
return &__no_progress_bar__
}

View File

@@ -5,18 +5,30 @@ import (
"os" "os"
"time" "time"
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obidefault"
"github.com/schollz/progressbar/v3" "github.com/schollz/progressbar/v3"
) )
func (iterator IBioSequence) Speed(message string, size ...int) IBioSequence { func (iterator IBioSequence) Speed(message string, size ...int) IBioSequence {
// If the STDERR is redicted and doesn't end up to a terminal // If the progress bar is disabled via --no-progressbar option
if !obidefault.ProgressBar() {
return iterator
}
// If the STDERR is redirected and doesn't end up to a terminal
// No progress bar is printed. // No progress bar is printed.
o, _ := os.Stderr.Stat() o, _ := os.Stderr.Stat()
if (o.Mode() & os.ModeCharDevice) != os.ModeCharDevice { if (o.Mode() & os.ModeCharDevice) != os.ModeCharDevice {
return iterator return iterator
} }
// If stdout is piped, no progress bar is printed.
oo, _ := os.Stdout.Stat()
if (oo.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe {
return iterator
}
newIter := MakeIBioSequence() newIter := MakeIBioSequence()
newIter.Add(1) newIter.Add(1)

View File

@@ -5,6 +5,7 @@ import (
"sort" "sort"
"unsafe" "unsafe"
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obidefault"
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obifp" "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obifp"
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obilog" "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obilog"
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiseq" "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiseq"
@@ -267,20 +268,23 @@ func NewKmerMap[T obifp.FPUint[T]](
} }
n := len(sequences) n := len(sequences)
pbopt := make([]progressbar.Option, 0, 5) var bar *progressbar.ProgressBar
pbopt = append(pbopt, if obidefault.ProgressBar() {
progressbar.OptionSetWriter(os.Stderr), pbopt := make([]progressbar.Option, 0, 5)
progressbar.OptionSetWidth(15), pbopt = append(pbopt,
progressbar.OptionShowCount(), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowIts(), progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("Indexing kmers"), progressbar.OptionShowCount(),
) progressbar.OptionShowIts(),
progressbar.OptionSetDescription("Indexing kmers"),
)
bar := progressbar.NewOptions(n, pbopt...) bar = progressbar.NewOptions(n, pbopt...)
}
for i, sequence := range sequences { for i, sequence := range sequences {
kmap.Push(sequence, maxoccurs) kmap.Push(sequence, maxoccurs)
if i%100 == 0 { if bar != nil && i%100 == 0 {
bar.Add(100) bar.Add(100)
} }
} }

View File

@@ -13,6 +13,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obialign" "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obialign"
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obidefault"
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiutils" "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiutils"
"github.com/schollz/progressbar/v3" "github.com/schollz/progressbar/v3"
) )
@@ -69,16 +70,18 @@ func EmpiricalDistCsv(filename string, data [][]Ratio, compressed bool) {
} }
defer destfile.Close() defer destfile.Close()
pbopt := make([]progressbar.Option, 0, 5) var bar *progressbar.ProgressBar
pbopt = append(pbopt, if obidefault.ProgressBar() {
progressbar.OptionSetWriter(os.Stderr), pbopt := make([]progressbar.Option, 0, 5)
progressbar.OptionSetWidth(15), pbopt = append(pbopt,
progressbar.OptionShowIts(), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionSetPredictTime(true), progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("[Save CSV stat ratio file]"), progressbar.OptionShowIts(),
) progressbar.OptionSetPredictTime(true),
progressbar.OptionSetDescription("[Save CSV stat ratio file]"),
bar := progressbar.NewOptions(len(data), pbopt...) )
bar = progressbar.NewOptions(len(data), pbopt...)
}
fmt.Fprintln(destfile, "Sample,Origin_id,Origin_status,Origin,Mutant,Origin_Weight,Mutant_Weight,Origin_Count,Mutant_Count,Position,Origin_length,A,C,G,T") fmt.Fprintln(destfile, "Sample,Origin_id,Origin_status,Origin,Mutant,Origin_Weight,Mutant_Weight,Origin_Count,Mutant_Count,Position,Origin_length,A,C,G,T")
for code, dist := range data { for code, dist := range data {
@@ -101,7 +104,9 @@ func EmpiricalDistCsv(filename string, data [][]Ratio, compressed bool) {
ratio.T, ratio.T,
) )
} }
bar.Add(1) if bar != nil {
bar.Add(1)
}
} }
} }
@@ -181,16 +186,18 @@ func SaveGMLGraphs(dirname string,
} }
} }
pbopt := make([]progressbar.Option, 0, 5) var bar *progressbar.ProgressBar
pbopt = append(pbopt, if obidefault.ProgressBar() {
progressbar.OptionSetWriter(os.Stderr), pbopt := make([]progressbar.Option, 0, 5)
progressbar.OptionSetWidth(15), pbopt = append(pbopt,
progressbar.OptionShowIts(), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionSetPredictTime(true), progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("[Save GML Graph files]"), progressbar.OptionShowIts(),
) progressbar.OptionSetPredictTime(true),
progressbar.OptionSetDescription("[Save GML Graph files]"),
bar := progressbar.NewOptions(len(samples), pbopt...) )
bar = progressbar.NewOptions(len(samples), pbopt...)
}
for name, seqs := range samples { for name, seqs := range samples {
@@ -204,7 +211,9 @@ func SaveGMLGraphs(dirname string,
file.WriteString(Gml(seqs, name, statThreshold)) file.WriteString(Gml(seqs, name, statThreshold))
file.Close() file.Close()
bar.Add(1) if bar != nil {
bar.Add(1)
}
} }
} }
@@ -495,37 +504,44 @@ func BuildSeqGraph(samples map[string]*[]*seqPCR,
npairs += nseq * (nseq - 1) / 2 npairs += nseq * (nseq - 1) / 2
} }
pbopt := make([]progressbar.Option, 0, 5) var bar *progressbar.ProgressBar
pbopt = append(pbopt, if obidefault.ProgressBar() {
progressbar.OptionSetWriter(os.Stderr), pbopt := make([]progressbar.Option, 0, 5)
progressbar.OptionSetWidth(15),
progressbar.OptionShowIts(),
progressbar.OptionSetPredictTime(true),
progressbar.OptionSetDescription("[One error graph]"),
)
bar := progressbar.NewOptions(npairs, pbopt...)
for _, seqs := range samples {
np := buildSamplePairs(seqs, workers)
bar.Add(np)
}
if maxError > 1 {
pbopt = make([]progressbar.Option, 0, 5)
pbopt = append(pbopt, pbopt = append(pbopt,
progressbar.OptionSetWriter(os.Stderr), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionSetWidth(15), progressbar.OptionSetWidth(15),
progressbar.OptionShowIts(), progressbar.OptionShowIts(),
progressbar.OptionSetPredictTime(true), progressbar.OptionSetPredictTime(true),
progressbar.OptionSetDescription("[Adds multiple errors]"), progressbar.OptionSetDescription("[One error graph]"),
) )
bar = progressbar.NewOptions(npairs, pbopt...) bar = progressbar.NewOptions(npairs, pbopt...)
}
for _, seqs := range samples { for _, seqs := range samples {
np := extendSimilarityGraph(seqs, maxError, workers) np := buildSamplePairs(seqs, workers)
if bar != nil {
bar.Add(np) bar.Add(np)
} }
} }
if maxError > 1 {
if obidefault.ProgressBar() {
pbopt := make([]progressbar.Option, 0, 5)
pbopt = append(pbopt,
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionSetWidth(15),
progressbar.OptionShowIts(),
progressbar.OptionSetPredictTime(true),
progressbar.OptionSetDescription("[Adds multiple errors]"),
)
bar = progressbar.NewOptions(npairs, pbopt...)
}
for _, seqs := range samples {
np := extendSimilarityGraph(seqs, maxError, workers)
if bar != nil {
bar.Add(np)
}
}
}
} }

View File

@@ -31,7 +31,6 @@ var __output_in_json__ = false
var __output_fastjson_format__ = false var __output_fastjson_format__ = false
var __output_fastobi_format__ = false var __output_fastobi_format__ = false
var __no_progress_bar__ = false
var __skip_empty__ = false var __skip_empty__ = false
var __skip_on_error__ = false var __skip_on_error__ = false
@@ -82,7 +81,7 @@ func InputOptionSet(options *getoptions.GetOpt) {
} }
func OutputModeOptionSet(options *getoptions.GetOpt, compressed bool) { func OutputModeOptionSet(options *getoptions.GetOpt, compressed bool) {
options.BoolVar(&__no_progress_bar__, "no-progressbar", false, options.BoolVar(obidefault.NoProgressBarPtr(), "no-progressbar", obidefault.NoProgressBar(),
options.Description("Disable the progress bar printing")) options.Description("Disable the progress bar printing"))
if compressed { if compressed {
@@ -233,7 +232,7 @@ func CLIProgressBar() bool {
oo, _ := os.Stdout.Stat() oo, _ := os.Stdout.Stat()
toPipe := (oo.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe toPipe := (oo.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe
return onTerminal && !toPipe && !__no_progress_bar__ return onTerminal && !toPipe && obidefault.ProgressBar()
} }
func CLIOutPutFileName() string { func CLIOutPutFileName() string {

View File

@@ -210,9 +210,7 @@ func CLIReadBioSequences(filenames ...string) (obiiter.IBioSequence, error) {
} }
if CLIProgressBar() { iterator = iterator.Speed("Reading sequences")
iterator = iterator.Speed("Reading sequences")
}
return iterator, nil return iterator, nil
} }

View File

@@ -12,9 +12,7 @@ import (
func CLIWriteSequenceCSV(iterator obiiter.IBioSequence, func CLIWriteSequenceCSV(iterator obiiter.IBioSequence,
terminalAction bool, filenames ...string) *obiitercsv.ICSVRecord { terminalAction bool, filenames ...string) *obiitercsv.ICSVRecord {
if obiconvert.CLIProgressBar() { iterator = iterator.Speed("Writing CSV")
iterator = iterator.Speed("Writing CSV")
}
opts := make([]WithOption, 0, 10) opts := make([]WithOption, 0, 10)

View File

@@ -42,16 +42,19 @@ func MapOnLandmarkSequences(library obiseq.BioSequenceSlice, landmark_idx []int,
seqworld := obiutils.Make2DArray[float64](library_size, n_landmark) seqworld := obiutils.Make2DArray[float64](library_size, n_landmark)
pbopt := make([]progressbar.Option, 0, 5) var bar *progressbar.ProgressBar
pbopt = append(pbopt, if obidefault.ProgressBar() {
progressbar.OptionSetWriter(os.Stderr), pbopt := make([]progressbar.Option, 0, 5)
progressbar.OptionSetWidth(15), pbopt = append(pbopt,
progressbar.OptionShowCount(), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowIts(), progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("[Sequence mapping]"), progressbar.OptionShowCount(),
) progressbar.OptionShowIts(),
progressbar.OptionSetDescription("[Sequence mapping]"),
)
bar := progressbar.NewOptions(library_size, pbopt...) bar = progressbar.NewOptions(library_size, pbopt...)
}
waiting := sync.WaitGroup{} waiting := sync.WaitGroup{}
waiting.Add(nworkers) waiting.Add(nworkers)
@@ -66,7 +69,9 @@ func MapOnLandmarkSequences(library obiseq.BioSequenceSlice, landmark_idx []int,
match, lalign := obialign.FastLCSScore(landmark, seq, -1, &buffer) match, lalign := obialign.FastLCSScore(landmark, seq, -1, &buffer)
coord[j] = float64(lalign - match) coord[j] = float64(lalign - match)
} }
bar.Add(1) if bar != nil {
bar.Add(1)
}
} }
waiting.Done() waiting.Done()
} }
@@ -170,23 +175,26 @@ func CLISelectLandmarkSequences(iterator obiiter.IBioSequence) obiiter.IBioSeque
taxa.Set(i, taxon) taxa.Set(i, taxon)
} }
pbopt := make([]progressbar.Option, 0, 5) var bar2 *progressbar.ProgressBar
pbopt = append(pbopt, if obidefault.ProgressBar() {
progressbar.OptionSetWriter(os.Stderr), pbopt := make([]progressbar.Option, 0, 5)
progressbar.OptionSetWidth(15), pbopt = append(pbopt,
progressbar.OptionShowCount(), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowIts(), progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("[Sequence Indexing]"), progressbar.OptionShowCount(),
) progressbar.OptionShowIts(),
progressbar.OptionSetDescription("[Sequence Indexing]"),
)
bar := progressbar.NewOptions(len(library), pbopt...) bar2 = progressbar.NewOptions(len(library), pbopt...)
}
for i, seq := range library { for i, seq := range library {
idx := obirefidx.GeomIndexSesquence(i, library, taxa, taxo) idx := obirefidx.GeomIndexSesquence(i, library, taxa, taxo)
seq.SetOBITagGeomRefIndex(idx) seq.SetOBITagGeomRefIndex(idx)
if i%10 == 0 { if bar2 != nil && i%10 == 0 {
bar.Add(10) bar2.Add(10)
} }
} }
} }

View File

@@ -207,16 +207,19 @@ func IndexFamilyDB(iterator obiiter.IBioSequence) obiiter.IBioSequence {
log.Infof("Done. Found %d clusters", clusters.Len()) log.Infof("Done. Found %d clusters", clusters.Len())
pbopt := make([]progressbar.Option, 0, 5) var bar *progressbar.ProgressBar
pbopt = append(pbopt, if obidefault.ProgressBar() {
progressbar.OptionSetWriter(os.Stderr), pbopt := make([]progressbar.Option, 0, 5)
progressbar.OptionSetWidth(15), pbopt = append(pbopt,
progressbar.OptionShowCount(), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowIts(), progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("Cluster indexing"), progressbar.OptionShowCount(),
) progressbar.OptionShowIts(),
progressbar.OptionSetDescription("Cluster indexing"),
)
bar := progressbar.NewOptions(len(clusters), pbopt...) bar = progressbar.NewOptions(len(clusters), pbopt...)
}
limits := make(chan [2]int) limits := make(chan [2]int)
waiting := sync.WaitGroup{} waiting := sync.WaitGroup{}
@@ -233,7 +236,9 @@ func IndexFamilyDB(iterator obiiter.IBioSequence) obiiter.IBioSequence {
for i := l[0]; i < l[1]; i++ { for i := l[0]; i < l[1]; i++ {
idx := IndexSequence(i, clusters, &kcluster, taxa, taxonomy) idx := IndexSequence(i, clusters, &kcluster, taxa, taxonomy)
clusters[i].SetOBITagRefIndex(idx) clusters[i].SetOBITagRefIndex(idx)
bar.Add(1) if bar != nil {
bar.Add(1)
}
} }
} }

View File

@@ -239,16 +239,19 @@ func IndexReferenceDB(iterator obiiter.IBioSequence) obiiter.IBioSequence {
log.Info("done") log.Info("done")
pbopt := make([]progressbar.Option, 0, 5) var bar *progressbar.ProgressBar
pbopt = append(pbopt, if obidefault.ProgressBar() {
progressbar.OptionSetWriter(os.Stderr), pbopt := make([]progressbar.Option, 0, 5)
progressbar.OptionSetWidth(15), pbopt = append(pbopt,
progressbar.OptionShowCount(), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowIts(), progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("[Sequence Processing]"), progressbar.OptionShowCount(),
) progressbar.OptionShowIts(),
progressbar.OptionSetDescription("[Sequence Processing]"),
)
bar := progressbar.NewOptions(len(references), pbopt...) bar = progressbar.NewOptions(len(references), pbopt...)
}
limits := make(chan [2]int) limits := make(chan [2]int)
indexed := obiiter.MakeIBioSequence() indexed := obiiter.MakeIBioSequence()
@@ -267,7 +270,9 @@ func IndexReferenceDB(iterator obiiter.IBioSequence) obiiter.IBioSequence {
iref := references[i].Copy() iref := references[i].Copy()
iref.SetOBITagRefIndex(idx) iref.SetOBITagRefIndex(idx)
sl = append(sl, iref) sl = append(sl, iref)
bar.Add(1) if bar != nil {
bar.Add(1)
}
} }
indexed.Push(obiiter.MakeBioSequenceBatch(source, l[0]/10, sl)) indexed.Push(obiiter.MakeBioSequenceBatch(source, l[0]/10, sl))
} }