[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69B88VMBPW8VM7MGPYW5TY6":3,"skill-same:01M69B88VMBPW8VM7MGPYW5TY6":77},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":49,"linkOnly":50,"markdownContent":51,"markdownBody":52,"frontMatter":53,"refName":54,"commitSha":55,"skillDirectory":56,"forksCount":57,"repositoryHtmlUrl":58,"repositoryHomepageUrl":6,"ownerHtmlUrl":59,"ownerBlogUrl":60,"ownerDescription":61,"updatedAt":62,"install":63,"resources":76},"01M69B88VMBPW8VM7MGPYW5TY6","reactor-charts",null,"Reactor charts and data visualization — choosing a chart type (line, bar, area, donut, `TreeChart`, `ForceGraph`), the chart DSL, `LabelView` \u002F `XTickLabelView` \u002F `YTickLabelView` for icon-plus-text and rich labels, and the visualization-best-practices rules. Use when adding charts or designing visualizations.","microsoft\u002Fmicrosoft-ui-reactor","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M69B6EF21X2GHARCXN2BH1K1",863,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor\u002Fblob\u002Fmain\u002Fplugins\u002Freactor\u002Fskills\u002Freactor-charts\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],"reactor charts","Charts","when","data visualization","dsl","rich","labels","bar","for","icon","line","chart","type","best-practices","use","Rules","text","visualizations","data","visualization","2026-11-10 10:12:30",false,"---\nname: reactor-charts\ndescription: \"Reactor charts and data visualization — choosing a chart type (line, bar, area, donut, `TreeChart`, `ForceGraph`), the chart DSL, `LabelView` \u002F `XTickLabelView` \u002F `YTickLabelView` for icon-plus-text and rich labels, and the visualization-best-practices rules. Use when adding charts or designing visualizations.\"\n---\n\n# Reactor Charts\n\nThe chart surface lives in `Reactor.D3.Charts` (full guide:\n`docs\u002Fguide\u002Fcharting.md`). This skill is the AI-agent quick reference —\nchart-choice rules, the new `*View` extension points, and the a11y\u002Faccuracy\nrails you should keep on by default.\n\n## Choose the right chart first\n\nMost \"my chart looks bad\" problems are wrong-chart problems, not styling\nproblems. Cleveland & McGill's perceptual ranking (1984) — accuracy of\ngraphical judgment, best to worst:\n\n> position on a common scale > position on non-aligned scales > length \u002F\n> direction \u002F angle > area > volume > shading \u002F color saturation\n\nThat ordering is why bars and dots win and why pies lose. Translate it into\nrules of thumb:\n\n| Chart | Use when | Avoid when |\n|---|---|---|\n| **Bar** | Discrete categories, time buckets (Q1..Q4), ranked comparison. **Default when in doubt.** | (Use a different chart if the data is continuous, e.g. dense time-series — line is clearer.) |\n| **Line** | Continuous data, many x-values, trends\u002Fslopes, autocorrelated series (prices, sensor readings). | Few categorical observations — use bar. |\n| **Area** | Cumulative magnitude or parts-of-whole over time. | Series cross frequently — overlap occludes; switch to line. |\n| **Pie** | Parts-of-a-whole **and** ≤5 slices **and** large differences **and** proportions land near recognizable fractions (½, ¼, ⅓). | Anything else. Ranking, change-over-time, negative values, precise comparison — use a sorted bar chart. |\n| **Donut** (`PieChart` with `InnerRadius > 0`) | Same conditions as pie. The inner hole gives you a place for a center label (total, current selection) — useful when the chart sits inside a dashboard. | Same as pie. The hole doesn't fix pie's ranking weakness. |\n| **Tree** (`TreeChart`) | Hierarchical data: org charts, file\u002Ffolder structures, taxonomies, decision trees. Visualizes parent→child links. | Wide hierarchies (>~30 nodes per level) — the tree gets unreadable; consider a treemap (use the `D3.Layout.Treemap` primitive — no top-level factory yet). |\n| **Force graph** (`ForceGraph`) | Relationship networks: dependency graphs, social graphs, knowledge graphs. Shows which nodes cluster. | Hierarchical data — use `TreeChart` (an explicit layout always reads better when one exists). Static print\u002Fsnapshot output — force layouts converge differently each run. |\n\nWhen the user asks for a pie chart, push back unless all four pie conditions\nhold. A sorted bar chart usually wins. (Few\u002FTufte say \"almost never pie\";\nCairo\u002FWilke allow the narrow case above. Default to \"no\" and concede when\nthe conditions are met.)\n\n**Charts not yet exposed as top-level factories:** Sankey, Treemap, Cluster\ndendrograms, partition\u002Fsunburst, stratified hierarchies. The math primitives\nexist in `src\u002FReactor.Advanced\u002FCharting\u002FD3\u002FLayout\u002F` (`Sankey.cs`, `Treemap.cs`,\n`Cluster.cs`, `Stratify.cs`, `TreeLayout.cs`) and can be composed with\n`D3Canvas` + the d3 shape generators. If a user asks for one of these and\nisn't comfortable assembling D3 primitives directly, suggest filing a\nfactory request rather than hand-rolling — the resulting chart will lack\nthe shared accessibility surface.\n\n## The DSL — quick reference\n\n```csharp\nLineChart (data, x, y)              \u002F\u002F continuous line\nBarChart  (data, x, y)              \u002F\u002F vertical bars (always anchored at zero — see pitfalls)\nAreaChart (data, x, y)              \u002F\u002F filled area\nPieChart  (data, value)             \u002F\u002F slices summing to 100%\nPieChart  (data, value)             \u002F\u002F donut variant: chain .InnerRadius(40+)\n    .InnerRadius(60)\nTreeChart (root, children)          \u002F\u002F hierarchical (org chart, file tree, taxonomy)\nForceGraph(nodes, links)            \u002F\u002F network graph (dependencies, relationships)\n```\n\nCommon fluent knobs (chain-call any subset):\n\n```csharp\n.Title(\"Monthly Revenue\")\n.SeriesName(\"Revenue\")\n.Units(xUnits: \"months\", yUnits: \"USD\")\n.AxisLabel(ChartAxisType.X, \"Month\")\n.AxisLabel(ChartAxisType.Y, \"Revenue (USD)\")\n.Width(600).Height(250)\n.Stroke(\"#0078D4\").StrokeWidth(2.5)\n.Fill(\"#50C878\")                                  \u002F\u002F bars \u002F area \u002F pie slice baseline\n.ShowGrid(true).ShowAxes(true)\n.DataLabel((point, idx) => $\"{point.Revenue:C}\")  \u002F\u002F string label per point\n.Palette(ChartPalette.Categorical)                \u002F\u002F Tier 1 curated palette (a11y-scanned)\n.ChartBackground(\"#1E1E1E\")                        \u002F\u002F declare active bg → scopes A11Y_CHART_011\n```\n\n`AxisLabel` text and `Title` are reserved for *labeling the chart*, not\nlabeling individual data points or ticks — for those, see the next two\nsections.\n\n## Make D3 do the work\n\nCharts compose D3-style scales and generators internally. When you reach\nunder the DSL hood (or hand-roll Canvas drawings), follow these:\n\n- **Scales map domain → range — never compute pixel positions by hand.** A\n  `LinearScale` from `[min, max]` to `[plotLeft, plotRight]` is the boundary\n  between \"data\" and \"pixels\". Mixing them is the #1 source of \"off by 5px\"\n  bugs.\n- **Pick the right scale type for the data.** Linear for quantitative,\n  log for exponential, time for dates, ordinal\u002Fband for categories. Linear-\n  on-exponential hides patterns; log-on-linear inflates them.\n- **Always `.nice()` quantitative domains.** Axis bounds should round to\n  human-friendly numbers (0\u002F100\u002F200, not 13.7\u002F187.4). Pair with `.ticks(n)`\n  as a *suggestion*, not a hard count — D3 picks readable intervals.\n- **Reserve margins.** Long y-axis labels and multi-line tick `*View`\n  elements need gutter. The Bostock margin convention\n  (`{top, right, bottom, left}`) is the safe default; if you customize tick\n  labels (next section), measure the longest one and grow the margin.\n- **Don't reinvent the axis.** The built-in axis generator handles tick\n  selection, formatting, alignment, label rotation. Custom tick code is\n  where charts go to die.\n\n## When string labels aren't enough — `*View`\n\nThree cases the string-label APIs (`DataLabel`, `AxisLabel`, `LabelAccessor`)\ncan't handle:\n\n1. The label needs an **icon** next to or inside the text.\n2. The label needs **multi-line text**, wrapping, or different colors \u002F\n   weights per fragment.\n3. The label needs to render a **mini sub-tree** (badge, sparkline, mini\n   button, anything Reactor can build).\n\nFor these, reach for the `*View` extensions. They take a render delegate and\nsubstitute its returned `Element` for the built-in `TextBlock` at the same\nanchor position:\n\n```csharp\n\u002F\u002F Pie slice: replace text label with arbitrary element rendered at the slice centroid\nPieChart(data, d => d.Value)\n    .LabelView((d, layout) => HStack(\n        FontIcon(IconForCategory(d.Category)).FontSize(12),\n        TextBlock($\"{layout.Fraction:P0}\").FontWeight(FontWeights.SemiBold)));\n\n\u002F\u002F Axis tick: replace numeric tick label with arbitrary element\nLineChart(data, x, y)\n    .XTickLabelView(t => VStack(\n        TextBlock(MonthName((int)t)).FontSize(11),\n        TextBlock(\"month\").FontSize(8).Foreground(Theme.SecondaryText)))\n    .YTickLabelView(t => TextBlock($\"${t:N0}\").FontFamily(\"Cascadia Mono\"));\n```\n\n### `PieChartElement\u003CT>.LabelView(Func\u003CT, PieSliceLayout, Element>)`\n\nThe render delegate receives:\n\n- `T data` — the slice's source data item.\n- `PieSliceLayout layout` — a `readonly record struct` with everything you\n  need to render a label that knows its slice geometry:\n  - `Index, Value, Fraction` (0..1 of total)\n  - `CentroidX, CentroidY` (absolute canvas coords — already applied via\n    `CenterAt`, you don't need to apply them yourself)\n  - `StartAngle, EndAngle` (radians, clockwise from 12 o'clock — d3 semantics)\n  - `InnerRadius, OuterRadius`\n  - `Color` — the resolved `D3Color` from the chart's palette, so your label\n    can echo the slice color without a separate lookup.\n\nThe returned element is auto-anchored at the centroid via `CenterAt`. You do\n**not** need a known size at construction time; the reconciler recomputes\nposition after layout from `ActualWidth`\u002F`ActualHeight`.\n\n### `ChartElement\u003CT>.XTickLabelView(Func\u003Cdouble, Element>)` and `YTickLabelView`\n\nSame pattern for axis ticks. The delegate receives the tick's domain value\n(`double`); X labels are anchored horizontally centered on the tick mark, Y\nlabels right-anchored to the axis edge and vertically centered.\n\n## Direct labeling vs legend vs tooltip\n\nA label-placement decision tree (Tufte, Cleveland — direct labeling raises\nthe data-ink ratio and avoids legend ping-pong):\n\n1. **Direct labels first.** Label series at the end of each line, label pie\n   slices on the chart, label bars above the bar. `LabelView` \u002F\n   `*TickLabelView` exist precisely so you can do this without re-templating\n   the whole chart. Eyes don't ping-pong from line to legend; print works;\n   screen readers work.\n2. **Use a legend** only when direct labeling would collide — many series,\n   tightly-packed lines, repeating palette across small multiples. Treat it\n   as a fallback, not a default.\n3. **Use a tooltip** for precise values on dense data, *in addition to* —\n   never *instead of* — direct labels or a legend. Tooltips fail print,\n   screen readers, mobile-tap accuracy, and keyboard navigation.\n4. **Pie slices**: large slices get inside-labels; small slices (\u003C~5%) need\n   outside leader lines or get rolled into \"Other\". Don't label tiny slices\n   inline — they overlap.\n5. **Backfire cases**: dense scatterplots, tightly-packed bars, many\n   overlapping line endpoints. Label collisions there are worse than a\n   legend; switch to legend.\n\n## Anchor primitive (used by `*View` internally)\n\nThe `*View` methods are built on `Canvas`'s anchor extensions\n(`CanvasExtensions.cs`). You'll rarely call them directly, but if you need to\nposition arbitrary content on a Reactor `Canvas` without knowing its size at\nbuild time (overlay markers, custom callouts), use these:\n\n```csharp\n.Canvas(left, top, anchorX, anchorY)   \u002F\u002F 0..1 fractions of rendered size\n.CenterAt(x, y)                        \u002F\u002F sugar for anchor (0.5, 0.5)\n```\n\nThe reconciler subscribes once to `Loaded + SizeChanged` per anchored element\nand recomputes `Canvas.Left\u002FTop` as `target − anchor × ActualWidth\u002FHeight`.\nZero-anchor `(0, 0)` is the legacy fast path with no subscription overhead.\n\n## Accessibility — beyond the framework defaults\n\nCharts implement `IChartAccessibilityData`, which exposes axis ranges, units,\npoint values, and (for pie) slice descriptors via UIA. Don't disable that.\nBeyond that, your responsibilities:\n\n- **Color is never the sole channel** (WCAG 1.4.1). Pair color with shape,\n  pattern, dash style, or — best — a direct text label. Useful for series\n  identification when the user can't distinguish two of your colors.\n- **Color-blind-safe palettes.** Use `ChartPalette.Categorical` (Reactor's\n  curated set; Okabe-Ito-style). Avoid red\u002Fgreen pairings. Avoid rainbow\n  for ordinal data — use a sequential ramp (Viridis-style) instead.\n- **Contrast.** WCAG 1.4.11 — 3:1 for non-text essential graphics, 4.5:1\n  for text labels. The default chart palette meets this against the\n  framework's surface tokens; if you override with `.Stroke(\"#…\")` \u002F\n  `.Fill(\"#…\")`, check contrast against `Theme.SurfaceBackground`.\n- **Custom colors & the scanner.** Three tiers, in order of safety:\n  `.Palette(ChartPalette.Categorical)` (Tier 1, curated) and `.SeriesColors(…)`\n  (Tier 3, your own colors) are both contrast-checked by the a11y scanner\n  (`A11Y_CHART_011`). `.RawColors(…)` (Tier 4) is an escape hatch that bypasses\n  the check and itself trips the `A11Y_CHART_012` info. A pie chart's low-level\n  `.SetColors(…)` colors are the slices it actually draws, so they are\n  scanner-visible too — validated as a Tier-3 custom palette. When a pie sets\n  both `.SetColors(…)` and `.Palette(…)`, the rendered `.SetColors(…)` colors are\n  the ones scanned.\n- **Declare the background you render on.** `A11Y_CHART_011` is theme-agnostic\n  by default, so it can only flag a custom color against *either* fixed\n  light\u002Fdark background as an `info`. Call `.ChartBackground(\"#1E1E1E\")` (also\n  takes a `D3Color` or `Windows.UI.Color`) to scope the check to the single\n  background the chart actually renders on — the finding becomes an actionable\n  `warning` with a real, contrast-hardened fix, and palettes that are fine on\n  their actual background stop being flagged.\n- **Screen-reader fallback.** UIA structured data is good but not enough\n  for screen-reader-only users — a hidden, expandable data table next to\n  the chart is the pattern Tenon and the W3C WAI accessibility guidance\n  recommend. Build it from the same data the chart consumed.\n- **Keyboard nav.** Data points should be focusable in reading order, and\n  focus should announce category + value. The `IChartAccessibilityData`\n  surface drives this; if you turn the chart `Interactive(false)` you lose\n  it — keep it on unless there's a reason.\n- **`*View` defaults.** Custom labels are non-interactive by default: the\n  chart force-applies `AccessibilityView=Raw` to the **entire realized\n  subtree** (not just the outer wrapper) and clears `IsTabStop` on every inner\n  control, so no inner peer surfaces to UIA and nothing inside the label joins\n  the tab order. Prefer keeping the string `LabelAccessor` (PieChart) or\n  `DataLabel` (line\u002Fbar\u002Farea) set — those feed UIA. When the visual lives\n  entirely in the `*View`, pass `name:` (a `Func\u003CT,string>` for pie \u002F\n  `Func\u003Cdouble,string>` for ticks) so the accessible name matches the visible\n  label instead of falling back to `Slice {n}`. Set `interactive: true` only\n  when the label has focusable children that must stay reachable — then **you**\n  own its accessibility. Signatures:\n  `LabelView(render, name: null, interactive: false)`,\n  `XTickLabelView(render, name: null, interactive: false)`,\n  `YTickLabelView(render, name: null, interactive: false)`.\n\n## Common pitfalls — refuse to ship these\n\nThe most-cited visualization mistakes (Tufte, Few, Cairo, Wilke). If a user\nasks for one, push back with the alternative.\n\n- **Truncated bar baselines.** Bars MUST start at zero. A 3% gap with a\n  truncated baseline visually looks like 300%. Cairo's *How Charts Lie*\n  spends a chapter on this. Line charts may truncate because shape, not\n  height, conveys meaning — bars never.\n- **Dual y-axes.** Fabricates correlation between unrelated series. Use two\n  small multiples or normalize both series to an index (e.g. `(value \u002F\n  baseline) × 100`) so they share a single axis.\n- **3D \u002F exploded pies, drop shadows, gradients on bars.** Tufte's\n  \"chartjunk.\" 3D pies are actively misleading — angle distortion changes\n  the visual proportion of slices.\n- **Too many series.** >5–7 lines, >7 pie slices. Group the tail into\n  \"Other\" or split into small multiples.\n- **Rainbow \u002F unordered categorical palettes on ordinal data.** When the\n  variable has order (low\u002Fmedium\u002Fhigh, age buckets, sentiment), use a\n  sequential ramp. A categorical palette implies \"different kind\", not\n  \"different magnitude\".\n- **Pie chart for ranking.** Pies hide rank — angle judgments are\n  imprecise. A sorted bar chart shows it directly.\n\n## When to reach for `*View` (and when not to)\n\nReach for it when:\n\n- You need an **icon-plus-text** axis tick or slice label.\n- You need to render the slice **percent** in the slice itself instead of a\n  side legend (direct labeling, see above).\n- You're embedding a chart in a dashboard whose typography contract demands\n  fonts\u002Fcolors the built-in `ChartAxis` style doesn't match.\n\nSkip it when a `string` works:\n\n- Plain numeric formatting → `DataLabel((d, i) => d.Value.ToString(\"C\"))`.\n- Custom number-to-string for ticks → built-in tick formatting (`Fmt(t)`\n  handles short numbers cleanly).\n- Just changing color\u002Ffont of a built-in label — that's not exposed yet;\n  if you need it, file an issue rather than dropping to `*View` for a\n  one-property override.\n\n## Reading list\n\n- `docs\u002Fguide\u002Fcharting.md` — full user-facing chart guide.\n- `src\u002FReactor.Advanced\u002FCharting\u002FCharts.cs` — `ChartElement\u003CT>` \u002F `PieChartElement\u003CT>`\n  fluent API. `*View` methods sit near the bottom of each class.\n- `src\u002FReactor.Advanced\u002FCharting\u002FCharts.Tree.cs` — `TreeChart` and `ForceGraph`\n  factories + their elements.\n- `src\u002FReactor.Advanced\u002FCharting\u002FD3Charts.cs` — d3 primitives (`D3Pie`, `D3Axes`,\n  `D3Grid`, `D3Canvas`). `D3Axes` is where the optional `xTickLabel` \u002F\n  `yTickLabel` delegates plug in.\n- `src\u002FReactor.Advanced\u002FCharting\u002FD3\u002FLayout\u002F` — composable layout algorithms\n  (`Sankey.cs`, `Treemap.cs`, `Cluster.cs`, `Stratify.cs`, `TreeLayout.cs`).\n  No top-level factory wrapping these yet; they're the building blocks for\n  one when the time comes.\n- `src\u002FReactor\u002FElements\u002FCanvasExtensions.cs` — `CenterAt` and the anchor\n  overload of `Canvas`.\n\nExternal (read these once if charting is new to you):\n\n- Cleveland & McGill (1984), *Graphical Perception* — the perceptual ranking.\n- Edward Tufte, *The Visual Display of Quantitative Information* — data-ink ratio, chartjunk.\n- Stephen Few, *Show Me the Numbers* — practitioner playbook for business charts.\n- Claus Wilke, *Fundamentals of Data Visualization* — free online; the modern reference.\n- Alberto Cairo, *How Charts Lie* — the pitfalls chapter is required reading.\n- d3js.org docs on `d3-scale`, `d3-axis`, `d3-shape` — even when working through Reactor's wrappers.\n","# Reactor Charts\n\nThe chart surface lives in `Reactor.D3.Charts` (full guide:\n`docs\u002Fguide\u002Fcharting.md`). This skill is the AI-agent quick reference —\nchart-choice rules, the new `*View` extension points, and the a11y\u002Faccuracy\nrails you should keep on by default.\n\n## Choose the right chart first\n\nMost \"my chart looks bad\" problems are wrong-chart problems, not styling\nproblems. Cleveland & McGill's perceptual ranking (1984) — accuracy of\ngraphical judgment, best to worst:\n\n> position on a common scale > position on non-aligned scales > length \u002F\n> direction \u002F angle > area > volume > shading \u002F color saturation\n\nThat ordering is why bars and dots win and why pies lose. Translate it into\nrules of thumb:\n\n| Chart | Use when | Avoid when |\n|---|---|---|\n| **Bar** | Discrete categories, time buckets (Q1..Q4), ranked comparison. **Default when in doubt.** | (Use a different chart if the data is continuous, e.g. dense time-series — line is clearer.) |\n| **Line** | Continuous data, many x-values, trends\u002Fslopes, autocorrelated series (prices, sensor readings). | Few categorical observations — use bar. |\n| **Area** | Cumulative magnitude or parts-of-whole over time. | Series cross frequently — overlap occludes; switch to line. |\n| **Pie** | Parts-of-a-whole **and** ≤5 slices **and** large differences **and** proportions land near recognizable fractions (½, ¼, ⅓). | Anything else. Ranking, change-over-time, negative values, precise comparison — use a sorted bar chart. |\n| **Donut** (`PieChart` with `InnerRadius > 0`) | Same conditions as pie. The inner hole gives you a place for a center label (total, current selection) — useful when the chart sits inside a dashboard. | Same as pie. The hole doesn't fix pie's ranking weakness. |\n| **Tree** (`TreeChart`) | Hierarchical data: org charts, file\u002Ffolder structures, taxonomies, decision trees. Visualizes parent→child links. | Wide hierarchies (>~30 nodes per level) — the tree gets unreadable; consider a treemap (use the `D3.Layout.Treemap` primitive — no top-level factory yet). |\n| **Force graph** (`ForceGraph`) | Relationship networks: dependency graphs, social graphs, knowledge graphs. Shows which nodes cluster. | Hierarchical data — use `TreeChart` (an explicit layout always reads better when one exists). Static print\u002Fsnapshot output — force layouts converge differently each run. |\n\nWhen the user asks for a pie chart, push back unless all four pie conditions\nhold. A sorted bar chart usually wins. (Few\u002FTufte say \"almost never pie\";\nCairo\u002FWilke allow the narrow case above. Default to \"no\" and concede when\nthe conditions are met.)\n\n**Charts not yet exposed as top-level factories:** Sankey, Treemap, Cluster\ndendrograms, partition\u002Fsunburst, stratified hierarchies. The math primitives\nexist in `src\u002FReactor.Advanced\u002FCharting\u002FD3\u002FLayout\u002F` (`Sankey.cs`, `Treemap.cs`,\n`Cluster.cs`, `Stratify.cs`, `TreeLayout.cs`) and can be composed with\n`D3Canvas` + the d3 shape generators. If a user asks for one of these and\nisn't comfortable assembling D3 primitives directly, suggest filing a\nfactory request rather than hand-rolling — the resulting chart will lack\nthe shared accessibility surface.\n\n## The DSL — quick reference\n\n```csharp\nLineChart (data, x, y)              \u002F\u002F continuous line\nBarChart  (data, x, y)              \u002F\u002F vertical bars (always anchored at zero — see pitfalls)\nAreaChart (data, x, y)              \u002F\u002F filled area\nPieChart  (data, value)             \u002F\u002F slices summing to 100%\nPieChart  (data, value)             \u002F\u002F donut variant: chain .InnerRadius(40+)\n    .InnerRadius(60)\nTreeChart (root, children)          \u002F\u002F hierarchical (org chart, file tree, taxonomy)\nForceGraph(nodes, links)            \u002F\u002F network graph (dependencies, relationships)\n```\n\nCommon fluent knobs (chain-call any subset):\n\n```csharp\n.Title(\"Monthly Revenue\")\n.SeriesName(\"Revenue\")\n.Units(xUnits: \"months\", yUnits: \"USD\")\n.AxisLabel(ChartAxisType.X, \"Month\")\n.AxisLabel(ChartAxisType.Y, \"Revenue (USD)\")\n.Width(600).Height(250)\n.Stroke(\"#0078D4\").StrokeWidth(2.5)\n.Fill(\"#50C878\")                                  \u002F\u002F bars \u002F area \u002F pie slice baseline\n.ShowGrid(true).ShowAxes(true)\n.DataLabel((point, idx) => $\"{point.Revenue:C}\")  \u002F\u002F string label per point\n.Palette(ChartPalette.Categorical)                \u002F\u002F Tier 1 curated palette (a11y-scanned)\n.ChartBackground(\"#1E1E1E\")                        \u002F\u002F declare active bg → scopes A11Y_CHART_011\n```\n\n`AxisLabel` text and `Title` are reserved for *labeling the chart*, not\nlabeling individual data points or ticks — for those, see the next two\nsections.\n\n## Make D3 do the work\n\nCharts compose D3-style scales and generators internally. When you reach\nunder the DSL hood (or hand-roll Canvas drawings), follow these:\n\n- **Scales map domain → range — never compute pixel positions by hand.** A\n  `LinearScale` from `[min, max]` to `[plotLeft, plotRight]` is the boundary\n  between \"data\" and \"pixels\". Mixing them is the #1 source of \"off by 5px\"\n  bugs.\n- **Pick the right scale type for the data.** Linear for quantitative,\n  log for exponential, time for dates, ordinal\u002Fband for categories. Linear-\n  on-exponential hides patterns; log-on-linear inflates them.\n- **Always `.nice()` quantitative domains.** Axis bounds should round to\n  human-friendly numbers (0\u002F100\u002F200, not 13.7\u002F187.4). Pair with `.ticks(n)`\n  as a *suggestion*, not a hard count — D3 picks readable intervals.\n- **Reserve margins.** Long y-axis labels and multi-line tick `*View`\n  elements need gutter. The Bostock margin convention\n  (`{top, right, bottom, left}`) is the safe default; if you customize tick\n  labels (next section), measure the longest one and grow the margin.\n- **Don't reinvent the axis.** The built-in axis generator handles tick\n  selection, formatting, alignment, label rotation. Custom tick code is\n  where charts go to die.\n\n## When string labels aren't enough — `*View`\n\nThree cases the string-label APIs (`DataLabel`, `AxisLabel`, `LabelAccessor`)\ncan't handle:\n\n1. The label needs an **icon** next to or inside the text.\n2. The label needs **multi-line text**, wrapping, or different colors \u002F\n   weights per fragment.\n3. The label needs to render a **mini sub-tree** (badge, sparkline, mini\n   button, anything Reactor can build).\n\nFor these, reach for the `*View` extensions. They take a render delegate and\nsubstitute its returned `Element` for the built-in `TextBlock` at the same\nanchor position:\n\n```csharp\n\u002F\u002F Pie slice: replace text label with arbitrary element rendered at the slice centroid\nPieChart(data, d => d.Value)\n    .LabelView((d, layout) => HStack(\n        FontIcon(IconForCategory(d.Category)).FontSize(12),\n        TextBlock($\"{layout.Fraction:P0}\").FontWeight(FontWeights.SemiBold)));\n\n\u002F\u002F Axis tick: replace numeric tick label with arbitrary element\nLineChart(data, x, y)\n    .XTickLabelView(t => VStack(\n        TextBlock(MonthName((int)t)).FontSize(11),\n        TextBlock(\"month\").FontSize(8).Foreground(Theme.SecondaryText)))\n    .YTickLabelView(t => TextBlock($\"${t:N0}\").FontFamily(\"Cascadia Mono\"));\n```\n\n### `PieChartElement\u003CT>.LabelView(Func\u003CT, PieSliceLayout, Element>)`\n\nThe render delegate receives:\n\n- `T data` — the slice's source data item.\n- `PieSliceLayout layout` — a `readonly record struct` with everything you\n  need to render a label that knows its slice geometry:\n  - `Index, Value, Fraction` (0..1 of total)\n  - `CentroidX, CentroidY` (absolute canvas coords — already applied via\n    `CenterAt`, you don't need to apply them yourself)\n  - `StartAngle, EndAngle` (radians, clockwise from 12 o'clock — d3 semantics)\n  - `InnerRadius, OuterRadius`\n  - `Color` — the resolved `D3Color` from the chart's palette, so your label\n    can echo the slice color without a separate lookup.\n\nThe returned element is auto-anchored at the centroid via `CenterAt`. You do\n**not** need a known size at construction time; the reconciler recomputes\nposition after layout from `ActualWidth`\u002F`ActualHeight`.\n\n### `ChartElement\u003CT>.XTickLabelView(Func\u003Cdouble, Element>)` and `YTickLabelView`\n\nSame pattern for axis ticks. The delegate receives the tick's domain value\n(`double`); X labels are anchored horizontally centered on the tick mark, Y\nlabels right-anchored to the axis edge and vertically centered.\n\n## Direct labeling vs legend vs tooltip\n\nA label-placement decision tree (Tufte, Cleveland — direct labeling raises\nthe data-ink ratio and avoids legend ping-pong):\n\n1. **Direct labels first.** Label series at the end of each line, label pie\n   slices on the chart, label bars above the bar. `LabelView` \u002F\n   `*TickLabelView` exist precisely so you can do this without re-templating\n   the whole chart. Eyes don't ping-pong from line to legend; print works;\n   screen readers work.\n2. **Use a legend** only when direct labeling would collide — many series,\n   tightly-packed lines, repeating palette across small multiples. Treat it\n   as a fallback, not a default.\n3. **Use a tooltip** for precise values on dense data, *in addition to* —\n   never *instead of* — direct labels or a legend. Tooltips fail print,\n   screen readers, mobile-tap accuracy, and keyboard navigation.\n4. **Pie slices**: large slices get inside-labels; small slices (\u003C~5%) need\n   outside leader lines or get rolled into \"Other\". Don't label tiny slices\n   inline — they overlap.\n5. **Backfire cases**: dense scatterplots, tightly-packed bars, many\n   overlapping line endpoints. Label collisions there are worse than a\n   legend; switch to legend.\n\n## Anchor primitive (used by `*View` internally)\n\nThe `*View` methods are built on `Canvas`'s anchor extensions\n(`CanvasExtensions.cs`). You'll rarely call them directly, but if you need to\nposition arbitrary content on a Reactor `Canvas` without knowing its size at\nbuild time (overlay markers, custom callouts), use these:\n\n```csharp\n.Canvas(left, top, anchorX, anchorY)   \u002F\u002F 0..1 fractions of rendered size\n.CenterAt(x, y)                        \u002F\u002F sugar for anchor (0.5, 0.5)\n```\n\nThe reconciler subscribes once to `Loaded + SizeChanged` per anchored element\nand recomputes `Canvas.Left\u002FTop` as `target − anchor × ActualWidth\u002FHeight`.\nZero-anchor `(0, 0)` is the legacy fast path with no subscription overhead.\n\n## Accessibility — beyond the framework defaults\n\nCharts implement `IChartAccessibilityData`, which exposes axis ranges, units,\npoint values, and (for pie) slice descriptors via UIA. Don't disable that.\nBeyond that, your responsibilities:\n\n- **Color is never the sole channel** (WCAG 1.4.1). Pair color with shape,\n  pattern, dash style, or — best — a direct text label. Useful for series\n  identification when the user can't distinguish two of your colors.\n- **Color-blind-safe palettes.** Use `ChartPalette.Categorical` (Reactor's\n  curated set; Okabe-Ito-style). Avoid red\u002Fgreen pairings. Avoid rainbow\n  for ordinal data — use a sequential ramp (Viridis-style) instead.\n- **Contrast.** WCAG 1.4.11 — 3:1 for non-text essential graphics, 4.5:1\n  for text labels. The default chart palette meets this against the\n  framework's surface tokens; if you override with `.Stroke(\"#…\")` \u002F\n  `.Fill(\"#…\")`, check contrast against `Theme.SurfaceBackground`.\n- **Custom colors & the scanner.** Three tiers, in order of safety:\n  `.Palette(ChartPalette.Categorical)` (Tier 1, curated) and `.SeriesColors(…)`\n  (Tier 3, your own colors) are both contrast-checked by the a11y scanner\n  (`A11Y_CHART_011`). `.RawColors(…)` (Tier 4) is an escape hatch that bypasses\n  the check and itself trips the `A11Y_CHART_012` info. A pie chart's low-level\n  `.SetColors(…)` colors are the slices it actually draws, so they are\n  scanner-visible too — validated as a Tier-3 custom palette. When a pie sets\n  both `.SetColors(…)` and `.Palette(…)`, the rendered `.SetColors(…)` colors are\n  the ones scanned.\n- **Declare the background you render on.** `A11Y_CHART_011` is theme-agnostic\n  by default, so it can only flag a custom color against *either* fixed\n  light\u002Fdark background as an `info`. Call `.ChartBackground(\"#1E1E1E\")` (also\n  takes a `D3Color` or `Windows.UI.Color`) to scope the check to the single\n  background the chart actually renders on — the finding becomes an actionable\n  `warning` with a real, contrast-hardened fix, and palettes that are fine on\n  their actual background stop being flagged.\n- **Screen-reader fallback.** UIA structured data is good but not enough\n  for screen-reader-only users — a hidden, expandable data table next to\n  the chart is the pattern Tenon and the W3C WAI accessibility guidance\n  recommend. Build it from the same data the chart consumed.\n- **Keyboard nav.** Data points should be focusable in reading order, and\n  focus should announce category + value. The `IChartAccessibilityData`\n  surface drives this; if you turn the chart `Interactive(false)` you lose\n  it — keep it on unless there's a reason.\n- **`*View` defaults.** Custom labels are non-interactive by default: the\n  chart force-applies `AccessibilityView=Raw` to the **entire realized\n  subtree** (not just the outer wrapper) and clears `IsTabStop` on every inner\n  control, so no inner peer surfaces to UIA and nothing inside the label joins\n  the tab order. Prefer keeping the string `LabelAccessor` (PieChart) or\n  `DataLabel` (line\u002Fbar\u002Farea) set — those feed UIA. When the visual lives\n  entirely in the `*View`, pass `name:` (a `Func\u003CT,string>` for pie \u002F\n  `Func\u003Cdouble,string>` for ticks) so the accessible name matches the visible\n  label instead of falling back to `Slice {n}`. Set `interactive: true` only\n  when the label has focusable children that must stay reachable — then **you**\n  own its accessibility. Signatures:\n  `LabelView(render, name: null, interactive: false)`,\n  `XTickLabelView(render, name: null, interactive: false)`,\n  `YTickLabelView(render, name: null, interactive: false)`.\n\n## Common pitfalls — refuse to ship these\n\nThe most-cited visualization mistakes (Tufte, Few, Cairo, Wilke). If a user\nasks for one, push back with the alternative.\n\n- **Truncated bar baselines.** Bars MUST start at zero. A 3% gap with a\n  truncated baseline visually looks like 300%. Cairo's *How Charts Lie*\n  spends a chapter on this. Line charts may truncate because shape, not\n  height, conveys meaning — bars never.\n- **Dual y-axes.** Fabricates correlation between unrelated series. Use two\n  small multiples or normalize both series to an index (e.g. `(value \u002F\n  baseline) × 100`) so they share a single axis.\n- **3D \u002F exploded pies, drop shadows, gradients on bars.** Tufte's\n  \"chartjunk.\" 3D pies are actively misleading — angle distortion changes\n  the visual proportion of slices.\n- **Too many series.** >5–7 lines, >7 pie slices. Group the tail into\n  \"Other\" or split into small multiples.\n- **Rainbow \u002F unordered categorical palettes on ordinal data.** When the\n  variable has order (low\u002Fmedium\u002Fhigh, age buckets, sentiment), use a\n  sequential ramp. A categorical palette implies \"different kind\", not\n  \"different magnitude\".\n- **Pie chart for ranking.** Pies hide rank — angle judgments are\n  imprecise. A sorted bar chart shows it directly.\n\n## When to reach for `*View` (and when not to)\n\nReach for it when:\n\n- You need an **icon-plus-text** axis tick or slice label.\n- You need to render the slice **percent** in the slice itself instead of a\n  side legend (direct labeling, see above).\n- You're embedding a chart in a dashboard whose typography contract demands\n  fonts\u002Fcolors the built-in `ChartAxis` style doesn't match.\n\nSkip it when a `string` works:\n\n- Plain numeric formatting → `DataLabel((d, i) => d.Value.ToString(\"C\"))`.\n- Custom number-to-string for ticks → built-in tick formatting (`Fmt(t)`\n  handles short numbers cleanly).\n- Just changing color\u002Ffont of a built-in label — that's not exposed yet;\n  if you need it, file an issue rather than dropping to `*View` for a\n  one-property override.\n\n## Reading list\n\n- `docs\u002Fguide\u002Fcharting.md` — full user-facing chart guide.\n- `src\u002FReactor.Advanced\u002FCharting\u002FCharts.cs` — `ChartElement\u003CT>` \u002F `PieChartElement\u003CT>`\n  fluent API. `*View` methods sit near the bottom of each class.\n- `src\u002FReactor.Advanced\u002FCharting\u002FCharts.Tree.cs` — `TreeChart` and `ForceGraph`\n  factories + their elements.\n- `src\u002FReactor.Advanced\u002FCharting\u002FD3Charts.cs` — d3 primitives (`D3Pie`, `D3Axes`,\n  `D3Grid`, `D3Canvas`). `D3Axes` is where the optional `xTickLabel` \u002F\n  `yTickLabel` delegates plug in.\n- `src\u002FReactor.Advanced\u002FCharting\u002FD3\u002FLayout\u002F` — composable layout algorithms\n  (`Sankey.cs`, `Treemap.cs`, `Cluster.cs`, `Stratify.cs`, `TreeLayout.cs`).\n  No top-level factory wrapping these yet; they're the building blocks for\n  one when the time comes.\n- `src\u002FReactor\u002FElements\u002FCanvasExtensions.cs` — `CenterAt` and the anchor\n  overload of `Canvas`.\n\nExternal (read these once if charting is new to you):\n\n- Cleveland & McGill (1984), *Graphical Perception* — the perceptual ranking.\n- Edward Tufte, *The Visual Display of Quantitative Information* — data-ink ratio, chartjunk.\n- Stephen Few, *Show Me the Numbers* — practitioner playbook for business charts.\n- Claus Wilke, *Fundamentals of Data Visualization* — free online; the modern reference.\n- Alberto Cairo, *How Charts Lie* — the pitfalls chapter is required reading.\n- d3js.org docs on `d3-scale`, `d3-axis`, `d3-shape` — even when working through Reactor's wrappers.\n",{"name":5,"description":7},"main","74791562c11792f7c0e2dd875f1e82b94d70b397","plugins\u002Freactor\u002Fskills\u002Freactor-charts",66,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-11-12 01:49:38",{"source":8,"skillName":5,"commands":64,"prompt":74,"zipAvailable":75},[65,68,71],{"tool":66,"command":67},"npx","npx skills add microsoft\u002Fmicrosoft-ui-reactor --skill reactor-charts",{"tool":69,"command":70},"bunx","bunx skills add microsoft\u002Fmicrosoft-ui-reactor --skill reactor-charts",{"tool":72,"command":73},"pnpm","pnpm dlx skills add microsoft\u002Fmicrosoft-ui-reactor --skill reactor-charts","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor\u002Fblob\u002Fmain\u002Fplugins\u002Freactor\u002Fskills\u002Freactor-charts\u002FSKILL.md",true,[],[78,84,112,137,161,184],{"skillNo":79,"name":80,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":49},"01M69B94E15PYYWXAGFV832MRK","Charting","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor\u002Fblob\u002Fmain\u002Fsrc\u002FReactor.Advanced\u002FCharting\u002Fskill.md",[],[80],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":90,"publishedAt":49},"01M69B92C846XMSNJ4PZGVYY3C","reactor-wrapping","Turn ANY WinUI control — a vendor\u002Fthird-party control, your own custom Control, or a Windows Community Toolkit one — into a first-class declarative Reactor element with the [GenerateReactorWrapper] source generator, zero hand-written wrapper code. Covers auto-inference (props, content, two-way pairs, panel\u002Fitems children, events), the [Wrap*] annotation cheat-sheet, imperative-lifecycle controls, diagnostics, and when to fall back to a hand-written ControlDescriptor.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor\u002Fblob\u002Fmain\u002Fplugins\u002Freactor\u002Fskills\u002Freactor-wrapping\u002FSKILL.md",[],[91,92,93,94,95,96,97,31,98,99,100,101,102,103,104,105,106,107,108,109,110,111],"reactor wrapping","declarative","with","hand","code","cheat","generator","auto","controls","custom","element","lifecycle","winui","ZeRO","panel","community","back","inference","diagnostics","toolkit","windows",{"skillNo":113,"name":114,"nameZh":6,"description":115,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":116,"categories":117,"keywords":118,"publishedAt":49},"01M69B90PW92BQ4YNZYTP4SERB","reactor-windowing","Reactor top-level windowing cookbook: WindowSpec, OpenWindow, draggable windows, borderless\u002Ftool windows, placement persistence, taskbar visibility, z-order, aspect ratio, SizeToContent, displays, taskbar integration, and owner-window file\u002Ffolder pickers.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor\u002Fblob\u002Fmain\u002Fplugins\u002Freactor\u002Fskills\u002Freactor-windowing\u002FSKILL.md",[],[119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,111,134,135,136],"reactor windowing","progress","persistence","cookbook","integration","folder","command","command palette","top","window","palette","file","restore","open","tool","remember","position","make",{"skillNo":138,"name":139,"nameZh":6,"description":140,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":141,"categories":142,"keywords":143,"publishedAt":49},"01M69B8Y5Y0VKXADXCN3W1NK89","reactor-recipes","Paste-ready single-file Reactor recipes indexed by intent — list with add\u002Fdelete\u002Ftoggle, sidebar navigation between pages, form with validation + submit gating, async fetch with loading\u002Ferror\u002Fdata states, themed Win11 card surface. Use a recipe instead of synthesizing from prose: copy, adjust, ship.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor\u002Fblob\u002Fmain\u002Fplugins\u002Freactor\u002Fskills\u002Freactor-recipes\u002FSKILL.md",[],[144,145,130,146,93,147,43,148,149,150,151,152,153,154,155,156,157,158,159,160],"reactor recipes","recipes","recipe","form","adjust","single","pages","async","card","submit","loading","states","fetch","gating","single-file","ready","error",{"skillNo":162,"name":163,"nameZh":6,"description":164,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":165,"categories":166,"keywords":167,"publishedAt":49},"01M69B8WNYS31M4P012P2QTX6R","reactor-navigation","Reactor navigation — `UseNavigation` hook, `NavigationHost` renderer, `NavigationView` sidebar, `TabView` tabs, route params, stack operations, page lifecycle, deep linking, transitions, caching. Use when building multi-page apps or wiring sidebar\u002Ftab navigation.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor\u002Fblob\u002Fmain\u002Fplugins\u002Freactor\u002Fskills\u002Freactor-navigation\u002FSKILL.md",[],[168,169,170,31,171,43,102,172,173,174,175,176,177,178,179,180,181,182,183],"navigation","reactor navigation","caching","apps","renderer","multi-page","page","deep","wiring","hook","operations","transitions","linking","stack","route","multi",{"skillNo":185,"name":186,"nameZh":6,"description":187,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":188,"categories":189,"keywords":190,"publishedAt":49},"01M69B8TGJA43N8X6BFVWTXC1H","reactor-input","Reactor input — gestures (`OnPan`, `OnPinch`, `OnRotate`), pointer events, drag-and-drop (`OnDragStarting`), focus management (`UseElementFocus`, `UseFocus`, `UseFocusTrap`). Use when implementing direct manipulation or custom focus behavior.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor\u002Fblob\u002Fmain\u002Fplugins\u002Freactor\u002Fskills\u002Freactor-input\u002FSKILL.md",[],[191,192,193,194,195,196,197,198,31,43,100,199,200,201],"input","reactor input","direct","events","management","behavior","focus","drop","implementing","drag","gestures"]