Skip to content

Adds date / time data type#527

Open
bioinfbloke wants to merge 3 commits into
mainfrom
feature/handle-date-time
Open

Adds date / time data type#527
bioinfbloke wants to merge 3 commits into
mainfrom
feature/handle-date-time

Conversation

@bioinfbloke

@bioinfbloke bioinfbloke commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Adds real date-column support end to end. Datetimes ingested from pandas/polars are stored as numeric days since the Unix epoch, tagged with is_date, and shown as YYYY-MM-DD in tables, tooltips, axes, color legends, Selection Dialog filters, and Find/Replace — while charts and filters keep using the underlying day numbers so sorting and brushing stay chronological.

Summary by CodeRabbit

  • New Features

    • Added support for date columns across data ingestion and visualization.
    • Dates display as YYYY-MM-DD in tables, charts, axes, legends, filters, histograms, and value replacement.
    • Added chronological sorting and date-aware filtering for date columns.
    • Added support for date columns from pandas and polars data sources.
  • Documentation

    • Documented date column configuration, storage, formatting, sorting, and filtering behavior.
  • Bug Fixes

    • Improved CSS asset mapping for additional stylesheet names.

Stephen Taylor and others added 3 commits July 16, 2026 16:26
project_bootstrap / desktop_index import ./all_css, which Rolldown emits as all_css.css; keep Flask asset naming consistent with mdv.css.

Co-authored-by: Cursor <cursoragent@cursor.com>
@netlify

netlify Bot commented Jul 17, 2026

Copy link
Copy Markdown

Deploy Preview for mdv-dev ready!

Name Link
🔨 Latest commit c55e9eb
🔍 Latest deploy log https://app.netlify.com/projects/mdv-dev/deploys/6a5a1e1f93e58a0008f00029
😎 Deploy Preview https://deploy-preview-527--mdv-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Date-valued columns are ingested as UTC epoch-day doubles with is_date metadata. Shared helpers format, parse, and validate dates across tables, filters, charts, axes, legends, and color scales. Documentation and CSS asset filename mapping are also updated.

Changes

Date column support

Layer / File(s) Summary
Date representation and contracts
src/lib/dateFormat.ts, src/charts/charts.d.ts, src/charts/schemas/DataSourceSchema.ts, docs/...
Defines epoch-day date metadata, parsing/formatting helpers, public types, runtime schema fields, and documentation.
Pandas and Polars ingestion
python/mdvtools/mdvproject.py, python/mdvtools/tests/test_date_columns.py
Detects datetime columns, converts values to day doubles, applies metadata, preserves annotated numeric dates, and tests pandas and Polars ingestion.
Table display and date filtering
src/datastore/DataStore.js, src/react/components/{SelectionDialogComponent,HistogramWidget}.tsx, src/react/utils/valueReplacementUtil.ts, src/tests/...
Formats date values for display and editing, parses ISO inputs, configures date filters and histogram ranges, and validates the behavior.
Chart axes and legends
src/charts/*, src/react/components/AxisComponent.tsx, src/react/components/legend/*, src/react/legend/*, src/utilities/Color.js, src/tests/...
Formats date ticks, adjusts date-axis scaling and sizing, propagates date state through continuous legends, and tests tick and legend formatting.

CSS asset mapping

Layer / File(s) Summary
Stylesheet asset routing
vite.config.mts
Maps all_css.css alongside existing MDV stylesheet names to assets/mdv.css.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Source
  participant MDVProject
  participant DataStore
  participant SelectionDialog
  participant Chart
  Source->>MDVProject: submit datetime columns
  MDVProject->>DataStore: store epoch-day doubles and date metadata
  DataStore->>SelectionDialog: provide date column and numeric range
  SelectionDialog->>DataStore: apply parsed date bounds
  DataStore->>Chart: provide date column values
  Chart->>Chart: render ISO date ticks and labels
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is clearly related to the main change: end-to-end support for date/time columns.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/handle-date-time

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/charts/SVGChart.js (1)

129-131: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use isDateColumn helper to centralize date detection.

All three files manually check is_date || date_unit === "days". To prevent divergence, import and use the shared isDateColumn helper from src/lib/dateFormat.ts.

  • src/charts/SVGChart.js#L129-L131: replace the manual check with if (isDateColumn(col)) { return col; }.
  • src/charts/WGLScatterPlot.js#L274-L275: replace with const xIsDate = isDateColumn(xCol); and const yIsDate = isDateColumn(yCol);.
  • src/utilities/Color.js#L243-L243: replace the ternary condition with isDateColumn(c).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/charts/SVGChart.js` around lines 129 - 131, Replace manual date detection
with the shared isDateColumn helper and import it from src/lib/dateFormat.ts:
update SVGChart.js at lines 129-131 to use isDateColumn(col), WGLScatterPlot.js
at lines 274-275 to derive xIsDate and yIsDate through isDateColumn, and
Color.js at line 243 to use isDateColumn(c) in the ternary condition.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/charts/WGLScatterPlot.js`:
- Around line 505-522: Remove the entire updateAxis() override from
WGLScatterPlot. Rely on the inherited SVGChart.js implementation for date tick
formatting and axis updates, preserving smooth transitions for non-date X and Y
axes.
- Around line 270-289: Extract the date-specific axis logic from the constructor
into a _applyDateAxisDefaults() helper, preserving the existing date detection,
log-scale disabling, and minimum axis sizes. Call this helper from both the
constructor and drawChart(), after the dynamic x/y parameters are assigned, so
Settings-driven column changes apply the defaults before rendering.

---

Nitpick comments:
In `@src/charts/SVGChart.js`:
- Around line 129-131: Replace manual date detection with the shared
isDateColumn helper and import it from src/lib/dateFormat.ts: update SVGChart.js
at lines 129-131 to use isDateColumn(col), WGLScatterPlot.js at lines 274-275 to
derive xIsDate and yIsDate through isDateColumn, and Color.js at line 243 to use
isDateColumn(c) in the ternary condition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: beb45690-7222-42dd-9102-c2eb76a810c3

📥 Commits

Reviewing files that changed from the base of the PR and between bdec64e and c55e9eb.

📒 Files selected for processing (30)
  • docs/TABLE_CHART_REACT.md
  • docs/extradocs/datasource.md
  • docs/jsdocs/extradocs/datasource.md
  • python/mdvtools/mdvproject.py
  • python/mdvtools/tests/test_date_columns.py
  • src/charts/BaseChart.ts
  • src/charts/SVGChart.js
  • src/charts/WGLScatterPlot.js
  • src/charts/charts.d.ts
  • src/charts/schemas/DataSourceSchema.ts
  • src/datastore/DataStore.js
  • src/lib/dateFormat.ts
  • src/react/components/AxisComponent.tsx
  • src/react/components/HistogramWidget.tsx
  • src/react/components/SelectionDialogComponent.tsx
  • src/react/components/legend/ColorLegend.tsx
  • src/react/components/legend/LegendContinuousSvg.tsx
  • src/react/legend/color_legend/buildColorLegendSpec.ts
  • src/react/legend/color_legend/types.ts
  • src/react/legend/shared/legendTypes.ts
  • src/react/legend/shared/legendUtils.ts
  • src/react/utils/valueReplacementUtil.ts
  • src/tests/dateAxisTicks.spec.ts
  • src/tests/dateColumnDisplay.spec.ts
  • src/tests/dateFormat.spec.ts
  • src/tests/histogramBrushRange.spec.ts
  • src/tests/react/legend/legendUtils.test.ts
  • src/tests/table_react/utils/valueReplacementUtils.test.tsx
  • src/utilities/Color.js
  • vite.config.mts

Comment on lines +270 to +289
// Date tick labels are longer than day numbers — give axes a bit more room.
// Log scales are not meaningful for calendar days.
const xCol = this.dataStore.columnIndex[this.x];
const yCol = this.dataStore.columnIndex[this.y];
const xIsDate = xCol?.is_date || xCol?.date_unit === "days";
const yIsDate = yCol?.is_date || yCol?.date_unit === "days";
if (xIsDate && this.config.axis) {
this.config.axis.x_log_scale = false;
if (this.config.axis.x && (!this.config.axis.x.size || this.config.axis.x.size < 40)) {
this.config.axis.x.size = 40;
this.setAxisSize("x", 40);
}
}
if (yIsDate && this.config.axis) {
this.config.axis.y_log_scale = false;
if (this.config.axis.y && (!this.config.axis.y.size || this.config.axis.y.size < 45)) {
this.config.axis.y.size = 45;
this.setAxisSize("y", 45);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Apply date-specific axis adjustments dynamically.

Disabling the log scale and increasing the axis size for date columns is only performed in the constructor. If a user dynamically changes the X or Y parameter to a date column via the Settings dialog, drawChart() is called to rebuild the graph, but it does not execute these adjustments. As a result, the new date column may render with an incompatible log scale and clipped labels.

💡 Proposed fix to apply defaults dynamically

Extract this logic into a helper method and call it in both the constructor and drawChart(). Note: you can also import and use isDateColumn here to simplify the condition.

-        // Date tick labels are longer than day numbers — give axes a bit more room.
-        // Log scales are not meaningful for calendar days.
-        const xCol = this.dataStore.columnIndex[this.x];
-        const yCol = this.dataStore.columnIndex[this.y];
-        const xIsDate = xCol?.is_date || xCol?.date_unit === "days";
-        const yIsDate = yCol?.is_date || yCol?.date_unit === "days";
-        if (xIsDate && this.config.axis) {
-            this.config.axis.x_log_scale = false;
-            if (this.config.axis.x && (!this.config.axis.x.size || this.config.axis.x.size < 40)) {
-                this.config.axis.x.size = 40;
-                this.setAxisSize("x", 40);
-            }
-        }
-        if (yIsDate && this.config.axis) {
-            this.config.axis.y_log_scale = false;
-            if (this.config.axis.y && (!this.config.axis.y.size || this.config.axis.y.size < 45)) {
-                this.config.axis.y.size = 45;
-                this.setAxisSize("y", 45);
-            }
-        }

Add the helper method:

    _applyDateAxisDefaults() {
        if (!this.config.axis) return;
        
        const xCol = this.dataStore.columnIndex[this.x];
        const yCol = this.dataStore.columnIndex[this.y];
        
        if ((xCol?.is_date || xCol?.date_unit === "days")) {
            this.config.axis.x_log_scale = false;
            if (this.config.axis.x && (!this.config.axis.x.size || this.config.axis.x.size < 40)) {
                this.config.axis.x.size = 40;
                this.setAxisSize("x", 40);
            }
        }
        if ((yCol?.is_date || yCol?.date_unit === "days")) {
            this.config.axis.y_log_scale = false;
            if (this.config.axis.y && (!this.config.axis.y.size || this.config.axis.y.size < 45)) {
                this.config.axis.y.size = 45;
                this.setAxisSize("y", 45);
            }
        }
    }

Then call this._applyDateAxisDefaults() inside both the constructor (where the old code was) and inside drawChart() (e.g. immediately after this.y = this.config.param[1];).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/charts/WGLScatterPlot.js` around lines 270 - 289, Extract the
date-specific axis logic from the constructor into a _applyDateAxisDefaults()
helper, preserving the existing date detection, log-scale disabling, and minimum
axis sizes. Call this helper from both the constructor and drawChart(), after
the dynamic x/y parameters are assigned, so Settings-driven column changes apply
the defaults before rendering.

Comment on lines +505 to +522
updateAxis() {
super.updateAxis();
// Classic WGL scatters redraw axes often on pan/zoom; re-assert date tick
// labels so d3 does not fall back to numeric thousands separators.
if (this._isLinearScale(this.x_scale) && this.x_axis_call) {
this._applyDateTickFormat("x", this.x_axis_call);
this.x_axis_svg.call(this.x_axis_call);
}
if (
this._isLinearScale(this.y_scale) &&
this.y_axis_call &&
this._getDateColumnForAxis("y")
) {
this._applyDateTickFormat("y", this.y_axis_call);
this.y_axis_svg.call(this.y_axis_call);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Remove the redundant and buggy updateAxis override.

This override appears to be an artifact intended to fix date labels falling back to thousands separators. However, the date formatting is already correctly and natively re-applied by SVGChart.js in its own updateAxis() on every update.

Furthermore, because the X-axis check misses the _getDateColumnForAxis("x") guard, this override unconditionally calls this.x_axis_svg.call(this.x_axis_call) for all non-date X axes. This unintentionally interrupts and cancels the smooth D3 pan/zoom transition that super.updateAxis() initiates, causing non-date X axes to snap instantly while non-date Y axes transition gracefully.

🗑️ Proposed fix

Since SVGChart.js already perfectly handles the date axis formatting for all subclasses, you can safely delete this entire method to restore correctness and consistent transition behavior.

-    updateAxis() {
-        super.updateAxis();
-        // Classic WGL scatters redraw axes often on pan/zoom; re-assert date tick
-        // labels so d3 does not fall back to numeric thousands separators.
-        if (this._isLinearScale(this.x_scale) && this.x_axis_call) {
-            this._applyDateTickFormat("x", this.x_axis_call);
-            this.x_axis_svg.call(this.x_axis_call);
-        }
-        if (
-            this._isLinearScale(this.y_scale) &&
-            this.y_axis_call &&
-            this._getDateColumnForAxis("y")
-        ) {
-            this._applyDateTickFormat("y", this.y_axis_call);
-            this.y_axis_svg.call(this.y_axis_call);
-        }
-    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
updateAxis() {
super.updateAxis();
// Classic WGL scatters redraw axes often on pan/zoom; re-assert date tick
// labels so d3 does not fall back to numeric thousands separators.
if (this._isLinearScale(this.x_scale) && this.x_axis_call) {
this._applyDateTickFormat("x", this.x_axis_call);
this.x_axis_svg.call(this.x_axis_call);
}
if (
this._isLinearScale(this.y_scale) &&
this.y_axis_call &&
this._getDateColumnForAxis("y")
) {
this._applyDateTickFormat("y", this.y_axis_call);
this.y_axis_svg.call(this.y_axis_call);
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/charts/WGLScatterPlot.js` around lines 505 - 522, Remove the entire
updateAxis() override from WGLScatterPlot. Rely on the inherited SVGChart.js
implementation for date tick formatting and axis updates, preserving smooth
transitions for non-date X and Y axes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants