Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
157655 stories
·
33 followers

AI Natural Language Document Generation with MCP and TX Text Control .NET

1 Share
This article explains how AI agents can use natural language to create documents through an MCP server. Instead of letting a language model generate documents directly, the AI translates prompts into structured tool calls while TX Text Control performs the actual document processing.

Read the whole story
alvinashcraft
30 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Announcing Rust 1.97.1

1 Share

The Rust team has published a new point release of Rust, 1.97.1. Rust is a programming language that is empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, getting Rust 1.97.1 is as easy as:

rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website.

What's in 1.97.1

Rust 1.97.1 fixes a miscompilation in an LLVM optimization.

We have backported both an LLVM fix and a disable of the underlying change in Rust 1.97.0 of Rust's generated IR that increased the likelihood of this happening. However, note that the underlying miscompilation has been present since at least Rust 1.87.

If you'd like to help us out by testing future releases, you might consider running your code's CI or locally using the beta channel (rustup default beta) or the nightly channel (rustup default nightly). Please report any bugs you might come across!

Contributors to 1.97.1

Many people came together to create Rust 1.97.1. We couldn't have done it without all of you. Thanks!

Read the whole story
alvinashcraft
41 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Speculating on how the buggy control panel extension truncated a value that it had right in front of it

2 Shares

Last time, we found that a crash in a control panel extension was caused by pointer truncation. The code had a perfectly good 64-bit pointer in its hand, but somehow lost its mind and opted to throw away the top 32 bits.

How could something like this happen?

My guess is that this code started out as perfectly good 32-bit code:

HWND hwndButton = GetDlgItem(hdlg, ID_BUTTON);
SetWindowLong(hwndButton, GWL_WNDPROC, (LONG)g_originalWndProc);

And then they recompiled it as 64-bit code and got an error.

error C2065: 'GWL_WNDPROC': undeclared identifier

They then went back to the documentation and saw that for 64-bit Windows, GWL_WNDPROC was renamed to GWLP_WNDPROC.

So they fixed it by changing GWL_WNDPROC to GWLP_WNDPROC.

HWND hwndButton = GetDlgItem(hdlg, ID_BUTTON);
SetWindowLong(hwndButton, GWL_WNDPROC, (LONG)g_originalWndProc);

However, the point of renaming the value was not to annoy you. The point of renaming the value was to call your attention to places where pointer truncation is likely to occur. In this case, it’s the final parameter, the original 64-bit window procedure. The build break is telling you that you are probably passing a 32-bit value as something that should be 64-bit. In this case, because it was being cast to (LONG). You are expected to upgrade the GWL_WNDPROC to GWLP_WNDPROC and at the same time upgrade the cast from (LONG) to (LONG_PTR).

HWND hwndButton = GetDlgItem(hdlg, ID_BUTTON);
SetWindowLong(hwndButton, GWL_WNDPROC, (LONG_PTR)g_originalWndProc);

Now, this was likely an oversight rather than a systemic failure, because they did manage to subclass the window properly:

WNDPROC g_originalWndProc;

HWND hwndButton = GetDlgItem(hdlg, ID_BUTTON);
g_originalWndProc = (WNDPROC)SetWindowLong(hwndButton, GWLP_WNDPROC,
    (LONG_PTR)subclassWndProc);

They merely missed a spot. Perhaps the developer got distracted after fixing the symbol name and forgot to come back and fix the pointer.

Next time, we’ll look at why this bug has remained unfixed for so long.

The post Speculating on how the buggy control panel extension truncated a value that it had right in front of it appeared first on The Old New Thing.

Read the whole story
alvinashcraft
57 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Visual Studio Administrator? Join our Private Marketplace Preview!

1 Share

Organizations are increasingly looking for greater control over extensions within development environments. Driven by security, compliance, and internal governance requirements, teams want more visibility into how developers discover and acquire extensions.

To address these needs, we’re excited to begin previewing Private Marketplace support in Visual Studio.

Private Marketplace for Visual Studio

For organizations familiar with Private Marketplace in VS Code, Private Marketplace in Visual Studio provides a similar curated extension acquisition experience while preserving the familiar Visual Studio workflow.

With Private Marketplace for Visual Studio, organizations can:

  • Host and distribute private extensions within their organization
  • Centrally configure and enforce a Private Marketplace
  • Control which extensions are surfaced through the Visual Studio marketplace experience

Join the Preview

We’re looking for Visual Studio administrators, security teams, and enterprise stakeholders interested in evaluating Private Marketplace and providing feedback as we prepare for broader availability.

Interested in joining?

While our immediate focus is Private Marketplace, we’re also interested in learning more about how organizations manage extensions today, the challenges they face, and the governance capabilities that matter most to them.

Whether you’re interested in Private Marketplace specifically or want to discuss your organization’s extension management and governance needs, we’d love to hear from you.

 

The post Visual Studio Administrator? Join our Private Marketplace Preview! appeared first on Visual Studio Blog.

Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete

Building a React Sankey Diagram to Visualize California’s Energy Flow

1 Share

Building a React Sankey Diagram to Visualize California’s Energy Flow

TL;DR: Complex data flows are often difficult to understand when hidden in spreadsheets or traditional charts. See how a React Sankey Diagram transforms California’s energy data into an interactive visualization, helping you uncover flow patterns, energy losses, and key insights with validation, tooltips, responsive layouts, and export support.

Imagine you’re reviewing an energy report and trying to answer a simple question:

Where does the energy actually go?

You may have the numbers, but tables and traditional charts often make it difficult to follow how energy moves through the system. A bar chart can compare values, but it can’t easily show how those values split, combine, or eventually reach their destination.

This is exactly the type of problem that a Sankey Diagram solves.

A Sankey Diagram visualizes movement between connected stages. The width of each connection represents the quantity being transferred, allowing viewers to immediately identify major contributors, distribution patterns, and losses throughout a process.

In this tutorial, we’ll use a simplified California energy dataset to build a React Sankey Diagram with Syncfusion. While the data is intentionally simplified, the implementation approach is the same one you can use in production dashboards, reporting systems, analytics portals, or operational monitoring applications.

By the end, you’ll have a reusable React component that makes complex flow-based data significantly easier to understand.

What you’ll build

We’ll create an interactive Sankey Diagram that shows:

  • Energy originating from sources such as Solar, Wind, Nuclear, Geothermal, Biomass, Coal, Petroleum, and Natural Gas.
  • Energy flowing into Electricity Generation.
  • Distribution across Residential, Commercial, Industrial, and Transportation sectors.
  • Final allocation into Energy Services and Rejected Energy.
  • Source-colored links for easier visual tracking.
  • Hover tooltips and visible node labels.
  • A responsive layout that adapts to different screen sizes.
  • Built-in printing and PNG export options.
  • Data validation that detects:
    • Duplicate node IDs,
    • Broken source or destination references, and
    • Invalid flow values.

The final result isn’t just a demo visualization; it’s a foundation you can extend for reporting, operations monitoring, and analytics applications.

When a Sankey Diagram makes sense

A Sankey Diagram works best when the primary goal is understanding how something moves through a process.

Instead of focusing on comparisons or trends, it helps answer questions such as:

  • Where do the largest inputs come from?
  • How is a resource distributed?
  • Where do losses or bottlenecks occur?
  • Which paths carry the most volume?

For scenarios involving movement, allocation, or transformation of data, resources, or energy, a Sankey Diagram often communicates relationships more effectively than traditional charts.

Tip: If you’re comparing categories, use a bar chart. If you’re showing changes over time, use a line chart. Sankey Diagrams are most useful when the flow itself is the story.

Why use Syncfusion for a React Sankey Diagram?

You can build a Sankey Diagram from scratch using D3 or SVG, which gives you complete control over the visualization. However, that flexibility comes with the responsibility of maintaining the rendering logic, interactions, and responsive behavior yourself.

Syncfusion React Sankey Diagram offers a component-based alternative that helps you go from structured data to a production-ready visualization much faster. It includes built-in support for labels, legends, tooltips, responsiveness, printing, and exporting, reducing the amount of code you need to build and maintain.

Choose Syncfusion when:

  • You want to quickly transform data into a reusable dashboard component.
  • Your application already uses Syncfusion React components and benefits from a consistent look and feel across the UI.
  • You prefer a ready-made solution that includes common visualization features out of the box.

A custom D3 or SVG implementation may be a better fit only when your application requires a highly specialized layout or unique interactions that are not available through the component API.

Prerequisites

Before you begin, make sure you have Node.js installed, an existing React project, and a basic understanding of React and TypeScript.

Visualizing California’s energy flow pattern using a React Sankey Diagram

Now that the project setup is ready, let’s start building the diagram itself.

We’ll use a simplified California energy dataset to keep the example focused on the implementation rather than the data. Along the way, we’ll define the data structure, add a validation layer to catch common mistakes, and then render the complete Sankey Diagram with labels, tooltips, legends, printing, and export capabilities.

Step 1: Install the Syncfusion package

To get started, install the Syncfusion React Charts package:

npm install @syncfusion/ej2-react-charts --save

This package includes the React Sankey Diagram component along with supporting services for features such as tooltips, legends, and exporting.

Step 2: Understand the Sankey data model

Before moving into the chart configuration, it’s helpful to understand how Sankey data is organized.

Every Sankey Diagram is built from two core pieces:

  • Nodes represent the entities in your system.
  • Links represent the amount moving between those entities.

In our example, energy sources such as Solar and Natural Gas are nodes. The energy flowing between those sources and other stages in the system is represented by links.

Once you understand these two building blocks, creating and troubleshooting Sankey Diagrams becomes much easier.

Each node must have a unique id (string). You can also use offset (number) to adjust its vertical position and color (string) to customize its appearance.

Each link connects two nodes and requires a sourceId (string), targetId (string), and value (number). The source and target IDs must match existing node IDs, while the value determines the thickness of the link.

Refer to the following image for a better understanding.

Sankey Diagram nodes and links visualized as connected stages of flow
Sankey Diagram nodes and links visualized as connected stages of flow

Important: Every sourceId and targetId must match a node id exactly. The strings are case-sensitive, so “Natural Gas” and “natural gas” are treated as two different node references.

Step 3: Prepare the California energy-flow dataset

For this tutorial, we’ll use a simplified version of a California energy-flow model.

The dataset is intentionally structured to mirror how energy moves through a real system. Energy starts at primary sources such as Solar, Wind, Petroleum, and Natural Gas. Some of that energy passes through Electricity Generation before reaching end-use sectors such as Residential, Commercial, Industrial, and Transportation. Finally, the flow is divided into useful output and energy losses.

This structure provides sufficient complexity to demonstrate how Sankey Diagrams handle branching paths, aggregation points, and losses without introducing unnecessary noise in the example.

Dataset note: The values used here have been simplified for demonstration purposes. Lawrence Livermore National Laboratory (LLNL) publishes detailed state-level energy-flow charts. If you’re building a production solution, replace these values with official data and reference the appropriate chart year.

Node data

type EnergyNode = {
  id: string;
  offset?: number;
  color?: string;
};

type EnergyLink = {
  sourceId: string;
  targetId: string;
  value: number;
};

const nodes: EnergyNode[] = [
  { id: 'Solar', offset: 20, color: '#FDB462' },
  { id: 'Nuclear', offset: 40, color: '#80B1D3' },
  { id: 'Wind', offset: 50, color: '#BEBADA' },
  { id: 'Geothermal', offset: 60, color: '#8DD3C7' },
  { id: 'Natural Gas', offset: 80, color: '#FB8072' },
  { id: 'Coal', offset: 100, color: '#8C8C8C' },
  { id: 'Biomass', offset: 110, color: '#B3DE69' },
  { id: 'Petroleum', offset: -10, color: '#BC80BD' },
  { id: 'Electricity Generation', offset: -120, color: '#FFD92F' },
  { id: 'Residential', offset: 38, color: '#A6CEE3' },
  { id: 'Commercial', offset: 36, color: '#1F78B4' },
  { id: 'Industrial', offset: 34, color: '#33A02C' },
  { id: 'Transportation', offset: 32, color: '#E31A1C' },
  { id: 'Rejected Energy', offset: -40, color: '#BDBDBD' },
  { id: 'Energy Services', color: '#4DAF4A' }
];

Link data

const links: EnergyLink[] = [
  { sourceId: 'Solar', targetId: 'Electricity Generation', value: 454 },
  { sourceId: 'Nuclear', targetId: 'Electricity Generation', value: 185 },
  { sourceId: 'Wind', targetId: 'Electricity Generation', value: 47.8 },
  { sourceId: 'Geothermal', targetId: 'Electricity Generation', value: 40 },
  { sourceId: 'Natural Gas', targetId: 'Electricity Generation', value: 800 },
  { sourceId: 'Coal', targetId: 'Electricity Generation', value: 28.7 },
  { sourceId: 'Biomass', targetId: 'Electricity Generation', value: 50 },
  { sourceId: 'Electricity Generation', targetId: 'Residential', value: 182 },
  { sourceId: 'Electricity Generation', targetId: 'Commercial', value: 351 },
  { sourceId: 'Electricity Generation', targetId: 'Industrial', value: 641 },
  { sourceId: 'Electricity Generation', targetId: 'Transportation', value: 20 },
  { sourceId: 'Electricity Generation', targetId: 'Rejected Energy', value: 411.5 },
  { sourceId: 'Natural Gas', targetId: 'Residential', value: 400 },
  { sourceId: 'Natural Gas', targetId: 'Commercial', value: 300 },
  { sourceId: 'Natural Gas', targetId: 'Industrial', value: 786 },
  { sourceId: 'Natural Gas', targetId: 'Transportation', value: 51 },
  { sourceId: 'Biomass', targetId: 'Industrial', value: 563 },
  { sourceId: 'Biomass', targetId: 'Transportation', value: 71 },
  { sourceId: 'Petroleum', targetId: 'Residential', value: 50 },
  { sourceId: 'Petroleum', targetId: 'Industrial', value: 300 },
  { sourceId: 'Petroleum', targetId: 'Transportation', value: 2486 },
  { sourceId: 'Residential', targetId: 'Rejected Energy', value: 432 },
  { sourceId: 'Residential', targetId: 'Energy Services', value: 200 },
  { sourceId: 'Commercial', targetId: 'Rejected Energy', value: 351 },
  { sourceId: 'Commercial', targetId: 'Energy Services', value: 300 },
  { sourceId: 'Industrial', targetId: 'Rejected Energy', value: 1535 },
  { sourceId: 'Industrial', targetId: 'Energy Services', value: 755 },
  { sourceId: 'Transportation', targetId: 'Rejected Energy', value: 1991 },
  { sourceId: 'Transportation', targetId: 'Energy Services', value: 637 }
];

Step 4: Validate the data before rendering

If you’ve ever spent time debugging a chart that refuses to render, you already know that data issues are often the culprit.

A single typo in a node ID, a missing reference, or an invalid value can silently break the visualization. These problems are easy to introduce, especially when chart data comes from APIs, spreadsheets, or transformed datasets.

To avoid that frustration, let’s add a small validation step before rendering. The following helper function checks for:

  • Duplicate node IDs,
  • Invalid source or target references,
  • Missing, zero, or negative values.

Refer to the following code example.

function validateSankeyData(nodes: EnergyNode[], links: EnergyLink[]) {
  const nodeIds = new Set(nodes.map((node) => node.id));

  const duplicateIds = nodes
    .map((node) => node.id)
    .filter((id, index, array) => array.indexOf(id) !== index);

  if (duplicateIds.length > 0) {
    return `Duplicate node IDs found: ${duplicateIds.join(', ')}`;
  }

  const invalidLink = links.find(
    (link) =>
        !nodeIds.has(link.sourceId) ||
        !nodeIds.has(link.targetId) ||
        typeof link.value !== 'number' ||
        link.value <= 0
  );

  return invalidLink ? `Invalid Sankey link found: ${JSON.stringify(invalidLink)}` : null;
}

However, it does not replace full data-quality checks, such as:

  • Balance validation,
  • Circular-flow detection, or
  • Source-data auditing.

But it does catch the kinds of mistakes that commonly lead to broken visualizations and unnecessary debugging sessions.

Step 5: Render the React Sankey Diagram

With the dataset prepared and validated, we can finally render the diagram.

The component below brings everything together. It validates the dataset, renders the Sankey Diagram, enables tooltips and legends, and adds export and print actions, allowing the chart to be used in both interactive dashboards and reporting scenarios.

import React, { useRef } from 'react';
import {
    SankeyComponent,
    SankeyNodesCollectionDirective,
    SankeyNodeDirective,
    SankeyLinksCollectionDirective,
    SankeyLinkDirective,
    Inject,
    SankeyTooltip,
    SankeyLegend,
    SankeyExport
} from '@syncfusion/ej2-react-charts';

// Include the EnergyNode, EnergyLink, validateSankeyData, nodes, and links
// declarations from the earlier sections in the same file, or import them
// from a separate data module.

export default function CaliforniaEnergySankey() {
    const sankeyRef = useRef<SankeyComponent | null>(null);
    const validationError = validateSankeyData(nodes, links);

    const exportAsPng = () => {
        sankeyRef.current?.export?.('PNG', 'california-energy-sankey');
    };

    const printChart = () => {
        sankeyRef.current?.print?.();
    };

    if (validationError) {
        return <div role="alert">{validationError}</div>;
    }

    return (
        <section
            role="region"
            aria-label="California energy flow Sankey chart"
            aria-describedby="california-energy-sankey-description">
            <p id="california-energy-sankey-description">
                This Sankey chart shows energy moving from primary sources through
                electricity generation and end-use sectors into energy services and
                rejected energy. The values are simplified for this tutorial.
            </p>

            <div style={{ marginBottom: '12px' }}>
                <button type="button" onClick={exportAsPng}>
                    Export as PNG
                </button>
                <button
                    type="button"
                    onClick={printChart}
                    style={{ marginLeft: '8px' }}
                >
                    Print
                </button>
            </div>

            <SankeyComponent
                ref={sankeyRef}
                id="california-energy-sankey"
                width="100%"
                height="560px"
                title="California Energy Flow Example"
                subTitle="Tutorial dataset adapted from LLNL energy-flow concepts"
                linkStyle={{
                    opacity: 0.65,
                    curvature: 0.55,
                    colorType: 'Source'
                }}
                labelSettings={{ visible: true, fontSize: 12 }}
                tooltip={{ enable: true }}
                legendSettings={{
                    visible: true,
                    position: 'Bottom',
                    itemPadding: 8
                }}
            >
                <Inject
                    services={[
                        SankeyTooltip,
                        SankeyLegend,
                        SankeyExport
                    ]}/>

                <SankeyNodesCollectionDirective>
                    {nodes.map((node) => (
                        <SankeyNodeDirective
                            key={node.id}
                            id={node.id}
                            offset={node.offset}
                            color={node.color}/>
                    ))}
                </SankeyNodesCollectionDirective>

                <SankeyLinksCollectionDirective>
                    {links.map((link, index) => (
                        <SankeyLinkDirective
                            key={`${link.sourceId}-${link.targetId}-${index}`}
                            sourceId={link.sourceId}
                            targetId={link.targetId}
                            value={link.value}/>
                    ))}
                </SankeyLinksCollectionDirective>
            </SankeyComponent>
        </section>
    );
}

Refer to the following image.

React Sankey Diagram with labels, source-colored links, legend, and tooltips
Visualizing California’s energy flow data using the React Sankey Diagram

Step 6: Customize the Sankey Diagram for better readability

At this point, the chart is functional, but a few small adjustments can make it much easier to read, especially as the dataset grows.

For production use, consider the following improvements:

  • Reduce node overlaps by using the offset property to adjust the vertical position of closely placed nodes.
    { id: 'Residential', offset: 38 }
    { id: 'Commercial', offset: 36 }
    { id: 'Industrial', offset: 34 }
  • Apply source-based link colors by setting colorType to Source. This helps users follow flows more easily. The opacity and curvature properties control link transparency and shape.
    linkStyle={{ opacity: 0.65, curvature: 0.55, colorType: 'Source' }}
  • Keep labels visible so values and flow paths remain easy to understand. Enable tooltips to display additional flow details during interactions and add a legend below the diagram to help users identify categories and node colors.
    labelSettings={{ visible: true, fontSize: 12 }}
    tooltip={{ enable: true }}
    legendSettings={{ visible: true, position: 'Bottom', itemPadding: 8 }}

See the following image for more information.

Customizing the React Sankey Diagram
Customizing the React Sankey Diagram

In addition to improving readability, you can make the chart easier to share and analyze by enabling printing and export capabilities. Use the Sankey component reference to export the diagram as a PNG image or open the browser’s print interface. Ensure that SankeyExport is injected into the component.

<div style={{ width: '100%', height: '560px' }}> 
  <CaliforniaEnergySankey /> 
</div> 

const exportAsPng = () => { 
  sankeyRef.current?.export?.('PNG', 'california-energy-sankey'); 
}; 
 
const printChart = () => { 
  sankeyRef.current?.print?.(); 
};

Note: JPEG, SVG, and PDF export formats may also be available. Verify support in the specific Syncfusion package version used by your application before enabling it in production.

Step 7: Load data from JSON or an API

The sample data in this tutorial is hardcoded for simplicity, but most production applications load chart data from a service or API.

A good practice is to keep the visualization component separate from the data retrieval logic. Fetch the data, validate it, and render the chart only after it’s ready.

type EnergyFlowResponse = {
  nodes: EnergyNode[];
  links: EnergyLink[];
};

async function loadEnergyFlowData(): Promise<EnergyFlowResponse> {
  const response = await fetch('/data/california-energy-flow.json');

  if (!response.ok) {
    throw new Error('Unable to load energy-flow data.');
  }

  return response.json();
}

If you’re working with remote data, consider adding:

  • A loading state while data is being fetched.
  • An error state when requests fail.
  • Validation before rendering.
  • Memoization for larger datasets to avoid unnecessary recalculation during re-renders.

These small additions can make a noticeable difference in performance and maintainability as the application evolves.

Common issues and fixes

Most Sankey chart issues are typically related to data quality, component configuration, or sizing.

  • Missing links or tooltips: Verify that node references match exactly and that all required services are injected.
  • Overlapping or clipped content: Increase the chart or container height, and adjust node offsets, label size, padding, or overflow styles.
  • Inconsistent totals: Validate input and output values at each stage of the flow to ensure data accuracy.
  • Blank chart in hidden tabs: Refresh the chart after the tab becomes visible.
  • Print or export not working: Confirm that the component reference is available before calling print or export methods.

Once your chart is working as expected, it’s important to ensure that it’s accessible to all users.

Accessibility considerations

  • Keep labels visible whenever possible to help users understand the flow of data.
  • Avoid relying solely on color to communicate meaning, as some users may have difficulty distinguishing colors.
  • Provide a tabular view of the data alongside the chart to improve accessibility and make the information easier to consume.

Other use cases

Beyond energy data, Sankey Diagrams are useful whenever you need to explain how something moves through a system.

For example:

  • Tracking users through a signup funnel.
  • Visualizing API request routing across microservices.
  • Understanding cloud cost allocation across teams.
  • Mapping warehouse inventory movement.
  • Showing how support tickets flow between departments.
  • Analyzing ETL pipelines and data movement.

A common real-world example is cloud cost reporting. Teams often know their total spending but not how it is distributed across services, environments, and business units. A Sankey Diagram makes those relationships obvious within seconds.

Frequently Asked Questions

How do I debug missing links in a React Sankey Diagram?

Ensure that every sourceId and targetId matches a valid node id. Because node references are case-sensitive, even minor spelling differences can prevent links from rendering.

How do I export a React Sankey Diagram?

Create a component ref and call the export() method. Also, ensure that the SankeyExport service is injected into the React Sankey Diagram.

Can I use API data in a React Sankey Diagram?

Yes. Load the API data, map it to nodes and links, validate it, and then render the React Sankey Diagram after the data is ready.

Is the California energy-flow data used in this React Sankey Diagram official?

No. This React Sankey Diagram uses a simplified sample dataset. For production use, replace it with official data and cite the original source and publication year.

Explore the endless possibilities with Syncfusion’s outstanding React UI components.

Turning complex data flows into visualizations people can actually understand

Building a Sankey Diagram isn’t just about creating a more attractive chart. It’s about helping users understand how resources, transactions, requests, or energy move through a system.

In this example, we used California energy data to visualize how energy is generated, distributed, and ultimately consumed or lost. The same implementation pattern works for business analytics, cloud-cost reporting, API traffic analysis, logistics tracking, and many other scenarios where understanding movement is more important than comparing static values.

If you’re already using Syncfusion in your React applications, the Sankey Diagram component offers a practical way to add interactive flow visualizations without having to maintain custom rendering logic. You can explore additional capabilities in the latest version of Essential Studio® through the License and Downloads page or try the components with a 30-day free trial.

For any questions or assistance, feel free to reach out to us through our support forumsupport portal, or feedback portal. We’re always here to help. Happy coding!

Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete

Database Animations: How Index Seeks Work

1 Share

In my free How to Think Like the Engine class, I gloss over the entire concept of B-trees and just hand-wavily say “SQL Server can seek to the page that has the row you’re looking for.” That’s always kinda bothered me, so I finally gave in to temptation and whipped up an animated example of a clustered index on the Users table:

Btree Index Seek (animation)
▶ Watch the animated version of Btree Index Seek

Let’s break down what’s happening.

It Starts with the Root Page at the Top.

Every index has a single 8KB page at the top of the B-tree, and it’s kinda like the table of contents.

It annoys the bejeezus out of me that every B-tree diagram I’ve ever seen is always shaped like a pyramid, with the “root page” at the top. Do database people ever actually touch grass?!? The root is down deep in the earth, party people. It’s not called a B-pyramid. Whatever. I didn’t wanna fight convention and I just stuck with it, with the root at the top.

In this case, the root page is in data file #1, and it’s the 100th 8KB page in the file, thus the label 1:100. SQL Server pages are always labeled like that – and the rest of the pages in the diagram all start with 1: for that reason. You can tell this index lives in the 1st data file, and that our database (like most) probably only has one data file, since everything is in file 1.

When our query runs, and SQL Server decides to use this index to get the data, the first thing it has to do is open up that root page. We’re looking for Id 12345, so SQL Server looks at the root page to ask, “Which leaf page has row 12345?” The root page itself doesn’t know that in this case – although it could, in much smaller tables – but here, we’ve got enough rows that the root page needs to point to other directory pages.

The root page knows that if it’s looking for Ids 1-500,000, that’s on page 1:200. In our case, those numbers are nice and round, but they would never be that round in real life, because your tree isn’t going to be this balanced, and you can fit oddball numbers of rows on pages. More on that over the coming weeks. (Don’t wanna overwhelm you with diagrams today.) So our process pops over to page 1:200 in order to keep tracking down our row.

The Intermediate Pages are Like Tour Guides.

The root page, like all the other pages, is only 8KB. It can’t fit a complete directory of the ranges of every value on every 8KB page in the Users table, all on one 8KB page. You can only write so small on a grain of sand. So rather than pointing directly at the specific 8KB data page that holds Id 12345, it has to point at another directory page, called an intermediate page.

I'll be your tour guideThe middle two sets of pages on our fancy diagram are intermediate pages, which serve as further directories. “Oh, you’re looking for ladies’ intimates? No judgment, sir, head over in that direction over there. Yes, yes of course it’s a gift, no need to explain.”

The more data pages your object has, and the fewer rows you can fit on each data page, the more levels of intermediate trees you’re going to need in order to go from the root page down to the data page. These page reads are considered part of your logical reads: while they’re cached in memory, SQL Server has to keep popping them open for every seek that it does. This is why you’ll see a single row index seek take a whole handful of logical reads, sometimes more, on larger tables: it takes that long to traverse the tree.

The Data Page is the Finish Line.

Finally, on intermediate page 1:411, we’re able to see that rows from 12,001 to 16,000 are stored on page 1:301, and we’re able to open the page that actually has the data we’re looking for.

The pages with the actual data are called leaves, and the leaves are at the bottom of the diagram, on the ground, because they’re computer science professors, not biologists. Or human beings.

Nonclustered Indexes Work the Same Way

Say we have a nonclustered index on the Location column, and we wanna find the people who live in Helsinki:

Btree Index Seek Location (animation)
▶ Watch the animated version of Btree Index Seek Location

Now instead of looking for a particular number, we’re looking for a string, and these strings are organized in alphabetical order, so essentially it works the same as looking for a number. Helsinki is alphabetically between Geneva and Jakarta, so the intermediate tour guide pages direct us towards page 1:931.

Here’s where things get a little tricky: note that on the data pages, SQL Server isn’t storing the pages where the two people in Helsinki live. Instead, it lists their Id values. Our table has a clustered index on Id, so now when we want to do a key lookup, we’re going back to the top of this blog post, and we’re doing a clustered index seek on their Ids.

Essentially, an index seek + a key lookup = two index seeks: one on the nonclustered index, and one on the clustered index for the key lookup. Each index (the clustered and each nonclustered index) has its own root page and intermediate pages.

You might be thinking, “Wait, couldn’t we save a lot of time by, on the nonclustered leaf pages, saving the file_number:page_number where the corresponding clustered index row lives?” Well, you could save time on reads, but then you would spend a lot of time updating all of the indexes whenever we had to move a clustered index row around from one page to another. More on that in another post.

This Animated Diagram Has a Lot of Implications.

For example, look at the animation again, this time focusing on the page numbers. They’re scattered all over the file, and that’s completely fine. There’s no reason whatsoever that all these pages have to live next to each other in the data file. The index pages up at the top are very likely cached in RAM anyway, and RAM isn’t short for RAMEN. The R has a meaning, dear reader. Computers don’t need these pages next to each other in order to access them quickly.

This isn’t the only way to access the leaf pages, either. If you know you’re gonna hit all of them, you can start at either end, and read from one leaf page to the next. The leaf pages are doubly linked lists: every page has a pointer to the previous page and the next page, links if you will, so that you can keep paging down through the table, scanning it, without dealing with the intermediate pages.

These pointers also help when you need to read ranges of data. For example, if you want the Ids between 9500 and 13800, you can do a seek to 9500, and then jump from page to page without going back up the tree:

Btree Leaf Linked List (animation)
▶ Watch the animated version of Btree Leaf Linked List

Like These Animations?

You’re gonna love my Fundamentals training classes. In Fundamentals of Index Tuning 2026, I use animations like these to explain composite indexes, page splits, index reorganization & rebuilds, b-tree hotspots, and more. The live enrollments are closed now because the classes are underway (literally, I’m teaching Fundamentals of Query Tuning today), but you can stream the recordings for $495.

And if you’re already a subscriber, good news: the updated Fundamentals of Index Tuning 2026 is already watchable in your account! Get in there and take advantage of the training you paid for. Or your manager paid for. Or your last manager, if you’re the kind of person who steals staplers from the office, which I wholeheartedly endorse.

Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories