Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions addons/tau-plot/plot/plot.gd
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ const PaneOverlayType = preload("res://addons/tau-plot/plot/xy/pane_overlay_type
const VisualAttributes = preload("res://addons/tau-plot/plot/xy/visual_attributes.gd").VisualAttributes
const BarVisualAttributes := preload("res://addons/tau-plot/plot/xy/bar/bar_visual_attributes.gd").BarVisualAttributes
const ScatterVisualAttributes = preload("res://addons/tau-plot/plot/xy/scatter/scatter_visual_attributes.gd").ScatterVisualAttributes
const LineVisualAttributes = preload("res://addons/tau-plot/plot/xy/line/line_visual_attributes.gd").LineVisualAttributes

const VisualCallbacks = preload("res://addons/tau-plot/plot/xy/visual_callbacks.gd").VisualCallbacks
const BarVisualCallbacks := preload("res://addons/tau-plot/plot/xy/bar/bar_visual_callbacks.gd").BarVisualCallbacks
const ScatterVisualCallbacks = preload("res://addons/tau-plot/plot/xy/scatter/scatter_visual_callbacks.gd").ScatterVisualCallbacks
const LineVisualCallbacks = preload("res://addons/tau-plot/plot/xy/line/line_visual_callbacks.gd").LineVisualCallbacks

const SampleHit = preload("res://addons/tau-plot/plot/xy/hover/sample_hit.gd").SampleHit

Expand Down
25 changes: 21 additions & 4 deletions addons/tau-plot/plot/xy/bar/bar_config.gd
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ enum BarMode
const StackedNormalization = preload("res://addons/tau-plot/plot/xy/stacked_normalization.gd").StackedNormalization
@export var stacked_normalization: StackedNormalization = StackedNormalization.NONE

const StackedNegativePolicy = preload("res://addons/tau-plot/plot/xy/stacked_negative_policy.gd").StackedNegativePolicy

## How negative values are handled in STACKED mode:
## - SKIP_NEGATIVES (default) drops negative samples entirely from the stack.
## - DIVERGING splits each X into an upper stack of positive values and
## a lower stack of negative values, both anchored at zero.
## - SIGNED_SUM is not a valid choice for bars: bar geometry cannot represent a
## downward dip without overlapping rectangles. Setting it produces a validation
## error.
@export var stacked_negative_policy: StackedNegativePolicy = StackedNegativePolicy.SKIP_NEGATIVES


enum BarWidthPolicy
{
Expand Down Expand Up @@ -150,6 +161,8 @@ func is_equal_to(p_other: TauPaneOverlayConfig) -> bool:
return false
if stacked_normalization != other.stacked_normalization:
return false
if stacked_negative_policy != other.stacked_negative_policy:
return false

if bar_width_policy != other.bar_width_policy:
return false
Expand Down Expand Up @@ -180,10 +193,11 @@ func is_equal_to(p_other: TauPaneOverlayConfig) -> bool:
# Returns true if the change between this and p_other affects layout/domain.
# Returns false if the change only affects visual appearance.
#
# Only mode and stacked_normalization affect the domain (stacking changes Y
# bounds via _apply_bar_domain_overrides_y). All width, gap, and spacing
# properties are visual-only: they control how bars are drawn within a fixed
# domain but do not feed into domain or tick computation.
# mode, stacked_normalization, and stacked_negative_policy affect the domain:
# stacking changes Y bounds, normalization pins the range, and the negative
# policy decides whether the lower half-axis exists. All width, gap, and
# spacing properties are visual-only: they control how bars are drawn within
# a fixed domain but do not feed into domain or tick computation.
func has_layout_affecting_change(p_other: TauPaneOverlayConfig) -> bool:
var other := p_other as TauBarConfig
if other == null:
Expand All @@ -198,4 +212,7 @@ func has_layout_affecting_change(p_other: TauPaneOverlayConfig) -> bool:
if mode == BarMode.STACKED and stacked_normalization != other.stacked_normalization:
return true

if mode == BarMode.STACKED and stacked_negative_policy != other.stacked_negative_policy:
return true

return false
11 changes: 8 additions & 3 deletions addons/tau-plot/plot/xy/bar/bar_hit_record.gd
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ class BarHitRecord extends RefCounted:
## Float for continuous x, String for categorical.
var x_value: Variant

## Plotted y value. For STACKED with normalization, this is the scaled
## value matching the y-axis labels, not the raw dataset value.
var y_value: float
## Y position the bar's top is drawn at, in axis units.
## Differs from y_raw_value when STACKED is on (cumulative top) or when
## FRACTION/PERCENT normalization is on.
var y_plotted_value: float

## Original dataset value, before any stacking, normalization, or
## accumulation. Equal to y_plotted_value when STACKED is off.
var y_raw_value: float

## Painted rectangle, clipped to the pane.
var rect: Rect2
Expand Down
9 changes: 4 additions & 5 deletions addons/tau-plot/plot/xy/bar/bar_hit_tester.gd
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class BarHitTester extends OverlayHitTester:
return _bar_config.hoverable


func get_preferred_hover_mode() -> int:
func get_preferred_hover_mode() -> HoverMode:
return HoverMode.X_ALIGNED


Expand Down Expand Up @@ -80,14 +80,12 @@ class BarHitTester extends OverlayHitTester:
if _layout.domain.config.x_axis.type == TauAxisConfig.Type.CATEGORICAL:
return {}

# TODO: drop x_is_horizontal once XYLayout exposes a logical-x projector.
var x_is_horizontal: bool = _layout._x_is_horizontal
var best_px := INF
var best_val: float = 0.0
var found := false

for record: BarHitRecord in _bar_renderer.get_hit_records():
var anchor_along_x: float = record.anchor.x if x_is_horizontal else record.anchor.y
var anchor_along_x: float = _layout.map_screen_to_point(record.anchor).x
if absf(p_along_x_px - anchor_along_x) < absf(p_along_x_px - best_px):
best_px = anchor_along_x
best_val = record.x_value
Expand All @@ -108,7 +106,8 @@ class BarHitTester extends OverlayHitTester:
hit.series_name = _dataset.get_series_name(p_record.series_id)
hit.sample_index = p_record.sample_index
hit.x_value = p_record.x_value
hit.y_value = p_record.y_value
hit.y_plotted_value = p_record.y_plotted_value
hit.y_raw_value = p_record.y_raw_value
hit.screen_position = p_record.anchor
hit.pane_index = _pane_index
hit.overlay_type = PaneOverlayType.BAR
Expand Down
Loading