A D3.js plugin that produces flame graphs from hierarchical data.

Overview

d3-flame-graph

A D3.js plugin that produces flame graphs from hierarchical data.

Flame Graph Example

If you don't know what flame graphs are, check Brendan Gregg's post.

Flame graphs are a visualization of profiled software, allowing the most frequent code-paths to be identified quickly and accurately. They can be generated using my open source programs on github.com/brendangregg/FlameGraph, which create interactive SVGs.

Brendan Gregg

Examples

Click here to check the demo, and source.

Click here to check the animated assembly demo, and source

Click here to check the simplified demo on bl.ocks.org.

Getting Started

jsdelivr CDN

Just reference the CDN hosted CSS and JS files!

">
<head>
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-flamegraph.css">
head>
<body>
  <div id="chart">div>
  <script type="text/javascript" src="https://d3js.org/d3.v7.js">script>
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-flamegraph.min.js">script>
  <script type="text/javascript">
  var chart = flamegraph()
    .width(960);

  d3.json("data.json", function(error, data) {
    if (error) return console.warn(error);
    d3.select("#chart")
      .datum(data)
      .call(chart);
  });
  script>
body>

NPM

Make sure Node and npm installed on your system.

Install the d3-flame-graph plugin.

$ npm install d3-flame-graph --save

And use it!

">
<head>
  <link rel="stylesheet" type="text/css" href="node_modules/d3-flame-graph/dist/d3-flamegraph.css">
head>
<body>
  <div id="chart">div>
  <script type="text/javascript" src="node_modules/d3/d3.js">script>
  <script type="text/javascript" src="node_modules/d3-flame-graph/dist/d3-flamegraph.js">script>
  <script type="text/javascript">
  var chart = flamegraph()
    .width(960);
  
  d3.json("data.json")
    .then((data) => {
      d3.select("#chart")
        .datum(data)
        .call(chart);
    })
    .catch(error => {
      return console.warn(error);
    });
  script>
body>

More detailed examples in the /examples directory.

Input Format

Input stack is a simple hierarchical data structure in JSON format.

", "value": , "children": [ ] } ">
{
  "name": "
     
      "
     ,
  "value": <value>,
  "children": [
    <Object>
  ]
}

The burn CLI tool can convert multiple file formats to this hierarchical data structure.

Interacting with entries

Internally, the data is transformed into a d3 hierarchy. Functions like onClick, label and zoom expose individual entries as hierarchy Nodes, which wrap the provided data and add more properties:

, "parent": , "children": [ ], "x1": , // x2 - x1 is the size of this node, as a fraction of the root. "x2": } ">
{
  "data": 
          
           ,
  "parent": 
           
            ,
  "children": [
    
            
             
  ],
  "x1": 
             
              ,  // x2 - x1 is the size of this node, as a fraction of the root.
  "x2": 
              
                } 
              
             
            
           
          

This is a breaking change from previous versions of d3-flame-graph, which were based on version 3 of the d3 library. See d3-hierarchy.

API Reference

# flamegraph()

Create a new Flame Graph.

# flamegraph.selfValue([enabled])

Defines if the plugin should use the self value logic to calculate the node value for the Flame Graph frame size. If set to true, it will assume the node value from the input callgraph represents only the internal node value, or self value, not the sum of all children. If set to false it will assume the value includes the chidren values too. Defaults to false if not explicitely set, which if the same behavior 1.x had.

# flamegraph.width([size])

Graph width in px. Defaults to 960px if not set. If size is specified, it will set the graph width, otherwise it will return the current graph width.

# flamegraph.height([size])

Graph height in px. Defaults to the number of cell rows times cellHeight if not set. If size is specified, it will set the cell height, otherwise it will return the current graph height. If minHeight is specified, and higher than the provided or calculated values, it will override height.

# flamegraph.minHeight([size])

Minumum graph height in px. If size is specified, and higher than the provided or calculated height, it will override it.

# flamegraph.cellHeight([size])

Cell height in px. Defaults to 18px if not set. If size is specified, it will set the cell height, otherwise it will return the current cell height.

# flamegraph.minFrameSize([size])

Minimum size of a frame, in px, to be displayed in the flame graph. Defaults to 0px if not set. If size is specified, it will set the minimum frame size, otherwise it will return the current minimum frame size.

# flamegraph.title([title])

Title displayed on top of graph. Defaults to empty if not set. If title is specified, it will set the title displayed on the graph, otherwise it will return the current title.

# flamegraph.tooltip([function])

Sets a tooltip for the flamegraph frames. The tooltip function should implement two methods, .show(d) and .hide(), that will be called when the tooltip should be made visible or hidden respectively. The .show method takes a single argument, which is the flamegraph frame. The d3-flame-graph package includes a simple tooltip function, flamegraph.tooltip.defaultFlamegraphTooltip().

">
<script type="text/javascript" src="d3-flamegraph-tooltip.js">script>
var tip = flamegraph.tooltip.defaultFlamegraphTooltip()
    .html(function(d) { return "name: " + d.data.name + ", value: " + d.data.value; });
flamegraph.tooltip(tip)

The tooltip is compatible with d3-tip. This was the default library until version 2.1.10.

">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.min.js">script>
var tip = d3.tip()
  .attr('class', 'd3-flame-graph-tip')
  .html(function(d) { return "name: " + d.data.name + ", value: " + d.data.value; });
flamegraph.tooltip(tip)

# flamegraph.transitionDuration([duration])

Specifies transition duration in milliseconds. The default duration is 750ms. If duration is not specified, returns the current transition duration.

See d3.duration.

# flamegraph.transitionEase([ease])

Specifies the transition easing function. The default easing function is d3.easeCubic.

See d3-ease.

# flamegraph.label([function])

Adds a function that returns a formatted label. Example:

flamegraph.label(function(d) {
    return "name: " + d.name + ", value: " + d.value;
});

# flamegraph.sort([enabled])

Enables/disables sorting of children frames. Defaults to true if not set to sort in ascending order by frame's name. If set to a function, the function takes two frames (a,b) and returns -1 if frame a is less than b, 1 if greater, or 0 if equal. If a value is specified, it will enable/disable sorting, otherwise it will return the current sort configuration.

# flamegraph.inverted([bool])

Invert the flame graph direction. A top-down visualization of the flame graph, also known as icicle plot. Defaults to false if not set. If a value is specified, it will enable/disable the inverted flame graphs direction, otherwise it will return the current inverted configuration.

# flamegraph.computeDelta([bool])

If enabled, computes delta for all nodes. Delta value of each node is a sum of its own value from the getDelta(node) function, plus its children. Defaults to false if not set. If a value is specified, it will enable/disable the delta computation, otherwise it will return the current computeDelta configuration.

# flamegraph.resetZoom()

Resets the zoom so that everything is visible.

# flamegraph.onClick([function])

Adds a function that will be called when the user clicks on a frame. Example:

flamegraph.onClick(function (d) {
    console.info("You clicked on frame "+ d.data.name);
});

If called with no arguments, onClick will return the click handler.

# flamegraph.onHover([function])

Adds a function that will be called when the user hovers on a frame. Example:

flamegraph.onHover(function (d) {
    console.info("You hovered over frame "+ d.data.name);
});

If called with no arguments, onHover will return the hover handler.

# flamegraph.setDetailsElement([element])

Sets the element that should be updated with the focused sample details text. Example:

">
<div id="details">
div>
flamegraph.setDetailsElement(document.getElementById("details"));

If called with no arguments, setDetailsElement will return the current details element.

# flamegraph.setDetailsHandler([function])

Sets the handler function that is called when the details element needs to be updated. The function receives a single paramenter, the details text to be set. Example:

let detailsHandler = function (d) { if (detailsElement) { if (d) { detailsElement.innerHTML = d } else { if (typeof searchDetails === 'function') { searchDetails() } else { detailsElement.innerHTML = '' } } } }

flamegraph.setDetailsHandler(
  function (d) {
    if (detailsElement) {
        if (d) {
            detailsElement.innerHTML = d
        } else {
            detailsElement.innerHTML = ''
        }
    }
  }
);

If not set, setDetailsHandler will default to the above function.

If called with no arguments, setDetailsHandler will reset the details handler function.

# flamegraph.setSearchHandler([function])

Sets the handler function that is called when search results are returned. The function receives a three paramenters, the search results array, the search sample sum, and root value, Example:

let searchHandler = function (searchResults, searchSum, totalValue) { searchDetails = () => { if (detailsElement) { detailsElement.innerHTML = 'search: ' + searchSum + ' of ' + totalValue + ' total samples ( ' + format('.3f')(100 * (searchSum / totalValue), 3) + '%)' } } searchDetails() }

flamegraph.setSearchHandler(
  (searchResults, searchSum, totalValue) => {
    searchDetails = () => { // searchDetails is a global variable
        if (detailsElement) {
            detailsElement.innerHTML = 'search: ' + searchSum + ' of ' + totalValue + ' total samples ( ' + format('.3f')(100 * (searchSum / totalValue), 3) + '%)'
        }
    }
    searchDetails()
  }
);

If not set, setSearchHandler will default to the above function.

If called with no arguments, setSearchHandler will reset the search handler function.

# flamegraph.setColorMapper([function])

Replaces the built-in node color hash function. Function takes two arguments, the node data structure and the original color string for that node. It must return a color string. Example:

// Purple if highlighted, otherwise the original color
flamegraph.setColorMapper(function(d, originalColor) {
    return d.highlight ? "#E600E6" : originalColor;
});

If called with no arguments, setColorMapper will reset the color hash function.

# flamegraph.setColorHue([string])

Sets the flame graph color hue. Options are warm, cold, red, orange, yellow, green and aqua.

If called with no arguments, setColorHue will reset the color hash function.

# flamegraph.setSearchMatch([function])

Replaces the built-in node search match function. Function takes three arguments, the node data structure, the search term and an optional boolean argument to ignore case during search. If the third argument is not provided, the search will be case-sensitive by default. The function must return a boolean. Example:

flamegraph.setSearchMatch(function(d, term, true) {
  // Non-regex implementation of the search function
  return d.data.name.indexOf(term) != 0;
})

If called with no arguments, setSearchMatch will return reset the search match function.

# flamegraph.merge(date)

Merges the current data with the given data.

# flamegraph.update([data])

Updates the current chart. If the data parameters is passed, replaces the current data.

# flamegraph.destroy()

Removes the flamegraph.

All API functions will return the flame graph object if no other behavior is specified in the function details.

Issues

For bugs, questions and discussions please use the GitHub Issues.

Contributing

We love contributions! But in order to avoid total chaos, we have a few guidelines.

If you found a bug, have questions or feature requests, don't hesitate to open an issue.

If you're working on an issue, please comment on it so we can assign you to it.

If you have code to submit, follow the general pull request format. Fork the repo, make your changes, and submit a pull request.

Build

This plugin uses Webpack as build system. It includes a development server with live refresh on any changes. To start it, just execute the serve npm script.

$ git clone https://github.com/spiermar/d3-flame-graph.git
$ cd d3-flame-graph
$ npm install
$ npm run serve

Template

A standalone template with all JavaScript and CSS inlined gets built at dist/templates/d3-flamegraph-base.html. It contains a placeholder /** @flamegraph_params **/ which needs to be replaced with the stacks in the format described in Input Format.

License

Copyright 2018 Martin Spier. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Owner
Martin Spier
Performance Engineer @snowflakedb. Ex-Netflix. Venture Advisor. Investor. Adventurer.
Martin Spier
Python package for the analysis and visualisation of finite-difference fields.

discretisedfield Marijan Beg1,2, Martin Lang2, Samuel Holt3, Ryan A. Pepper4, Hans Fangohr2,5,6 1 Department of Earth Science and Engineering, Imperia

ubermag 12 Dec 14, 2022
This package creates clean and beautiful matplotlib plots that work on light and dark backgrounds

This package creates clean and beautiful matplotlib plots that work on light and dark backgrounds. Inspired by the work of Edward Tufte.

Nico Schlömer 205 Jan 07, 2023
Joyplots in Python with matplotlib & pandas :chart_with_upwards_trend:

JoyPy JoyPy is a one-function Python package based on matplotlib + pandas with a single purpose: drawing joyplots (a.k.a. ridgeline plots). The code f

Leonardo Taccari 462 Jan 02, 2023
Sparkling Pandas

SparklingPandas SparklingPandas aims to make it easy to use the distributed computing power of PySpark to scale your data analysis with Pandas. Sparkl

366 Oct 27, 2022
Automate the case review on legal case documents and find the most critical cases using network analysis

Automation on Legal Court Cases Review This project is to automate the case review on legal case documents and find the most critical cases using netw

Yi Yin 7 Dec 28, 2022
100 Days of Code The Complete Python Pro Bootcamp for 2022

100-Day-With-Python 100 Days of Code - The Complete Python Pro Bootcamp for 2022. In this course, I spend with python language over 100 days, and I up

Rajdip Das 8 Jun 22, 2022
Apache Superset is a Data Visualization and Data Exploration Platform

Apache Superset is a Data Visualization and Data Exploration Platform

The Apache Software Foundation 49.9k Jan 02, 2023
3D Vision functions with end-to-end support for deep learning developers, written in Ivy.

Ivy vision focuses predominantly on 3D vision, with functions for camera geometry, image projections, co-ordinate frame transformations, forward warping, inverse warping, optical flow, depth triangul

Ivy 61 Dec 29, 2022
Geospatial Data Visualization using PyGMT

Example script to visualize topographic data, earthquake data, and tomographic data on a map

Utpal Kumar 2 Jul 30, 2022
Simple implementation of Self Organizing Maps (SOMs) with rectangular and hexagonal grid topologies

py-self-organizing-map Simple implementation of Self Organizing Maps (SOMs) with rectangular and hexagonal grid topologies. A SOM is a simple unsuperv

Jonas Grebe 1 Feb 10, 2022
基于python爬虫爬取COVID-19爆发开始至今全球疫情数据并利用Echarts对数据进行分析与多样化展示。

COVID-19-Epidemic-Map 基于python爬虫爬取COVID-19爆发开始至今全球疫情数据并利用Echarts对数据进行分析与多样化展示。 觉得项目还不错的话欢迎给一个star! 项目的源码可以正常运行,各个库的版本、数据库的建表语句、运行过程中遇到的坑以及解决方式在笔记.md中都

31 Dec 15, 2022
PyPassword is a simple follow up to PyPassphrase

PyPassword PyPassword is a simple follow up to PyPassphrase. After finishing that project it occured to me that while some may wish to use that option

Scotty 2 Jan 22, 2022
The repository is my code for various types of data visualization cases based on the Matplotlib library.

ScienceGallery The repository is my code for various types of data visualization cases based on the Matplotlib library. It summarizes the code and cas

Warrick Xu 2 Apr 20, 2022
A small timeseries transformation API built on Flask and Pandas

#Mcflyin ###A timeseries transformation API built on Pandas and Flask This is a small demo of an API to do timeseries transformations built on Flask a

Rob Story 84 Mar 25, 2022
Open-questions - Open questions for Bellingcat technical contributors

Open questions for Bellingcat technical contributors These are difficult, long-term projects that would contribute to open source investigations at Be

Bellingcat 234 Dec 31, 2022
A little word cloud generator in Python

Linux macOS Windows PyPI word_cloud A little word cloud generator in Python. Read more about it on the blog post or the website. The code is tested ag

Andreas Mueller 9.2k Dec 30, 2022
Pyan3 - Offline call graph generator for Python 3

Pyan takes one or more Python source files, performs a (rather superficial) static analysis, and constructs a directed graph of the objects in the combined source, and how they define or use each oth

Juha Jeronen 235 Jan 02, 2023
JupyterHub extension for ContainDS Dashboards

ContainDS Dashboards for JupyterHub A Dashboard publishing solution for Data Science teams to share results with decision makers. Run a private on-pre

Ideonate 179 Nov 29, 2022
📊 Extensions for Matplotlib

📊 Extensions for Matplotlib

Nico Schlömer 519 Dec 30, 2022