Bug description
Summary
Charts backed by datasets with multiple datetime columns can end up with time_range / from_dttm–to_dttm and granularity driven by the wrong column when dashboard native filters apply TEMPORAL_RANGE to a non–x-axis datetime (or when several temporal filters are present).
That yields queries where the visible x-axis does not match the time bounds or grouping actually used.
Root cause (high level)
QueryObjectFactory._process_time_range could fall back to the first TEMPORAL_RANGE clause even when the chart’s BASE_AXIS was a different datetime column, so another column’s bounds could become the main time_range.
QueryContextFactory could let granularity be inferred from dashboard context in a way that rewrote grouping / series away from the x-axis temporal column, and could strip or overwrite temporal filters in ways that dropped legitimate secondary datetime filters.
Intended behavior
- Prefer
TEMPORAL_RANGE on the chart x-axis (BASE_AXIS) when resolving time_range.
- If the x-axis is known but no
TEMPORAL_RANGE targets that axis, do not adopt another column’s TEMPORAL_RANGE as the main chart time range.
- When the x-axis is a temporal column, pin
granularity to that x-axis column so grouping stays aligned with the axis.
- When deduplicating temporal filters for the main axis, preserve
TEMPORAL_RANGE on other datetime columns (secondary time dimensions).
- When propagating
time_range into existing filters, only update the TEMPORAL_RANGE row that matches the active granularity, and compare filter col values whether they are plain strings or adhoc column dicts (sqlExpression / label).
Implementation reference
superset/common/query_object_factory.py(vscode-file://vscode-app/Applications/Cursor.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/superset/common/query_object_factory.py): x-axis–aware _process_time_range, adhoc-safe column matching.
superset/common/query_context_factory.py(vscode-file://vscode-app/Applications/Cursor.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/superset/common/query_context_factory.py): lock granularity to x-axis temporal column, narrow filter removal / time_range application, adhoc-safe column matching.
tests/unit_tests/common/test_query_object_factory.py(vscode-file://vscode-app/Applications/Cursor.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/tests/unit_tests/common/test_query_object_factory.py): unit tests for _process_time_range (no wrong fallback, legacy fallback when no axis, multi-filter preference, adhoc col dict).
Commits
fix: align granularity with x-axis temporal column and preserve secondary dttm filters
test: cover QueryObjectFactory._process_time_range x-axis selection
How to reproduce (click-by-click template)
Fill in the bracketed placeholders for your environment. Remove steps that do not apply (e.g. if you reproduce via API only).
- Dataset: Create or use a virtual / physical dataset with at least two datetime columns, e.g.
[ColumnA_dttm] and [ColumnB_dttm] (replace with real names).
- Chart
- Create a time-series (or mixed) chart that uses
[ColumnA_dttm] as the x-axis / time column (BASE_AXIS).
-Save the chart as [Chart name].
- Dashboard
-Create a dashboard [Dashboard name] and add [Chart name].
- Native filter (critical)
- Add a dashboard native filter of type Time column / Time range (wording depends on Superset version) scoped to
[ColumnB_dttm] (the non–x-axis datetime).
- Set an explicit range, e.g.
[Start] to [End] that is narrower or different from any range you might set on ColumnA.
- Observe
- With no separate native filter on
[ColumnA_dttm], open the chart on the dashboard.
- Note: axis label / grain, data span, and SQL or query payload (if available) for
time_range, granularity, and filters.
- Expected
- Main query time bounds and grouping should follow
[ColumnA_dttm] (the chart x-axis), not [ColumnB_dttm]’s dashboard filter.
Filters on [ColumnB_dttm] should still apply as secondary temporal constraints where applicable, without replacing the x-axis time range.
- Actual (before fix)
- Describe what you see, e.g.:
- Query uses
[ColumnB_dttm] range for from_dttm / to_dttm, or
granularity / GROUP BY does not match [ColumnA_dttm] on the x-axis, or
- Secondary temporal filter incorrectly removed.
- Environment (fill in)
- Superset version:
[e.g. 4.x.x]
- Chart plugin / viz type:
[e.g. ECharts Timeseries]
- Database engine:
[e.g. Postgres / BigQuery / …]
- Feature flags (if any):
[list]
- Browser:
[e.g. Chrome 123]
Verification checklist (for reviewers)
Screenshots/recordings
No response
Superset version
master / latest-dev
Python version
3.11
Node version
18 or greater
Browser
Chrome
Additional context
No response
Checklist
Bug description
Summary
Charts backed by datasets with multiple datetime columns can end up with
time_range/from_dttm–to_dttmandgranularitydriven by the wrong column when dashboard native filters applyTEMPORAL_RANGEto a non–x-axis datetime (or when several temporal filters are present).That yields queries where the visible x-axis does not match the time bounds or grouping actually used.
Root cause (high level)
QueryObjectFactory._process_time_rangecould fall back to the firstTEMPORAL_RANGEclause even when the chart’s BASE_AXIS was a different datetime column, so another column’s bounds could become the maintime_range.QueryContextFactorycould letgranularitybe inferred from dashboard context in a way that rewrote grouping / series away from the x-axis temporal column, and could strip or overwrite temporal filters in ways that dropped legitimate secondary datetime filters.Intended behavior
TEMPORAL_RANGEon the chart x-axis (BASE_AXIS) when resolvingtime_range.TEMPORAL_RANGEtargets that axis, do not adopt another column’sTEMPORAL_RANGEas the main chart time range.granularityto that x-axis column so grouping stays aligned with the axis.TEMPORAL_RANGEon other datetime columns (secondary time dimensions).time_rangeinto existing filters, only update theTEMPORAL_RANGErow that matches the active granularity, and compare filtercolvalues whether they are plain strings or adhoc column dicts (sqlExpression/label).Implementation reference
superset/common/query_object_factory.py(vscode-file://vscode-app/Applications/Cursor.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/superset/common/query_object_factory.py): x-axis–aware_process_time_range, adhoc-safe column matching.superset/common/query_context_factory.py(vscode-file://vscode-app/Applications/Cursor.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/superset/common/query_context_factory.py): lock granularity to x-axis temporal column, narrow filter removal /time_rangeapplication, adhoc-safe column matching.tests/unit_tests/common/test_query_object_factory.py(vscode-file://vscode-app/Applications/Cursor.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/tests/unit_tests/common/test_query_object_factory.py): unit tests for_process_time_range(no wrong fallback, legacy fallback when no axis, multi-filter preference, adhoccoldict).Commits
fix: align granularity with x-axis temporal column and preserve secondary dttm filterstest: cover QueryObjectFactory._process_time_range x-axis selectionHow to reproduce (click-by-click template)
[ColumnA_dttm]and[ColumnB_dttm](replace with real names).[ColumnA_dttm]as the x-axis / time column (BASE_AXIS).-Save the chart as
[Chart name].-Create a dashboard
[Dashboard name]and add[Chart name].[ColumnB_dttm](the non–x-axis datetime).[Start]to[End]that is narrower or different from any range you might set onColumnA.[ColumnA_dttm], open the chart on the dashboard.time_range,granularity,andfilters.[ColumnA_dttm](the chart x-axis), not[ColumnB_dttm]’s dashboard filter.Filters on
[ColumnB_dttm]should still apply as secondary temporal constraints where applicable, without replacing the x-axis time range.[ColumnB_dttm]range forfrom_dttm/to_dttm, orgranularity/ GROUP BY does not match[ColumnA_dttm]on the x-axis, or[e.g. 4.x.x][e.g. ECharts Timeseries][e.g. Postgres / BigQuery / …][list][e.g. Chrome 123]Verification checklist (for reviewers)
Screenshots/recordings
No response
Superset version
master / latest-dev
Python version
3.11
Node version
18 or greater
Browser
Chrome
Additional context
No response
Checklist