agentsclimarketplace

D3 chart table sync

Skill cxcscmu/SkillLearnBench/skills/b4-skill-creator-claude-haiku-4-5/stock-data-visualization/d3-chart-table-sync

Synchronize interactions between D3 visualizations and HTML tables, enabling click-to-highlight and hover effects across both elements. Use this skill when you need chart and table elements to stay in sync - clicking a bubble highlights its table row, clicking a row highlights the bubble, and/or hovering shows related data across both. Essential for exploratory dashboards where users need to see data from multiple perspectives simultaneously.From its SKILL.md

Install
npx -y skills add cxcscmu/SkillLearnBench --skill d3-chart-table-sync

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

SKILL.md

5.0 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it

D3 Chart-Table Synchronization

This skill covers linking D3 visualizations with HTML data tables for synchronized interactions.

Architecture

The key is using a shared data key (usually unique identifier like ticker symbol) to link chart elements and table rows:

// In both chart and table, use consistent key
const KEY = d => d.ticker;

Basic Selection Linking

// When user clicks a bubble
circles.on("click", function(event, d) {
  const key = d.ticker;

  // Highlight bubble
  circles.classed("selected", e => KEY(e) === key);

  // Highlight table row
  tableRows.classed("selected", row => KEY(row) === key);
});

// When user clicks table row
tableRows.on("click", function(event, rowData) {
  const key = rowData.ticker;

  // Highlight table row
  tableRows.classed("selected", row => KEY(row) === key);

  // Highlight bubble
  circles.classed("selected", d => KEY(d) === key);
});

CSS for highlighting:

circle.selected,
tr.selected {
  stroke: #000;
  stroke-width: 2;
}

tr.selected {
  background-color: #fff3cd;
}

Click-to-Scroll: Table Follows Selection

When user clicks a bubble, scroll the table to show that row:

circles.on("click", function(event, d) {
  const key = d.ticker;

  // ... highlighting code above ...

  // Find and scroll to table row
  const selectedRow = document.querySelector(`tr[data-ticker="${key}"]`);
  if (selectedRow) {
    selectedRow.scrollIntoView({behavior: "smooth", block: "center"});
  }
});

In HTML table, add data attribute:

<tr data-ticker="AAPL">
  <td>AAPL</td>
  <td>Apple Inc.</td>
  ...
</tr>

Hover Coordination

Lighter interaction - highlight without full selection:

circles.on("mouseover", function(event, d) {
  const key = KEY(d);
  circles.classed("hovered", e => KEY(e) === key);
  tableRows.classed("hovered", row => KEY(row) === key);
})
.on("mouseout", function() {
  circles.classed("hovered", false);
  tableRows.classed("hovered", false);
});

tableRows.on("mouseover", function(event, rowData) {
  const key = KEY(rowData);
  tableRows.classed("hovered", row => KEY(row) === key);
  circles.classed("hovered", d => KEY(d) === key);
})
.on("mouseout", function() {
  tableRows.classed("hovered", false);
  circles.classed("hovered", false);
});

CSS for hover:

circle.hovered {
  stroke: #333;
  stroke-width: 1;
  opacity: 0.8;
}

tr.hovered {
  background-color: #f0f0f0;
}

D3 Data Binding Pattern

Ensure table rows and bubbles reference same data array:

// Load data once
d3.csv("data/stocks.csv").then(rawData => {
  const data = processData(rawData);

  // Chart uses this data
  drawChart(data);

  // Table uses this data
  drawTable(data);
});

function drawChart(data) {
  const circles = svg.selectAll("circle")
    .data(data, d => d.ticker) // Key function
    .enter()
    .append("circle");
  // ... rest of chart code
}

function drawTable(data) {
  const rows = tbody.selectAll("tr")
    .data(data, d => d.ticker) // Same key function!
    .enter()
    .append("tr");
  // ... rest of table code
}

Critical: Use identical key functions in both data() calls.

Pattern: Bilateral Selection State

Maintain a shared state object to prevent infinite loops:

let selectedTicker = null;

function selectByTicker(ticker) {
  selectedTicker = ticker;

  // Update both chart and table
  circles.classed("selected", d => d.ticker === ticker);
  tableRows.classed("selected", row => row.ticker === ticker);
}

circles.on("click", function(event, d) {
  selectByTicker(d.ticker);
});

tableRows.on("click", function(event, rowData) {
  selectByTicker(rowData.ticker);
});

Handling Dynamic Updates

If data changes:

function updateData(newData) {
  // Update chart circles
  circles = svg.selectAll("circle").data(newData, d => d.ticker);
  circles.exit().remove();
  // ... handle update and enter selections

  // Update table rows
  rows = tbody.selectAll("tr").data(newData, d => d.ticker);
  rows.exit().remove();
  // ... handle update and enter selections

  // Reattach event handlers
  attachClickHandlers();
}

Testing Checklist

  • Click bubble → row highlights and table scrolls
  • Click row → bubble highlights
  • Click different bubble → previous highlights clear
  • Hover bubble → row highlights
  • Hover row → bubble highlights
  • Scroll table → interactions still work
  • Multiple rapid clicks don't break state
  • Data keys are consistent (no duplicates)
  • CSS classes applied/removed correctly

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.