<commit_before>package chart

const (
	// DefaultMovingAverageWindowSize is the default number of values to average.
	DefaultMovingAverageWindowSize = 5
)

// MovingAverageSeries is a computed series.
type MovingAverageSeries struct {
	Name  string
	Style Style
	YAxis YAxisType

	WindowSize  int
	InnerSeries ValueProvider

	valueBuffer *RingBuffer
}

// GetName returns the name of the time series.
func (mas MovingAverageSeries) GetName() string {
	return mas.Name
}

// GetStyle returns the line style.
func (mas MovingAverageSeries) GetStyle() Style {
	return mas.Style
}

// GetYAxis returns which YAxis the series draws on.
func (mas MovingAverageSeries) GetYAxis() YAxisType {
	return mas.YAxis
}

// Len returns the number of elements in the series.
func (mas *MovingAverageSeries) Len() int {
	return mas.InnerSeries.Len()
}

// GetValue gets a value at a given index.
func (mas *MovingAverageSeries) GetValue(index int) (x float64, y float64) {
	if mas.valueBuffer == nil {
		mas.valueBuffer = NewRingBufferWithCapacity(mas.GetWindowSize())
	}
	if mas.valueBuffer.Len() >= mas.GetWindowSize() {
		mas.valueBuffer.Dequeue()
	}
	px, py := mas.InnerSeries.GetValue(index)
	mas.valueBuffer.Enqueue(py)
	x = px
	y = mas.getAverage()
	return
}

// GetWindowSize returns the window size.
func (mas MovingAverageSeries) GetWindowSize(defaults ...int) int {
	if mas.WindowSize == 0 {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return DefaultMovingAverageWindowSize
	}
	return mas.WindowSize
}

func (mas MovingAverageSeries) getAverage() float64 {
	var accum float64
	mas.valueBuffer.Each(func(v interface{}) {
		if typed, isTyped := v.(float64); isTyped {
			accum += typed
		}
	})<commit_msg>adding a `GetLastValue()` function to MovingAverageSeries.<commit_after>package chart

const (
	// DefaultMovingAverageWindowSize is the default number of values to average.
	DefaultMovingAverageWindowSize = 5
)

// MovingAverageSeries is a computed series.
type MovingAverageSeries struct {
	Name  string
	Style Style
	YAxis YAxisType

	WindowSize  int
	InnerSeries ValueProvider

	valueBuffer *RingBuffer
}

// GetName returns the name of the time series.
func (mas MovingAverageSeries) GetName() string {
	return mas.Name
}

// GetStyle returns the line style.
func (mas MovingAverageSeries) GetStyle() Style {
	return mas.Style
}

// GetYAxis returns which YAxis the series draws on.
func (mas MovingAverageSeries) GetYAxis() YAxisType {
	return mas.YAxis
}

// Len returns the number of elements in the series.
func (mas *MovingAverageSeries) Len() int {
	return mas.InnerSeries.Len()
}

// GetValue gets a value at a given index.
func (mas *MovingAverageSeries) GetValue(index int) (x float64, y float64) {
	if mas.InnerSeries == nil {
		return
	}
	if mas.valueBuffer == nil {
		mas.valueBuffer = NewRingBufferWithCapacity(mas.GetWindowSize())
	}
	if mas.valueBuffer.Len() >= mas.GetWindowSize() {
		mas.valueBuffer.Dequeue()
	}
	px, py := mas.InnerSeries.GetValue(index)
	mas.valueBuffer.Enqueue(py)
	x = px
	y = mas.getAverage(mas.valueBuffer)
	return
}

// GetLastValue computes the last moving average value but walking back window size samples,
// and recomputing the last moving average chunk.
func (mas MovingAverageSeries) GetLastValue() (x float64, y float64) {
	if mas.InnerSeries == nil {
		return
	}
	windowSize := mas.GetWindowSize()
	seriesLength := mas.InnerSeries.Len()
	startAt := seriesLength - (windowSize + 1)
	if (seriesLength - startAt) < 0 {
		startAt = 0
	}
	vb := NewRingBufferWithCapacity(windowSize)
	for index := startAt; index < seriesLength; index++ {
		xn, yn := mas.InnerSeries.GetValue(index)
		vb.Enqueue(yn)
		x = xn
	}
	y = mas.getAverage(vb)
	return
}

// GetWindowSize returns the window size.
func (mas MovingAverageSeries) GetWindowSize(defaults ...int) int {
	if mas.WindowSize == 0 {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return DefaultMovingAverageWindowSize
	}
	return mas.WindowSize
}

func (mas MovingAverageSeries) getAverage(valueBuffer *RingBuffer) float64 {
	var accum float64
	valueBuffer.Each(func(v interface{}) {
		if typed, isTyped := v.(float64); isTyped {
			accum += typed
		}
	})
{'fraction_non_alphanumeric': 0.09963985594237695, 'fraction_numerical': 0.008403361344537815, 'mean_word_length': 4.246851385390428, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7024518', 'n_tokens_mistral': 1430, 'n_tokens_neox': 1311, 'n_words': 407}