{"id":"c553d713-ae8d-4f56-a4b6-070b1e3e936c","shortId":"rFAkys","kind":"skill","title":"d3js-data-visualization","tagline":"Create interactive, custom data visualizations using d3.js — including charts, graphs, network diagrams, and geographic maps. Use when you need fine-grained control over visual elements, transitions, or interactions beyond what standard charting libraries offer, in any JavaScript","description":"# D3.js Data Visualization\n\nBuild sophisticated, interactive data visualizations using d3.js (Data-Driven Documents). D3 binds data to DOM elements and applies data-driven transformations to produce publication-quality, fully customizable visuals.\n\n## When to Use This Skill\n\n- Custom charts requiring unique visual encodings or layouts\n- Interactive visualizations with pan, zoom, or brush behaviors\n- Network/graph visualizations (force-directed, tree, hierarchy, chord diagrams)\n- Geographic visualizations with custom projections\n- Smooth, choreographed transitions and animations\n- Novel chart types not available in standard libraries (Recharts, Chart.js, etc.)\n- Fine-grained SVG styling and accessibility control\n\n**Consider alternatives for:**\n- 3D visualizations → use Three.js\n- Simple standard charts with minimal customization → use Chart.js or Recharts\n\n## Required Tools / Libraries\n\nNo backend required. Runs entirely in the browser or Node.js (with jsdom/canvas).\n\n```bash\n# Install via npm\nnpm install d3\n\n# Or use CDN in HTML\n<script src=\"https://d3js.org/d3.v7.min.js\"></script>\n```\n\n## Core Workflow\n\n### 1. Set Up D3\n\n```javascript\nimport * as d3 from 'd3';\n```\n\n### 2. Standard Chart Structure\n\nEvery d3 visualization follows this pattern:\n\n```javascript\nfunction drawChart(data) {\n  if (!data || data.length === 0) return;\n\n  const svg = d3.select('#chart');\n  svg.selectAll(\"*\").remove(); // clear previous render\n\n  const width = 800, height = 400;\n  const margin = { top: 20, right: 30, bottom: 40, left: 50 };\n  const innerWidth = width - margin.left - margin.right;\n  const innerHeight = height - margin.top - margin.bottom;\n\n  const g = svg.append(\"g\")\n    .attr(\"transform\", `translate(${margin.left},${margin.top})`);\n\n  // Define scales\n  const xScale = d3.scaleLinear().domain([0, d3.max(data, d => d.x)]).range([0, innerWidth]);\n  const yScale = d3.scaleLinear().domain([0, d3.max(data, d => d.y)]).range([innerHeight, 0]);\n\n  // Axes\n  g.append(\"g\").attr(\"transform\", `translate(0,${innerHeight})`).call(d3.axisBottom(xScale));\n  g.append(\"g\").call(d3.axisLeft(yScale));\n\n  // Data elements\n  g.selectAll(\"circle\")\n    .data(data)\n    .join(\"circle\")\n    .attr(\"cx\", d => xScale(d.x))\n    .attr(\"cy\", d => yScale(d.y))\n    .attr(\"r\", 5)\n    .attr(\"fill\", \"steelblue\");\n}\n```\n\n## Common Chart Patterns\n\n### Bar Chart\n\n```javascript\nconst xScale = d3.scaleBand().domain(data.map(d => d.category)).range([0, innerWidth]).padding(0.1);\nconst yScale = d3.scaleLinear().domain([0, d3.max(data, d => d.value)]).range([innerHeight, 0]);\n\ng.selectAll(\"rect\")\n  .data(data)\n  .join(\"rect\")\n  .attr(\"x\", d => xScale(d.category))\n  .attr(\"y\", d => yScale(d.value))\n  .attr(\"width\", xScale.bandwidth())\n  .attr(\"height\", d => innerHeight - yScale(d.value))\n  .attr(\"fill\", \"steelblue\");\n```\n\n### Line Chart\n\n```javascript\nconst line = d3.line()\n  .x(d => xScale(d.date))\n  .y(d => yScale(d.value))\n  .curve(d3.curveMonotoneX);\n\ng.append(\"path\")\n  .datum(data)\n  .attr(\"fill\", \"none\")\n  .attr(\"stroke\", \"steelblue\")\n  .attr(\"stroke-width\", 2)\n  .attr(\"d\", line);\n```\n\n### Scatter Plot\n\n```javascript\ng.selectAll(\"circle\")\n  .data(data)\n  .join(\"circle\")\n  .attr(\"cx\", d => xScale(d.x))\n  .attr(\"cy\", d => yScale(d.y))\n  .attr(\"r\", d => sizeScale(d.size))\n  .attr(\"fill\", d => colorScale(d.category))\n  .attr(\"opacity\", 0.7);\n```\n\n### Pie / Donut Chart\n\n```javascript\nconst pie = d3.pie().value(d => d.value).sort(null);\nconst arc = d3.arc().innerRadius(0).outerRadius(Math.min(width, height) / 2 - 20);\nconst colorScale = d3.scaleOrdinal(d3.schemeCategory10);\n\nconst g = svg.append(\"g\").attr(\"transform\", `translate(${width / 2},${height / 2})`);\n\ng.selectAll(\"path\")\n  .data(pie(data))\n  .join(\"path\")\n  .attr(\"d\", arc)\n  .attr(\"fill\", (d, i) => colorScale(i))\n  .attr(\"stroke\", \"white\")\n  .attr(\"stroke-width\", 2);\n```\n\n### Force-Directed Network Graph\n\n```javascript\nconst simulation = d3.forceSimulation(nodes)\n  .force(\"link\", d3.forceLink(links).id(d => d.id).distance(100))\n  .force(\"charge\", d3.forceManyBody().strength(-300))\n  .force(\"center\", d3.forceCenter(width / 2, height / 2));\n\nconst link = g.selectAll(\"line\").data(links).join(\"line\").attr(\"stroke\", \"#999\");\nconst node = g.selectAll(\"circle\").data(nodes).join(\"circle\")\n  .attr(\"r\", 8).attr(\"fill\", \"steelblue\")\n  .call(d3.drag()\n    .on(\"start\", (e) => { if (!e.active) simulation.alphaTarget(0.3).restart(); e.subject.fx = e.subject.x; e.subject.fy = e.subject.y; })\n    .on(\"drag\",  (e) => { e.subject.fx = e.x; e.subject.fy = e.y; })\n    .on(\"end\",   (e) => { if (!e.active) simulation.alphaTarget(0); e.subject.fx = null; e.subject.fy = null; }));\n\nsimulation.on(\"tick\", () => {\n  link.attr(\"x1\", d => d.source.x).attr(\"y1\", d => d.source.y)\n      .attr(\"x2\", d => d.target.x).attr(\"y2\", d => d.target.y);\n  node.attr(\"cx\", d => d.x).attr(\"cy\", d => d.y);\n});\n```\n\n### Heatmap\n\n```javascript\n// data: [{ row, column, value }, ...]\nconst rows = [...new Set(data.map(d => d.row))];\nconst cols = [...new Set(data.map(d => d.column))];\n\nconst xScale = d3.scaleBand().domain(cols).range([0, innerWidth]).padding(0.01);\nconst yScale = d3.scaleBand().domain(rows).range([0, innerHeight]).padding(0.01);\nconst colorScale = d3.scaleSequential(d3.interpolateYlOrRd).domain([0, d3.max(data, d => d.value)]);\n\ng.selectAll(\"rect\")\n  .data(data)\n  .join(\"rect\")\n  .attr(\"x\", d => xScale(d.column))\n  .attr(\"y\", d => yScale(d.row))\n  .attr(\"width\", xScale.bandwidth())\n  .attr(\"height\", yScale.bandwidth())\n  .attr(\"fill\", d => colorScale(d.value));\n```\n\n## Interactivity\n\n### Tooltips\n\n```javascript\nconst tooltip = d3.select(\"body\").append(\"div\")\n  .style(\"position\", \"absolute\")\n  .style(\"visibility\", \"hidden\")\n  .style(\"background\", \"white\")\n  .style(\"border\", \"1px solid #ddd\")\n  .style(\"padding\", \"10px\")\n  .style(\"border-radius\", \"4px\")\n  .style(\"pointer-events\", \"none\");\n\nelements\n  .on(\"mouseover\", (event, d) => tooltip.style(\"visibility\", \"visible\").html(`<strong>${d.label}</strong><br/>Value: ${d.value}`))\n  .on(\"mousemove\", (event)    => tooltip.style(\"top\", (event.pageY - 10) + \"px\").style(\"left\", (event.pageX + 10) + \"px\"))\n  .on(\"mouseout\",  ()         => tooltip.style(\"visibility\", \"hidden\"));\n```\n\n### Zoom and Pan\n\n```javascript\nconst zoom = d3.zoom()\n  .scaleExtent([0.5, 10])\n  .on(\"zoom\", (event) => g.attr(\"transform\", event.transform));\n\nsvg.call(zoom);\n```\n\n### Transitions & Animations\n\n```javascript\n// Basic\ncircles.transition().duration(750).attr(\"r\", 10);\n\n// Staggered\ncircles.transition().delay((d, i) => i * 50).duration(500).attr(\"cy\", d => yScale(d.value));\n\n// Custom easing\ncircles.transition().duration(1000).ease(d3.easeBounceOut).attr(\"r\", 10);\n```\n\n## Responsive Sizing\n\n```javascript\nfunction setupResponsiveChart(containerId, data) {\n  const container = document.getElementById(containerId);\n  const svg = d3.select(`#${containerId}`).append('svg');\n\n  const updateChart = () => {\n    const { width, height } = container.getBoundingClientRect();\n    svg.attr('width', width).attr('height', height);\n    drawChart(data, svg, width, height);\n  };\n\n  updateChart();\n  window.addEventListener('resize', updateChart);\n  return () => window.removeEventListener('resize', updateChart);\n}\n```\n\n## Scale Reference\n\n| Scale | Use case |\n|-------|----------|\n| `d3.scaleLinear()` | Continuous numeric data |\n| `d3.scaleLog()` | Exponential/logarithmic data |\n| `d3.scaleTime()` | Date/time axes |\n| `d3.scaleBand()` | Bar chart categories |\n| `d3.scaleOrdinal()` | Categorical colors |\n| `d3.scaleSequential()` | Single-hue color gradients |\n| `d3.scaleDiverging()` | Diverging color scales |\n\n## Best Practices\n\n- Always validate data: filter nulls and NaN before binding\n- Clear previous render with `svg.selectAll(\"*\").remove()` before redrawing\n- Use `.join()` (enter/update/exit in one call) instead of separate selections\n- Add ARIA labels (`role=\"img\"`, `aria-label`) for accessibility\n- For >1000 elements, consider Canvas rendering instead of SVG\n- Debounce resize handlers to avoid excessive redraws\n- Define color palettes upfront for visual consistency\n\n## Troubleshooting\n\n| Problem | Solution |\n|---------|----------|\n| Axes not appearing | Check for NaN in scale domain; verify group transform |\n| Transitions not working | Call `.transition()` before attribute changes |\n| Responsive sizing broken | Use `ResizeObserver` or update SVG `width`/`height` on resize |\n| Performance issues | Switch to Canvas, debounce resize, use `.join()` |\n\n## Related Skills\n\n- `generate-asset-price-chart` — OHLC candlestick chart generation\n- `trading-indicators-from-price-data` — Compute indicators to feed into charts\n- `free-geocoding-and-maps` — Geographic data for map visualizations","tags":["d3js","data","visualization","open","skills","besoeasy","agent-skills","ai-agents","claude-code","clawdbot","clawdbot-skill","llm-tools"],"capabilities":["skill","source-besoeasy","skill-d3js-data-visualization","topic-agent-skills","topic-ai-agents","topic-claude-code","topic-clawdbot","topic-clawdbot-skill","topic-llm-tools","topic-mcp-server","topic-openai","topic-openclaw","topic-vibe-coding","topic-vibecoding"],"categories":["open-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/besoeasy/open-skills/d3js-data-visualization","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add besoeasy/open-skills","source_repo":"https://github.com/besoeasy/open-skills","install_from":"skills.sh"}},"qualityScore":"0.505","qualityRationale":"deterministic score 0.51 from registry signals: · indexed on github topic:agent-skills · 111 github stars · SKILL.md body (8,709 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-02T12:55:03.240Z","embedding":null,"createdAt":"2026-04-18T22:10:39.601Z","updatedAt":"2026-05-02T12:55:03.240Z","lastSeenAt":"2026-05-02T12:55:03.240Z","tsv":"'-300':529 '0':209,260,266,272,279,286,334,342,349,460,591,652,662,671 '0.01':655,665 '0.1':337 '0.3':570 '0.5':777 '0.7':443 '1':182 '10':757,762,778,796,820 '100':524 '1000':815,935 '10px':728 '1px':723 '2':192,408,465,479,481,505,534,536 '20':228,466 '30':230 '3d':139 '40':232 '400':224 '4px':733 '5':316 '50':234,803 '500':805 '750':793 '8':558 '800':222 '999':547 'absolut':714 'access':134,933 'add':924 'altern':137 'alway':897 'anim':116,788 'appear':962 'append':710,836 'appli':64 'arc':457,491 'aria':925,930 'aria-label':929 'asset':1005 'attr':249,283,304,309,314,317,356,361,366,369,375,398,401,404,409,421,426,431,436,441,475,489,492,498,501,545,556,559,603,608,613,622,682,687,692,695,698,794,806,818,847 'attribut':978 'avail':121 'avoid':947 'axe':280,877,960 'backend':157 'background':719 'bar':323,879 'bash':168 'basic':790 'behavior':97 'best':895 'beyond':34 'bind':58,905 'bodi':709 'border':722,731 'border-radius':730 'bottom':231 'broken':982 'browser':163 'brush':96 'build':46 'call':288,293,562,919,975 'candlestick':1009 'canva':938,996 'case':867 'categor':883 'categori':881 'cdn':177 'center':531 'chang':979 'charg':526 'chart':13,37,83,118,145,194,214,321,324,379,446,880,1007,1010,1023 'chart.js':126,150 'check':963 'chord':105 'choreograph':113 'circl':299,303,416,420,551,555 'circles.transition':791,798,813 'clear':217,906 'col':640,650 'color':884,889,893,951 'colorscal':439,468,496,667,701 'column':630 'common':320 'comput':1018 'consid':136,937 'consist':956 'const':211,220,225,235,240,245,256,268,326,338,381,448,456,467,471,512,537,548,632,639,646,656,666,706,773,828,832,838,840 'contain':829 'container.getboundingclientrect':843 'containerid':826,831,835 'continu':869 'control':27,135 'core':180 'creat':5 'curv':392 'custom':7,82,110,148,811 'customiz':75 'cx':305,422,619 'cy':310,427,623,807 'd':263,275,306,311,331,345,358,363,371,385,389,410,423,428,433,438,452,490,494,521,600,605,610,615,620,624,637,644,674,684,689,700,743,800,808 'd.category':332,360,440 'd.column':645,686 'd.date':387 'd.id':522 'd.label':748 'd.row':638,691 'd.size':435 'd.source':601,606 'd.target':611,616 'd.value':346,365,374,391,453,675,702,750,810 'd.x':264,308,425,621 'd.y':276,313,430,625 'd3':57,174,185,189,191,197 'd3.arc':458 'd3.axisbottom':289 'd3.axisleft':294 'd3.curvemonotonex':393 'd3.drag':563 'd3.easebounceout':817 'd3.forcecenter':532 'd3.forcelink':518 'd3.forcemanybody':527 'd3.forcesimulation':514 'd3.interpolateylorrd':669 'd3.js':11,43,52 'd3.line':383 'd3.max':261,273,343,672 'd3.pie':450 'd3.scaleband':328,648,658,878 'd3.scalediverging':891 'd3.scalelinear':258,270,340,868 'd3.scalelog':872 'd3.scaleordinal':469,882 'd3.scalesequential':668,885 'd3.scaletime':875 'd3.schemecategory10':470 'd3.select':213,708,834 'd3.zoom':775 'd3js':2 'd3js-data-visualization':1 'data':3,8,44,49,54,59,66,205,207,262,274,296,300,301,344,352,353,397,417,418,484,486,541,552,628,673,678,679,827,851,871,874,899,1017,1030 'data-driven':53,65 'data.length':208 'data.map':330,636,643 'date/time':876 'datum':396 'ddd':725 'debounc':943,997 'defin':254,950 'delay':799 'diagram':16,106 'direct':102,508 'distanc':523 'div':711 'diverg':892 'document':56 'document.getelementbyid':830 'dom':61 'domain':259,271,329,341,649,659,670,968 'donut':445 'drag':579 'drawchart':204,850 'driven':55,67 'durat':792,804,814 'e':566,580,587 'e.active':568,589 'e.subject':573,576 'e.subject.fx':572,581,592 'e.subject.fy':575,583,594 'e.x':582 'e.y':584 'eas':812,816 'element':30,62,297,739,936 'encod':87 'end':586 'enter/update/exit':916 'entir':160 'etc':127 'event':737,742,753,781 'event.pagex':761 'event.pagey':756 'event.transform':784 'everi':196 'excess':948 'exponential/logarithmic':873 'feed':1021 'fill':318,376,399,437,493,560,699 'filter':900 'fine':25,129 'fine-grain':24,128 'follow':199 'forc':101,507,516,525,530 'force-direct':100,506 'free':1025 'free-geocoding-and-map':1024 'fulli':74 'function':203,824 'g':246,248,282,292,472,474 'g.append':281,291,394 'g.attr':782 'g.selectall':298,350,415,482,539,550,676 'generat':1004,1011 'generate-asset-price-chart':1003 'geocod':1026 'geograph':18,107,1029 'gradient':890 'grain':26,130 'graph':14,510 'group':970 'handler':945 'heatmap':626 'height':223,242,370,464,480,535,696,842,848,849,854,989 'hidden':717,768 'hierarchi':104 'html':179,747 'hue':888 'id':520 'img':928 'import':187 'includ':12 'indic':1014,1019 'innerheight':241,278,287,348,372,663 'innerradius':459 'innerwidth':236,267,335,653 'instal':169,173 'instead':920,940 'interact':6,33,48,90,703 'issu':993 'javascript':42,186,202,325,380,414,447,511,627,705,772,789,823 'join':302,354,419,487,543,554,680,915,1000 'jsdom/canvas':167 'label':926,931 'layout':89 'left':233,760 'librari':38,124,155 'line':378,382,411,540,544 'link':517,519,538,542 'link.attr':598 'map':19,1028,1032 'margin':226 'margin.bottom':244 'margin.left':238,252 'margin.right':239 'margin.top':243,253 'math.min':462 'minim':147 'mousemov':752 'mouseout':765 'mouseov':741 'nan':903,965 'need':23 'network':15,509 'network/graph':98 'new':634,641 'node':515,549,553 'node.attr':618 'node.js':165 'none':400,738 'novel':117 'npm':171,172 'null':455,593,595,901 'numer':870 'offer':39 'ohlc':1008 'one':918 'opac':442 'outerradius':461 'pad':336,654,664,727 'palett':952 'pan':93,771 'path':395,483,488 'pattern':201,322 'perform':992 'pie':444,449,485 'plot':413 'pointer':736 'pointer-ev':735 'posit':713 'practic':896 'previous':218,907 'price':1006,1016 'problem':958 'produc':70 'project':111 'public':72 'publication-qu':71 'px':758,763 'qualiti':73 'r':315,432,557,795,819 'radius':732 'rang':265,277,333,347,651,661 'rechart':125,152 'rect':351,355,677,681 'redraw':913,949 'refer':864 'relat':1001 'remov':216,911 'render':219,908,939 'requir':84,153,158 'resiz':857,861,944,991,998 'resizeobserv':984 'respons':821,980 'restart':571 'return':210,859 'right':229 'role':927 'row':629,633,660 'run':159 'scale':255,863,865,894,967 'scaleext':776 'scatter':412 'select':923 'separ':922 'set':183,635,642 'setupresponsivechart':825 'simpl':143 'simul':513 'simulation.alphatarget':569,590 'simulation.on':596 'singl':887 'single-hu':886 'size':822,981 'sizescal':434 'skill':81,1002 'skill-d3js-data-visualization' 'smooth':112 'solid':724 'solut':959 'sophist':47 'sort':454 'source-besoeasy' 'stagger':797 'standard':36,123,144,193 'start':565 'steelblu':319,377,403,561 'strength':528 'stroke':402,406,499,503,546 'stroke-width':405,502 'structur':195 'style':132,712,715,718,721,726,729,734,759 'svg':131,212,833,837,852,942,987 'svg.append':247,473 'svg.attr':844 'svg.call':785 'svg.selectall':215,910 'switch':994 'three.js':142 'tick':597 'tool':154 'tooltip':704,707 'tooltip.style':744,754,766 'top':227,755 'topic-agent-skills' 'topic-ai-agents' 'topic-claude-code' 'topic-clawdbot' 'topic-clawdbot-skill' 'topic-llm-tools' 'topic-mcp-server' 'topic-openai' 'topic-openclaw' 'topic-vibe-coding' 'topic-vibecoding' 'trade':1013 'trading-indicators-from-price-data':1012 'transform':68,250,284,476,783,971 'transit':31,114,787,972,976 'translat':251,285,477 'tree':103 'troubleshoot':957 'type':119 'uniqu':85 'updat':986 'updatechart':839,855,858,862 'upfront':953 'use':10,20,51,79,141,149,176,866,914,983,999 'valid':898 'valu':451,631,749 'verifi':969 'via':170 'visibl':716,745,746,767 'visual':4,9,29,45,50,76,86,91,99,108,140,198,955,1033 'white':500,720 'width':221,237,367,407,463,478,504,533,693,841,845,846,853,988 'window.addeventlistener':856 'window.removeeventlistener':860 'work':974 'workflow':181 'x':357,384,574,602,612,683 'x1':599 'x2':609 'xscale':257,290,307,327,359,386,424,647,685 'xscale.bandwidth':368,694 'y':362,388,577,607,617,688 'y1':604 'y2':614 'yscale':269,295,312,339,364,373,390,429,657,690,809 'yscale.bandwidth':697 'zoom':94,769,774,780,786","prices":[{"id":"50c7b939-44fc-4143-ba88-5a4ebf7fc896","listingId":"c553d713-ae8d-4f56-a4b6-070b1e3e936c","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"besoeasy","category":"open-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:10:39.601Z"}],"sources":[{"listingId":"c553d713-ae8d-4f56-a4b6-070b1e3e936c","source":"github","sourceId":"besoeasy/open-skills/d3js-data-visualization","sourceUrl":"https://github.com/besoeasy/open-skills/tree/main/skills/d3js-data-visualization","isPrimary":false,"firstSeenAt":"2026-04-18T22:10:39.601Z","lastSeenAt":"2026-05-02T12:55:03.240Z"}],"details":{"listingId":"c553d713-ae8d-4f56-a4b6-070b1e3e936c","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"besoeasy","slug":"d3js-data-visualization","github":{"repo":"besoeasy/open-skills","stars":111,"topics":["agent-skills","ai","ai-agents","claude-code","clawdbot","clawdbot-skill","llm-tools","mcp-server","openai","openclaw","vibe-coding","vibecoding"],"license":null,"html_url":"https://github.com/besoeasy/open-skills","pushed_at":"2026-03-31T13:05:30Z","description":"Battle-tested skill library for AI agents. Save 98% of API costs with ready-to-use code for crypto, PDFs, search, web scraping & more. No trial-and-error, no expensive APIs.","skill_md_sha":"ea9ec560edb2d65a9e739d50c1c0cb8ec8f5bfdc","skill_md_path":"skills/d3js-data-visualization/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/besoeasy/open-skills/tree/main/skills/d3js-data-visualization"},"layout":"multi","source":"github","category":"open-skills","frontmatter":{"name":"d3js-data-visualization","description":"Create interactive, custom data visualizations using d3.js — including charts, graphs, network diagrams, and geographic maps. Use when you need fine-grained control over visual elements, transitions, or interactions beyond what standard charting libraries offer, in any JavaScript environment (vanilla JS, React, Vue, Svelte, etc.)."},"skills_sh_url":"https://skills.sh/besoeasy/open-skills/d3js-data-visualization"},"updatedAt":"2026-05-02T12:55:03.240Z"}}