Source code for lightningchart.series.heatmap_grid_series

from __future__ import annotations
from typing import Optional

try:
    import numpy as np
except ImportError:
    np = None

from lightningchart.charts import Chart
from lightningchart.ui.axis import Axis
from lightningchart.series import (
    ComponentWithPaletteColoring,
    SeriesWithAddEventListener,
    SeriesWithCursor,
    SeriesWithIntensityInterpolation,
    SeriesWithWireframe,
    SeriesWithClear,
    SeriesWithDrawOrder,
    SeriesWithXYAxes,
)
from lightningchart.utils.utils import LegendOptions, build_series_legend_options, convert_color_to_hex, convert_to_list, convert_to_matrix


[docs] class HeatmapGridSeries( ComponentWithPaletteColoring, SeriesWithIntensityInterpolation, SeriesWithWireframe, SeriesWithClear, SeriesWithDrawOrder, SeriesWithAddEventListener, SeriesWithXYAxes, SeriesWithCursor, ): """Series for visualizing 2D heatmap data in a grid.""" def __init__( self, chart: Chart, columns: int, rows: int, data_order: str = 'columns', automatic_color_index: int = None, heatmap_data_type: str = 'intensity', axis_x: Axis = None, axis_y: Axis = None, legend: Optional[LegendOptions] = None, max_tile_size: int = None, ): super().__init__(chart, axis_x, axis_y) legend_options = build_series_legend_options(legend) self.instance.send( self.id, 'heatmapGridSeries', { 'chart': self.chart.id, 'columns': columns, 'rows': rows, 'dataOrder': data_order, 'automaticColorIndex': automatic_color_index, 'heatmapDataType': heatmap_data_type, 'axisX': axis_x, 'axisY': axis_y, 'legend': legend_options if legend_options else None, 'maxTileSize': max_tile_size, }, )
[docs] def set_start(self, x: int | float, y: int | float): """Set start coordinate of Heatmap on its X and Y axis where the first heatmap sample will be positioned Args: x: x-coordinate. y: y-coordinate. Returns: The instance of the class for fluent interface. """ self.instance.send(self.id, 'setStartXY', {'x': x, 'y': y}) return self
[docs] def set_end(self, x: int | float, y: int | float): """Set end coordinate of Heatmap on its X and Y axis where the last heatmap sample will be positioned. Args: x: x-coordinate. y: y-coordinate. Returns: The instance of the class for fluent interface. """ self.instance.send(self.id, 'setEndXY', {'x': x, 'y': y}) return self
[docs] def set_step(self, x: int | float, y: int | float): """Set Step between each consecutive heatmap value on the X and Y Axes. Args: x: x-coordinate. y: y-coordinate. Returns: The instance of the class for fluent interface. """ self.instance.send(self.id, 'setStepXY', {'x': x, 'y': y}) return self
[docs] def set_aggregation(self, mode: str | None): """ Set heatmap intensity aggregation mode. Notes: - Works when intensity interpolation is disabled. (e.g., `set_intensity_interpolation(False)`) Args: mode: Aggregation mode - 'max', 'min', or None to disable. Returns: The instance of the class for fluent interface. """ self.instance.send(self.id, 'setAggregation', {'mode': mode}) return self
[docs] def invalidate_intensity_values( self, data, column_index: int = None, row_index: int = None, sample_index: int = None, columns: int = None, rows: int = None, ): """Invalidate range of heatmap intensity values. Supports both 2D matrix and flat array formats. Flat arrays are more efficient for large datasets and TypedArray transfer. Args: data: Intensity values as either: - 2D matrix: list[list[int | float]] or np.ndarray (2D) - Flat array: list[int | float] or np.ndarray (1D) column_index: Index of first invalidated column (for partial updates). row_index: Index of first invalidated row (for partial updates). sample_index: Sample index for scrolling heatmaps. columns: Number of columns (required for flat array partial updates). rows: Number of rows (required for flat array partial updates). Returns: The instance of the class for fluent interface. Examples: Full update with 2D matrix: >>> series.invalidate_intensity_values([[1, 2], [3, 4]]) Full update with flat array (efficient): >>> series.invalidate_intensity_values([1, 2, 3, 4, 5, 6]) Partial update with flat array: >>> series.invalidate_intensity_values( ... data=[1, 2, 3, 4], ... column_index=5, row_index=2, ... columns=2, rows=2 ... ) """ is_flat = False if np is not None and isinstance(data, np.ndarray): is_flat = data.ndim == 1 data = convert_to_list(data) if is_flat else convert_to_matrix(data) elif isinstance(data, (list, tuple)): if len(data) > 0 and isinstance(data[0], (list, tuple) + ((np.ndarray,) if np is not None else ())): is_flat = False data = convert_to_matrix(data) else: is_flat = True data = convert_to_list(data) else: data = convert_to_list(data) is_flat = True if column_index is not None and row_index is not None: if is_flat and columns is not None and rows is not None: payload = { 'iColumn': column_index, 'iRow': row_index, 'columns': columns, 'rows': rows, 'values': data, } else: payload = { 'iColumn': column_index, 'iRow': row_index, 'values': data, } if sample_index is not None: payload['iSample'] = sample_index else: payload = {'data': data} self.instance.send(self.id, 'invalidateIntensityValues', payload) return self
[docs] def set_contours( self, levels: list[dict] = None, shadows: str = None, show_labels: bool = None, ): """Set contour lines for heatmap visualization. Args: levels: List of contour level configurations. Each level dict can contain: - value (float, required): Contour value threshold - label (str, optional): Text label for contour - label_color (str, optional): Color for label (hex "#FF0000" or name "red") - label_font (dict, optional): Font settings with keys: - size (int): Font size in pixels - family (str): Font family (e.g., "Arial, sans-serif") - weight (str): Font weight ("normal", "bold", "bolder", "lighter", or 100-900) - style (str): Font style ("normal", "italic", "oblique") - stroke_style (dict, optional): Line style with keys: - thickness (int): Line thickness in pixels - color (str): Line color (hex or name) shadows: Shadow color for contours (hex "#000000" or name "black", None to disable) show_labels: Whether to show contour labels Returns: The instance of the class for fluent interface. Examples: Simple contours: >>> series.set_contours( ... levels=[ ... {'value': 10}, ... {'value': 50}, ... {'value': 90} ... ] ... ) Styled contours with labels: >>> series.set_contours( ... levels=[ ... { ... 'value': 25, ... 'label': 'Low', ... 'label_color': '#0000FF', ... 'label_font': {'size': 14, 'weight': 'bold'}, ... 'stroke_style': {'thickness': 2, 'color': '#0000FF'} ... }, ... { ... 'value': 75, ... 'label': 'High', ... 'label_color': '#FF0000', ... 'label_font': {'size': 16, 'family': 'Arial'}, ... 'stroke_style': {'thickness': 3, 'color': '#FF0000'} ... } ... ], ... shadows='#00000040', ... show_labels=True ... ) """ if levels is None: self.instance.send(self.id, 'setContours', {'config': None}) return self processed_levels = [] for level in levels: processed_level = {'value': level['value']} if 'label' in level: processed_level['label'] = level['label'] if 'label_color' in level and level['label_color'] is not None: processed_level['labelColor'] = convert_color_to_hex(level['label_color']) if 'label_font' in level and level['label_font'] is not None: processed_level['labelFont'] = level['label_font'] if 'stroke_style' in level and level['stroke_style'] is not None: stroke = level['stroke_style'] processed_stroke = {} if 'thickness' in stroke: processed_stroke['thickness'] = stroke['thickness'] if 'color' in stroke and stroke['color'] is not None: processed_stroke['color'] = convert_color_to_hex(stroke['color']) processed_level['strokeStyle'] = processed_stroke processed_levels.append(processed_level) config = {'levels': processed_levels} if shadows is not None: config['shadows'] = convert_color_to_hex(shadows) if show_labels is not None: config['showLabels'] = show_labels self.instance.send(self.id, 'setContours', {'config': config}) return self
[docs] def set_contours_from_palette( self, shadows: str = None, show_labels: bool = True, ): """Generate contours automatically from the series' palette colors. Args: shadows: Shadow color (hex "#000000") show_labels: Show contour labels Example: >>> series.set_palette_colors(steps=[...]) >>> series.set_contours_from_palette(show_labels=True) """ self.instance.send( self.id, 'setContoursFromPalette', { 'shadows': convert_color_to_hex(shadows) if shadows else None, 'showLabels': show_labels, }, ) return self