from __future__ import annotations
from typing import Optional
from lightningchart import conf, Themes
from lightningchart.charts import ChartWithCursor2D, ChartsWithAddEventListener, ChartsWithCoordinateTransforms, GeneralMethods, TitleMethods, Chart
from lightningchart.instance import Instance
from lightningchart.utils import convert_to_dict, convert_color_to_hex
from lightningchart.ui import UserInteractions
from lightningchart.utils.utils import ColorInput, LegendOptions, apply_post_legend_config, build_legend_config
[docs]
class TreeMapChart(GeneralMethods, TitleMethods, UserInteractions, ChartsWithCoordinateTransforms, ChartWithCursor2D, ChartsWithAddEventListener):
"""TreeMap Chart for visualizing hierarchical data."""
def __init__(
self,
data: list[dict] = None,
theme: Themes = Themes.Light,
theme_scale: float = 1.0,
title: str = None,
license: str = None,
license_information: str = None,
html_text_rendering: bool = True,
legend: Optional[LegendOptions] = None,
):
"""A TreeMapChart with optional data and configurations.
Args:
data (list[dict]): Initial data for the TreeMap.
theme (Themes): Chart theme (Themes.Light, Themes.DarkGold, etc.).
theme_scale (float): Scale factor for fonts, ticks, padding (default: 1.0).
title (str): Chart title.
license (str): License key.
license_information (str): License information.
html_text_rendering (bool): Sharper text display with performance cost.
legend (dict): Legend configuration dictionary with the following options:
visible (bool): Show/hide legend.
position: Position (TopRight, RightCenter, etc.).
title (str): Legend title text.
title_font (dict): Title font settings
title_fill_style: Title color/fill style
orientation: Horizontal or Vertical orientation.
render_on_top (bool): Render above chart (default: False).
background_visible (bool): Show legend background.
background_fill_style (str): Background color ("#ff0000").
background_stroke_style (dict): Border style {'thickness': 2, 'color': '#000'}.
padding (int | dict): Padding around legend content.
margin_inner (int): Space between chart and legend.
margin_outer (int): Space from legend to chart edge.
entry_margin (int): Space between legend entries.
auto_hide_threshold (float): Auto-hide when legend takes >X of chart (0.0-1.0).
add_entries_automatically (bool): Auto-add series to legend.
entries (dict): Default styling for all legend entries with options:
button_shape (str): 'Arrow', 'Diamond', 'Plus', 'Triangle', 'Circle', 'Square', 'Cross', 'Minus' and 'Star'.
button_size (int | dict): Size in pixels or {'x': 20, 'y': 15}.
button_fill_style (str): Button color ("#ff0000").
button_stroke_style (dict): Button border {'thickness': 1, 'color': '#000'}.
button_rotation (float): Button rotation in degrees.
text (str): Override default series name.
text_font (dict): Font settings {'size': 16, 'family': 'Arial', 'weight': 'bold'}.
text_fill_style (str): Text color ("#000000").
show (bool): Show/hide this entry.
match_style_exactly (bool): Match series style exactly vs simplified.
highlight (bool): Whether highlighting on hover is enabled.
lut: LUT element for legends (None to disable).
lut_length (int): LUT bar length for heatmap legends.
lut_thickness (int): LUT bar thickness for heatmap legends.
lut_display_proportional_steps (bool): LUT step display mode.
Returns:
Reference to TreeMapChart class.
Examples:
Basic chart with simple legend
>>> chart = lc.TreeMapChart(
... title='My Chart',
... legend={
... 'visible': True,
... 'position': 'RightCenter',
... 'title': "Data Series"
... }
... )
Styled legend with background and custom entries
>>> chart = lc.TreeMapChart(
... title='Styled Chart',
... legend={
... 'visible': True,
... 'position': 'RightCenter',
... 'background_visible': True,
... 'background_fill_style': "#e01212",
... 'background_stroke_style': {'thickness': 3, 'color': '#003300'},
... 'entries': {
... 'button_shape': 'Circle',
... 'button_size': 20,
... 'text_font': {'size': 16},
... 'text_fill_style': "#000080"
... }
... }
... )
Custom positioned legend
>>> chart = lc.TreeMapChart(
... title='Custom Legend',
... legend={
... 'position': 'RightCenter',
... 'orientation': 'Horizontal',
... 'render_on_top': True,
... 'padding': 15,
... 'margin_inner': 10
... }
... )
"""
instance = Instance()
Chart.__init__(self, instance)
legend_config = build_legend_config(legend)
self.instance.send(
self.id,
'treeMapChart',
{
'theme': theme.value,
'scaleTheme': theme_scale,
'license': license or conf.LICENSE_KEY,
'licenseInformation': license_information or conf.LICENSE_INFORMATION,
'htmlTextRendering': html_text_rendering,
'legendConfig': legend_config,
},
)
if title:
self.set_title(title)
if data:
self.set_data(data)
apply_post_legend_config(self, legend)
[docs]
def set_data(self, data: list[dict]):
"""Set data for the TreeMap chart.
Args:
data: List of hierarchical node dicts, e.g.
{'name': str, 'value': number, 'children': [ ... ]}.
Returns:
The instance of the class for fluent interface.
"""
data = convert_to_dict(data)
self.instance.send(self.id, 'setData', {'data': data})
return self
[docs]
def set_displayed_levels_count(self, level: int):
"""Set the amount of levels of children nodes to display.
Args:
level: Amount of levels to display.
Returns:
The instance of the class for fluent interface.
"""
self.instance.send(self.id, 'setDisplayedLevelsCount', {'level': level})
return self
[docs]
def set_init_path_button_text(self, text: str):
"""Set the text for the back button that returns to the 1st level of Nodes.
Args:
text: Text for the button.
Returns:
The instance of the class for fluent interface.
"""
self.instance.send(self.id, 'setInitPathButtonText', {'text': text})
return self
[docs]
def set_animation_highlight(self, enabled: bool):
"""Set component highlight animations enabled or not.
Args:
enabled: Boolean flag.
Returns:
The instance of the class for fluent interface.
"""
self.instance.send(self.id, 'setAnimationHighlight', {'enabled': enabled})
return self
[docs]
def set_animation_values(self, enabled: bool, speed_multiplier: float = 1):
"""Enable/Disable animation of Nodes positions.
Args:
enabled: Boolean flag.
speed_multiplier: Optional multiplier for category animation speed. 1 matches default speed.
Returns:
The instance of the class for fluent interface.
"""
self.instance.send(
self.id,
'setAnimationValues',
{'enabled': enabled, 'speedMultiplier': speed_multiplier},
)
return self
[docs]
def set_node_coloring(
self,
steps: list[dict],
look_up_property: str = 'value',
interpolate: bool = True,
percentage_values: bool = False,
formatter_precision: int | None = None,
formatter_unit: str = '',
formatter_scale: float = 1.0,
formatter_type: str = 'standard',
formatter_operation: str = 'none',
):
"""Set the color of the nodes.
Args:
steps (list[dict]): List of {"value": number, "color": Color, 'label': 'Label'} dictionaries.
look_up_property (str): "value" | "x" | "y" | "z".
interpolate (bool): Enables automatic linear interpolation between color steps.
percentage_values (bool): Whether values represent percentages or explicit values.
formatter_precision: Decimal places for legend display.
formatter_unit: Unit suffix (e.g., "mag", "ms").
formatter_scale: Multiply values by this factor.
formatter_type: 'standard', 'compact', 'engineering', 'scientific'.
formatter_operation: 'none', 'round', 'ceil', 'floor'.
Returns:
The instance of the class for fluent interface.
"""
steps = [dict(s, color=convert_color_to_hex(s['color'])) if 'color' in s else s for s in steps]
self.instance.send(
self.id,
'setNodeColoring',
{
'steps': steps,
'lookUpProperty': look_up_property,
'interpolate': interpolate,
'percentageValues': percentage_values,
'formatter_precision': formatter_precision,
'formatter_unit': formatter_unit,
'formatter_scale': formatter_scale,
'formatter_type': formatter_type,
'formatter_operation': formatter_operation,
},
)
return self
[docs]
def set_path_label_color(self, color: ColorInput | None):
"""Set color of the path labels.
Args:
color: Color value. Use 'transparent' or None to hide.
Returns:
The instance of the class for fluent interface.
"""
color = convert_color_to_hex(color) if color is not None else None
self.instance.send(self.id, 'setPathLabelFillStyle', {'color': color})
return self
[docs]
def set_path_label_font(
self,
size: int | float,
family: str = 'Segoe UI, -apple-system, Verdana, Helvetica',
style: str = 'normal',
weight: str = 'normal',
):
"""Set the font of the path labels.
Args:
size (int | float): CSS font size. For example, 16.
family (str): CSS font family. For example, 'Arial, Helvetica, sans-serif'.
style (str): CSS font style. For example, 'italic'.
weight (str): CSS font weight. For example, 'bold'.
Returns:
The instance of the class for fluent interface.
"""
self.instance.send(
self.id,
'setPathLabelFont',
{'family': family, 'size': size, 'weight': weight, 'style': style},
)
return self
[docs]
def set_label_font(
self,
size: int | float,
family: str = 'Segoe UI, -apple-system, Verdana, Helvetica',
style: str = 'normal',
weight: str = 'normal',
):
"""Set the font of the node labels.
Args:
size (int | float): CSS font size. For example, 16.
family (str): CSS font family. For example, 'Arial, Helvetica, sans-serif'.
style (str): CSS font style. For example, 'italic'.
weight (str): CSS font weight. For example, 'bold'.
Returns:
The instance of the class for fluent interface.
"""
self.instance.send(
self.id,
'setLabelFont',
{'family': family, 'size': size, 'weight': weight, 'style': style},
)
return self
[docs]
def set_label_color(self, color: ColorInput | None):
"""Set the color of the node labels.
Args:
color: Color value. Use 'transparent' or None to hide.
Returns:
The instance of the class for fluent interface.
"""
color = convert_color_to_hex(color) if color is not None else None
self.instance.send(self.id, 'setLabelFillStyle', {'color': color})
return self
[docs]
def set_node_border_style(self, thickness: int | float, color: ColorInput | None = None):
"""Set the line style of the node border.
Args:
thickness (int | float): Thickness of the border.
color (Color): Color of the border. Use 'transparent' or None to hide.
Returns:
The instance of the class for fluent interface.
"""
color = convert_color_to_hex(color) if color is not None else None
self.instance.send(
self.id,
'setNodeBorderStyle',
{'thickness': thickness, 'color': color},
)
return self
[docs]
def set_node_effect(self, enabled: bool):
"""Set theme effect enabled on component or disabled.
Args:
enabled: Boolean flag.
Returns:
The instance of the class for fluent interface.
"""
self.instance.send(self.id, 'setNodeEffect', {'enabled': enabled})
return self
[docs]
def set_user_interactions(self, interactions=...):
"""Configure user interactions from a set of preset options.
Args:
interactions (dict or None):
- `None`: disable all interactions
- `{}` or no argument: restore default interactions
- `dict`: configure specific interactions
Examples:
# Disable all interactions:
>>> chart.set_user_interactions(None)
# Restore default interactions:
>>> chart.set_user_interactions()
>>> chart.set_user_interactions({})
"""
return super().set_user_interactions(interactions)
[docs]
def set_drill_down_node(self, node: str | list[str] | None = None):
"""Drill down to a node by name or path.
Args:
node: None to reset,
str for single node name,
list[str] for path.
Examples:
>>> chart.set_drill_down_node('TECHNOLOGY')
>>> chart.set_drill_down_node(['TECHNOLOGY', 'MSFT'])
>>> chart.set_drill_down_node(None)
Returns:
Self for chaining.
"""
self.instance.send(self.id, 'setDrillDownNode', {'node': node})
return self
[docs]
class TreeMapChartContainer(TreeMapChart):
def __init__(self, instance, container, column, row, colspan, rowspan, title, legend, theme):
Chart.__init__(self, instance)
legend_config = build_legend_config(legend)
self.instance.send(
self.id,
'createTreeMapChartContainer',
{
'theme': theme.value,
'license': conf.LICENSE_KEY,
'licenseInformation': conf.LICENSE_INFORMATION,
'container': container.id,
'column': column,
'row': row,
'colspan': colspan,
'rowspan': rowspan,
'legendConfig': legend_config,
},
)
if title:
self.instance.send(self.id, 'setTitle', {'title': title})
apply_post_legend_config(self, legend)
[docs]
def set_container(self, container_id: str):
"""
Attach this chart's engine to an existing container div.
Args:
container_id: DOM id of an existing div.
"""
self.instance.send(self.id, 'setContainer', {'containerId': container_id})
return self