diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index 4cc2efcd0..f7853d47f 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -1085,40 +1085,6 @@ pub struct CapGrossInvestorLossMvrvNetPeakPriceProfitSellSoprPattern { pub sopr: AdjustedRatioValuePattern, } -/// Pattern struct for repeated tree structure. -pub struct AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern { - pub average: SeriesPattern1, - pub cumulative: SeriesPattern1, - pub max: SeriesPattern1, - pub median: SeriesPattern1, - pub min: SeriesPattern1, - pub pct10: SeriesPattern1, - pub pct25: SeriesPattern1, - pub pct75: SeriesPattern1, - pub pct90: SeriesPattern1, - pub rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern, - pub sum: SeriesPattern1, -} - -impl AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern { - /// Create a new pattern node with accumulated series name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - average: SeriesPattern1::new(client.clone(), _m(&acc, "average")), - cumulative: SeriesPattern1::new(client.clone(), _m(&acc, "cumulative")), - max: SeriesPattern1::new(client.clone(), _m(&acc, "max")), - median: SeriesPattern1::new(client.clone(), _m(&acc, "median")), - min: SeriesPattern1::new(client.clone(), _m(&acc, "min")), - pct10: SeriesPattern1::new(client.clone(), _m(&acc, "pct10")), - pct25: SeriesPattern1::new(client.clone(), _m(&acc, "pct25")), - pct75: SeriesPattern1::new(client.clone(), _m(&acc, "pct75")), - pct90: SeriesPattern1::new(client.clone(), _m(&acc, "pct90")), - rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), acc.clone()), - sum: SeriesPattern1::new(client.clone(), _m(&acc, "sum")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct AverageBaseCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern2 { pub average: _1m1w1y24hPattern, @@ -2498,6 +2464,24 @@ impl CentsSatsUsdPattern { } } +/// Pattern struct for repeated tree structure. +pub struct CumulativeRollingSumPattern { + pub cumulative: SeriesPattern1, + pub rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern, + pub sum: SeriesPattern1, +} + +impl CumulativeRollingSumPattern { + /// Create a new pattern node with accumulated series name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + cumulative: SeriesPattern1::new(client.clone(), _m(&acc, "cumulative")), + rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), acc.clone()), + sum: SeriesPattern1::new(client.clone(), _m(&acc, "sum")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct DeltaHalfTotalPattern { pub delta: AbsoluteRatePattern, @@ -3418,7 +3402,7 @@ impl SeriesTree_Transactions_Volume { pub struct SeriesTree_Inputs { pub raw: SeriesTree_Inputs_Raw, pub spent: SeriesTree_Inputs_Spent, - pub count: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern, + pub count: CumulativeRollingSumPattern, } impl SeriesTree_Inputs { @@ -3426,7 +3410,7 @@ impl SeriesTree_Inputs { Self { raw: SeriesTree_Inputs_Raw::new(client.clone(), format!("{base_path}_raw")), spent: SeriesTree_Inputs_Spent::new(client.clone(), format!("{base_path}_spent")), - count: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern::new(client.clone(), "input_count".to_string()), + count: CumulativeRollingSumPattern::new(client.clone(), "input_count".to_string()), } } } @@ -3520,14 +3504,14 @@ impl SeriesTree_Outputs_Spent { /// Series tree node. pub struct SeriesTree_Outputs_Count { - pub total: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern, + pub total: CumulativeRollingSumPattern, pub unspent: SeriesPattern1, } impl SeriesTree_Outputs_Count { pub fn new(client: Arc, base_path: String) -> Self { Self { - total: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern::new(client.clone(), "output_count".to_string()), + total: CumulativeRollingSumPattern::new(client.clone(), "output_count".to_string()), unspent: SeriesPattern1::new(client.clone(), "utxo_count_bis".to_string()), } } diff --git a/crates/brk_computer/src/distribution/compute/block_loop.rs b/crates/brk_computer/src/distribution/compute/block_loop.rs index 90a70858d..7d63cc70c 100644 --- a/crates/brk_computer/src/distribution/compute/block_loop.rs +++ b/crates/brk_computer/src/distribution/compute/block_loop.rs @@ -67,8 +67,8 @@ pub(crate) fn process_blocks( let height_to_first_txout_index = &indexer.vecs.outputs.first_txout_index; let height_to_first_txin_index = &indexer.vecs.inputs.first_txin_index; let height_to_tx_count = &transactions.count.total.base.height; - let height_to_output_count = &outputs.count.total.full.sum.height; - let height_to_input_count = &inputs.count.full.sum.height; + let height_to_output_count = &outputs.count.total.sum.height; + let height_to_input_count = &inputs.count.sum.height; let tx_index_to_output_count = &indexes.tx_index.output_count; let tx_index_to_input_count = &indexes.tx_index.input_count; diff --git a/crates/brk_computer/src/inputs/count/compute.rs b/crates/brk_computer/src/inputs/count/compute.rs index 94d3db789..dd2349bd3 100644 --- a/crates/brk_computer/src/inputs/count/compute.rs +++ b/crates/brk_computer/src/inputs/count/compute.rs @@ -16,17 +16,15 @@ impl Vecs { exit: &Exit, ) -> Result<()> { let window_starts = blocks.lookback.window_starts(); - self.0 - .compute(starting_indexes.height, &window_starts, exit, |full| { - full.compute_with_skip( - starting_indexes.height, - &indexes.tx_index.input_count, - &indexer.vecs.transactions.first_tx_index, - &indexes.height.tx_index_count, - exit, - 0, - ) - })?; + self.0.compute( + starting_indexes.height, + &indexes.tx_index.input_count, + &indexer.vecs.transactions.first_tx_index, + &indexes.height.tx_index_count, + &window_starts, + exit, + 0, + )?; Ok(()) } diff --git a/crates/brk_computer/src/internal/per_block/computed/aggregated.rs b/crates/brk_computer/src/internal/per_block/computed/aggregated.rs index 5a1c32f56..5ec7ff765 100644 --- a/crates/brk_computer/src/internal/per_block/computed/aggregated.rs +++ b/crates/brk_computer/src/internal/per_block/computed/aggregated.rs @@ -1,17 +1,15 @@ -//! PerBlockAggregated - PerBlockDistributionFull (distribution + sum + cumulative) + RollingComplete. -//! -//! For metrics aggregated per-block from finer-grained sources (e.g., per-tx data), -//! where we want full per-block stats plus rolling window stats. - use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Height, Version}; +use brk_types::Height; use schemars::JsonSchema; -use vecdb::{Database, Exit, Rw, StorageMode}; +use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode, VecIndex, VecValue, Version}; use crate::{ indexes, - internal::{CachedWindowStarts, PerBlockDistributionFull, NumericValue, RollingComplete, WindowStarts}, + internal::{ + CachedWindowStarts, NumericValue, PerBlock, RollingComplete, WindowStarts, + algo::compute_aggregations, + }, }; #[derive(Traversable)] @@ -19,8 +17,8 @@ pub struct PerBlockAggregated where T: NumericValue + JsonSchema, { - #[traversable(flatten)] - pub full: PerBlockDistributionFull, + pub sum: PerBlock, + pub cumulative: PerBlock, pub rolling: RollingComplete, } @@ -35,34 +33,63 @@ where indexes: &indexes::Vecs, cached_starts: &CachedWindowStarts, ) -> Result { - let full = PerBlockDistributionFull::forced_import(db, name, version, indexes)?; + let sum = PerBlock::forced_import(db, &format!("{name}_sum"), version, indexes)?; + let cumulative = + PerBlock::forced_import(db, &format!("{name}_cumulative"), version, indexes)?; let rolling = RollingComplete::forced_import( db, name, version, indexes, - &full.cumulative.height, + &cumulative.height, cached_starts, )?; - Ok(Self { full, rolling }) + Ok(Self { + sum, + cumulative, + rolling, + }) } - /// Compute PerBlockDistributionFull stats via closure, then rolling distribution from the per-block sum. - pub(crate) fn compute( + #[allow(clippy::too_many_arguments)] + pub(crate) fn compute( &mut self, max_from: Height, + source: &impl ReadableVec, + first_indexes: &impl ReadableVec, + count_indexes: &impl ReadableVec, windows: &WindowStarts<'_>, exit: &Exit, - compute_full: impl FnOnce(&mut PerBlockDistributionFull) -> Result<()>, + skip_count: usize, ) -> Result<()> where T: From + Default + Copy + Ord, f64: From, + A: VecIndex + VecValue + brk_types::CheckedSub, { - compute_full(&mut self.full)?; + compute_aggregations( + max_from, + source, + first_indexes, + count_indexes, + exit, + skip_count, + None, + None, + None, + None, + None, + Some(&mut self.sum.height), + Some(&mut self.cumulative.height), + None, + None, + None, + None, + None, + )?; self.rolling - .compute(max_from, windows, &self.full.sum.height, exit)?; + .compute(max_from, windows, &self.sum.height, exit)?; Ok(()) } } diff --git a/crates/brk_computer/src/internal/per_block/computed/distribution_full.rs b/crates/brk_computer/src/internal/per_block/computed/distribution_full.rs deleted file mode 100644 index 0f23151a1..000000000 --- a/crates/brk_computer/src/internal/per_block/computed/distribution_full.rs +++ /dev/null @@ -1,73 +0,0 @@ -use brk_error::Result; -use brk_traversable::Traversable; -use brk_types::Height; -use schemars::JsonSchema; -use vecdb::{ - Database, Exit, ReadableVec, Rw, StorageMode, - VecIndex, VecValue, Version, -}; - -use crate::{ - indexes, - internal::{ComputedVecValue, NumericValue, PerBlock, algo::compute_aggregations}, -}; - -use super::PerBlockDistribution; - -#[derive(Traversable)] -pub struct PerBlockDistributionFull { - pub sum: PerBlock, - pub cumulative: PerBlock, - #[traversable(flatten)] - pub distribution: PerBlockDistribution, -} - -impl PerBlockDistributionFull { - pub(crate) fn forced_import( - db: &Database, - name: &str, - version: Version, - indexes: &indexes::Vecs, - ) -> Result { - Ok(Self { - distribution: PerBlockDistribution::forced_import(db, name, version, indexes)?, - sum: PerBlock::forced_import(db, &format!("{name}_sum"), version, indexes)?, - cumulative: PerBlock::forced_import(db, &format!("{name}_cumulative"), version, indexes)?, - }) - } - - pub(crate) fn compute_with_skip( - &mut self, - max_from: Height, - source: &impl ReadableVec, - first_indexes: &impl ReadableVec, - count_indexes: &impl ReadableVec, - exit: &Exit, - skip_count: usize, - ) -> Result<()> - where - A: VecIndex + VecValue + brk_types::CheckedSub, - { - let d = &mut self.distribution.0; - compute_aggregations( - max_from, - source, - first_indexes, - count_indexes, - exit, - skip_count, - None, - None, - Some(&mut d.min.height), - Some(&mut d.max.height), - Some(&mut d.average.height), - Some(&mut self.sum.height), - Some(&mut self.cumulative.height), - Some(&mut d.median.height), - Some(&mut d.pct10.height), - Some(&mut d.pct25.height), - Some(&mut d.pct75.height), - Some(&mut d.pct90.height), - ) - } -} diff --git a/crates/brk_computer/src/internal/per_block/computed/mod.rs b/crates/brk_computer/src/internal/per_block/computed/mod.rs index a9c486a2b..bfed10b39 100644 --- a/crates/brk_computer/src/internal/per_block/computed/mod.rs +++ b/crates/brk_computer/src/internal/per_block/computed/mod.rs @@ -3,7 +3,6 @@ mod base; mod cumulative; mod cumulative_sum; mod distribution; -mod distribution_full; mod full; mod lazy_distribution; mod lazy_rolling; @@ -17,7 +16,6 @@ pub use base::*; pub use cumulative::*; pub use cumulative_sum::*; pub use distribution::*; -pub use distribution_full::*; pub use full::*; pub use lazy_distribution::*; pub use lazy_rolling::*; diff --git a/crates/brk_computer/src/internal/per_block/rolling/delta.rs b/crates/brk_computer/src/internal/per_block/rolling/delta.rs index f5501aad2..371f9b695 100644 --- a/crates/brk_computer/src/internal/per_block/rolling/delta.rs +++ b/crates/brk_computer/src/internal/per_block/rolling/delta.rs @@ -1,5 +1,6 @@ use brk_traversable::Traversable; use brk_types::{Dollars, Height, StoredF32, Version}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use vecdb::{DeltaChange, DeltaRate, LazyDeltaVec, LazyVecFrom1, ReadableCloneableVec, VecValue}; @@ -7,7 +8,7 @@ use crate::{ indexes, internal::{ BpsType, CachedWindowStarts, CentsType, DerivedResolutions, LazyPerBlock, NumericValue, - Resolutions, Windows, + Percent, Resolutions, Windows, }, }; @@ -31,16 +32,14 @@ where /// Single-slot lazy delta percent: BPS delta + lazy ratio + lazy percent views. /// /// Mirrors `PercentPerBlock` but with lazy delta for the BPS source. -#[derive(Clone, Traversable)] -pub struct LazyDeltaPercentFromHeight +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(transparent)] +pub struct LazyDeltaPercentFromHeight( + pub Percent, LazyPerBlock>, +) where S: VecValue, - B: BpsType, -{ - pub bps: LazyDeltaFromHeight, - pub ratio: LazyPerBlock, - pub percent: LazyPerBlock, -} + B: BpsType; /// Lazy rolling deltas for all 4 window durations (24h, 1w, 1m, 1y). /// @@ -151,11 +150,11 @@ where )), }; - let rate = LazyDeltaPercentFromHeight { + let rate = LazyDeltaPercentFromHeight(Percent { bps, ratio, percent, - }; + }); (absolute, rate) }; @@ -304,11 +303,11 @@ where )), }; - let rate = LazyDeltaPercentFromHeight { + let rate = LazyDeltaPercentFromHeight(Percent { bps, ratio, percent, - }; + }); (absolute, rate) }; diff --git a/crates/brk_computer/src/outputs/count/compute.rs b/crates/brk_computer/src/outputs/count/compute.rs index b782b4cb0..018f1d23b 100644 --- a/crates/brk_computer/src/outputs/count/compute.rs +++ b/crates/brk_computer/src/outputs/count/compute.rs @@ -19,22 +19,20 @@ impl Vecs { exit: &Exit, ) -> Result<()> { let window_starts = blocks.lookback.window_starts(); - self.total - .compute(starting_indexes.height, &window_starts, exit, |full| { - full.compute_with_skip( - starting_indexes.height, - &indexes.tx_index.output_count, - &indexer.vecs.transactions.first_tx_index, - &indexes.height.tx_index_count, - exit, - 0, - ) - })?; + self.total.compute( + starting_indexes.height, + &indexes.tx_index.output_count, + &indexer.vecs.transactions.first_tx_index, + &indexes.height.tx_index_count, + &window_starts, + exit, + 0, + )?; self.unspent.height.compute_transform3( starting_indexes.height, - &self.total.full.cumulative.height, - &inputs_count.full.cumulative.height, + &self.total.cumulative.height, + &inputs_count.cumulative.height, &scripts_count.op_return.cumulative.height, |(h, output_count, input_count, op_return_count, ..)| { let block_count = u64::from(h + 1_usize); diff --git a/crates/brk_computer/src/scripts/adoption.rs b/crates/brk_computer/src/scripts/adoption.rs index b5feecc5d..c2aba4c0b 100644 --- a/crates/brk_computer/src/scripts/adoption.rs +++ b/crates/brk_computer/src/scripts/adoption.rs @@ -39,14 +39,14 @@ impl Vecs { self.taproot.compute_binary::<_, _, RatioU64Bp16>( starting_indexes.height, &count.p2tr.base.height, - &outputs_count.total.full.sum.height, + &outputs_count.total.sum.height, exit, )?; self.segwit.compute_binary::<_, _, RatioU64Bp16>( starting_indexes.height, &count.segwit.base.height, - &outputs_count.total.full.sum.height, + &outputs_count.total.sum.height, exit, )?; diff --git a/crates/brk_computer/src/transactions/volume/compute.rs b/crates/brk_computer/src/transactions/volume/compute.rs index f1bf5d128..278bcdbe1 100644 --- a/crates/brk_computer/src/transactions/volume/compute.rs +++ b/crates/brk_computer/src/transactions/volume/compute.rs @@ -50,7 +50,7 @@ impl Vecs { .height .compute_binary::<_, Timestamp, PerSec>( starting_indexes.height, - &inputs_count.full.sum.height, + &inputs_count.sum.height, &blocks.interval.base, exit, )?; @@ -58,7 +58,7 @@ impl Vecs { .height .compute_binary::<_, Timestamp, PerSec>( starting_indexes.height, - &outputs_count.total.full.sum.height, + &outputs_count.total.sum.height, &blocks.interval.base, exit, )?; diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index 53f8a56b5..ec30e9031 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -1795,43 +1795,6 @@ function create_10y1m1w1y2y3m3y4y5y6m6y8yPattern3(client, acc) { * @property {AdjustedRatioValuePattern} sopr */ -/** - * @typedef {Object} AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern - * @property {SeriesPattern1} average - * @property {SeriesPattern1} cumulative - * @property {SeriesPattern1} max - * @property {SeriesPattern1} median - * @property {SeriesPattern1} min - * @property {SeriesPattern1} pct10 - * @property {SeriesPattern1} pct25 - * @property {SeriesPattern1} pct75 - * @property {SeriesPattern1} pct90 - * @property {AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern} rolling - * @property {SeriesPattern1} sum - */ - -/** - * Create a AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated series name - * @returns {AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern} - */ -function createAverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern(client, acc) { - return { - average: createSeriesPattern1(client, _m(acc, 'average')), - cumulative: createSeriesPattern1(client, _m(acc, 'cumulative')), - max: createSeriesPattern1(client, _m(acc, 'max')), - median: createSeriesPattern1(client, _m(acc, 'median')), - min: createSeriesPattern1(client, _m(acc, 'min')), - pct10: createSeriesPattern1(client, _m(acc, 'pct10')), - pct25: createSeriesPattern1(client, _m(acc, 'pct25')), - pct75: createSeriesPattern1(client, _m(acc, 'pct75')), - pct90: createSeriesPattern1(client, _m(acc, 'pct90')), - rolling: createAverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern(client, acc), - sum: createSeriesPattern1(client, _m(acc, 'sum')), - }; -} - /** * @typedef {Object} AverageBaseCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern2 * @property {_1m1w1y24hPattern} average @@ -3395,6 +3358,27 @@ function createCentsSatsUsdPattern(client, acc) { }; } +/** + * @typedef {Object} CumulativeRollingSumPattern + * @property {SeriesPattern1} cumulative + * @property {AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern} rolling + * @property {SeriesPattern1} sum + */ + +/** + * Create a CumulativeRollingSumPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated series name + * @returns {CumulativeRollingSumPattern} + */ +function createCumulativeRollingSumPattern(client, acc) { + return { + cumulative: createSeriesPattern1(client, _m(acc, 'cumulative')), + rolling: createAverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern(client, acc), + sum: createSeriesPattern1(client, _m(acc, 'sum')), + }; +} + /** * @typedef {Object} DeltaHalfTotalPattern * @property {AbsoluteRatePattern} delta @@ -4125,7 +4109,7 @@ function createUnspentPattern(client, acc) { * @typedef {Object} SeriesTree_Inputs * @property {SeriesTree_Inputs_Raw} raw * @property {SeriesTree_Inputs_Spent} spent - * @property {AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern} count + * @property {CumulativeRollingSumPattern} count */ /** @@ -4166,7 +4150,7 @@ function createUnspentPattern(client, acc) { /** * @typedef {Object} SeriesTree_Outputs_Count - * @property {AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern} total + * @property {CumulativeRollingSumPattern} total * @property {SeriesPattern1} unspent */ @@ -7645,7 +7629,7 @@ class BrkClient extends BrkClientBase { txoutIndex: createSeriesPattern20(this, 'txout_index'), value: createSeriesPattern20(this, 'value'), }, - count: createAverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern(this, 'input_count'), + count: createCumulativeRollingSumPattern(this, 'input_count'), }, outputs: { raw: { @@ -7659,7 +7643,7 @@ class BrkClient extends BrkClientBase { txinIndex: createSeriesPattern21(this, 'txin_index'), }, count: { - total: createAverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern(this, 'output_count'), + total: createCumulativeRollingSumPattern(this, 'output_count'), unspent: createSeriesPattern1(this, 'utxo_count_bis'), }, }, diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index 652b0cd0b..5654e5c49 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -2221,23 +2221,6 @@ class CapGrossInvestorLossMvrvNetPeakPriceProfitSellSoprPattern: """Pattern struct for repeated tree structure.""" pass -class AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated series name.""" - self.average: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'average')) - self.cumulative: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'cumulative')) - self.max: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'max')) - self.median: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'median')) - self.min: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'min')) - self.pct10: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'pct10')) - self.pct25: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'pct25')) - self.pct75: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'pct75')) - self.pct90: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'pct90')) - self.rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern = AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern(client, acc) - self.sum: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'sum')) - class AverageBaseCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern2: """Pattern struct for repeated tree structure.""" @@ -2916,6 +2899,15 @@ class CentsSatsUsdPattern: self.sats: SeriesPattern1[SatsFract] = SeriesPattern1(client, _m(acc, 'sats')) self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, acc) +class CumulativeRollingSumPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated series name.""" + self.cumulative: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'cumulative')) + self.rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern = AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern(client, acc) + self.sum: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'sum')) + class DeltaHalfTotalPattern: """Pattern struct for repeated tree structure.""" @@ -3369,7 +3361,7 @@ class SeriesTree_Inputs: def __init__(self, client: BrkClientBase, base_path: str = ''): self.raw: SeriesTree_Inputs_Raw = SeriesTree_Inputs_Raw(client) self.spent: SeriesTree_Inputs_Spent = SeriesTree_Inputs_Spent(client) - self.count: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern = AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern(client, 'input_count') + self.count: CumulativeRollingSumPattern = CumulativeRollingSumPattern(client, 'input_count') class SeriesTree_Outputs_Raw: """Series tree node.""" @@ -3391,7 +3383,7 @@ class SeriesTree_Outputs_Count: """Series tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.total: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern = AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern(client, 'output_count') + self.total: CumulativeRollingSumPattern = CumulativeRollingSumPattern(client, 'output_count') self.unspent: SeriesPattern1[StoredU64] = SeriesPattern1(client, 'utxo_count_bis') class SeriesTree_Outputs: diff --git a/website/scripts/options/network.js b/website/scripts/options/network.js index 859201a31..163bfcadf 100644 --- a/website/scripts/options/network.js +++ b/website/scripts/options/network.js @@ -13,11 +13,12 @@ import { chartsFromFullPerBlock, chartsFromCount, chartsFromCountEntries, - chartsFromSumPerBlock, + chartsFromAggregatedPerBlock, rollingWindowsTree, ROLLING_WINDOWS, chartsFromBlockAnd6b, + multiSeriesTree, simpleDeltaTree, percentRatio, percentRatioDots, @@ -737,27 +738,32 @@ export function createNetworkSection() { }), { name: "Flow", - title: "UTXO Flow", - bottom: [ - line({ - series: outputs.count.total.sum, - name: "Created", - color: colors.entity.output, - unit: Unit.count, - }), - line({ - series: inputs.count.sum, - name: "Spent", - color: colors.entity.input, - unit: Unit.count, - }), - ], + tree: multiSeriesTree({ + entries: [ + { + name: "Created", + color: colors.entity.output, + base: outputs.count.total.sum, + rolling: outputs.count.total.rolling.sum, + cumulative: outputs.count.total.cumulative, + }, + { + name: "Spent", + color: colors.entity.input, + base: inputs.count.sum, + rolling: inputs.count.rolling.sum, + cumulative: inputs.count.cumulative, + }, + ], + title: "UTXO Flow", + unit: Unit.count, + }), }, ], }, { name: "Inputs", - tree: chartsFromSumPerBlock({ + tree: chartsFromAggregatedPerBlock({ pattern: inputs.count, title: "Input Count", unit: Unit.count, @@ -765,7 +771,7 @@ export function createNetworkSection() { }, { name: "Outputs", - tree: chartsFromSumPerBlock({ + tree: chartsFromAggregatedPerBlock({ pattern: outputs.count.total, title: "Output Count", unit: Unit.count, diff --git a/website/scripts/options/series.js b/website/scripts/options/series.js index de9b34ffa..0b913812c 100644 --- a/website/scripts/options/series.js +++ b/website/scripts/options/series.js @@ -758,67 +758,6 @@ export function simpleDeltaTree({ delta, title, unit }) { // ============================================================================ // These split patterns into separate Sum/Distribution/Cumulative charts -/** - * Create distribution series (avg + percentiles) - * @param {DistributionStats} pattern - * @param {Unit} unit - * @returns {AnyFetchedSeriesBlueprint[]} - */ -function distributionSeries(pattern, unit) { - const { stat } = colors; - return [ - dots({ series: pattern.average, name: "avg", color: stat.avg, unit }), - dots({ - series: pattern.median, - name: "median", - color: stat.median, - unit, - defaultActive: false, - }), - dots({ - series: pattern.max, - name: "max", - color: stat.max, - unit, - defaultActive: false, - }), - dots({ - series: pattern.min, - name: "min", - color: stat.min, - unit, - defaultActive: false, - }), - dots({ - series: pattern.pct75, - name: "pct75", - color: stat.pct75, - unit, - defaultActive: false, - }), - dots({ - series: pattern.pct25, - name: "pct25", - color: stat.pct25, - unit, - defaultActive: false, - }), - dots({ - series: pattern.pct90, - name: "pct90", - color: stat.pct90, - unit, - defaultActive: false, - }), - dots({ - series: pattern.pct10, - name: "pct10", - color: stat.pct10, - unit, - defaultActive: false, - }), - ]; -} /** * Create btc/sats/usd series from patterns @@ -910,7 +849,7 @@ export const chartsFromFullPerBlock = (args) => * @param {string} [args.distributionSuffix] * @returns {PartialOptionsTree} */ -export function chartsFromSum({ +export function chartsFromAggregated({ pattern, title, unit, @@ -922,17 +861,12 @@ export function chartsFromSum({ : title; return [ { - name: "Sum", + name: "Per Block", title, - bottom: [{ series: pattern.sum, title: "sum", color: stat.sum, unit }], + bottom: [{ series: pattern.sum, title: "base", color: stat.sum, unit }], }, rollingWindowsTree({ windows: pattern.rolling.sum, title, unit }), distributionWindowsTree({ pattern: pattern.rolling, title: distTitle, unit }), - { - name: "Distribution", - title: `${distTitle} Distribution`, - bottom: distributionSeries(pattern, unit), - }, { name: "Cumulative", title: `${title} (Total)`, @@ -949,8 +883,8 @@ export function chartsFromSum({ * @param {Unit} args.unit * @returns {PartialOptionsTree} */ -export const chartsFromSumPerBlock = (args) => - chartsFromSum({ ...args, distributionSuffix: "per Block" }); +export const chartsFromAggregatedPerBlock = (args) => + chartsFromAggregated({ ...args, distributionSuffix: "per Block" }); /** * Create Per Block + Per 6 Blocks stats charts from a _6bBlockTxPattern @@ -1024,12 +958,34 @@ export function chartsFromCount({ pattern, title, unit, color }) { * @returns {PartialOptionsTree} */ export function chartsFromCountEntries({ entries, title, unit }) { + return multiSeriesTree({ + entries: entries.map(([name, data], i, arr) => ({ + name, + color: colors.at(i, arr.length), + base: data.base, + rolling: data.sum, + cumulative: data.cumulative, + })), + title, + unit, + }); +} + +/** + * Per Block + Sums + Cumulative tree for multiple named series shown side-by-side + * @param {Object} args + * @param {Array<{ name: string, color: Color, base: AnySeriesPattern, rolling: { _24h: AnySeriesPattern, _1w: AnySeriesPattern, _1m: AnySeriesPattern, _1y: AnySeriesPattern }, cumulative: AnySeriesPattern }>} args.entries + * @param {string} args.title + * @param {Unit} args.unit + * @returns {PartialOptionsTree} + */ +export function multiSeriesTree({ entries, title, unit }) { return [ { name: "Per Block", title, - bottom: entries.map(([name, data], i, arr) => - line({ series: data.base, name, color: colors.at(i, arr.length), unit }), + bottom: entries.map((e) => + line({ series: e.base, name: e.name, color: e.color, unit }), ), }, { @@ -1037,16 +993,16 @@ export function chartsFromCountEntries({ entries, title, unit }) { tree: ROLLING_WINDOWS.map((w) => ({ name: w.name, title: `${title} (${w.name})`, - bottom: entries.map(([name, data], i, arr) => - line({ series: data.sum[w.key], name, color: colors.at(i, arr.length), unit }), + bottom: entries.map((e) => + line({ series: e.rolling[w.key], name: e.name, color: e.color, unit }), ), })), }, { name: "Cumulative", title: `${title} (Total)`, - bottom: entries.map(([name, data], i, arr) => - line({ series: data.cumulative, name, color: colors.at(i, arr.length), unit }), + bottom: entries.map((e) => + line({ series: e.cumulative, name: e.name, color: e.color, unit }), ), }, ];