Skip to content

No way to make plot not overflow #15

@MarcSkovMadsen

Description

@MarcSkovMadsen

I simply cannot figure out how to make plot not overflow in below example. Please make it easy for users to use dynamic plots.

"""Example 2: Data Explorer Pipeline — DataFrames flowing between nodes with an hvPlot scatter chart."""

import hvplot.pandas  # noqa: F401
import numpy as np
import pandas as pd
import panel as pn
import param
from panel.viewable import Viewer

from panel_reactflow import EdgeSpec, NodeSpec, ReactFlow

pn.extension("jsoneditor")

# Generate sample datasets (no external dependencies needed)
DATASETS = {
    "iris": pd.DataFrame(
        {
            "sepal_length": np.random.normal(5.8, 0.8, 150),
            "sepal_width": np.random.normal(3.0, 0.4, 150),
            "petal_length": np.random.normal(3.7, 1.8, 150),
            "petal_width": np.random.normal(1.2, 0.8, 150),
        }
    ),
    "random": pd.DataFrame(
        {
            "x": np.random.randn(200),
            "y": np.random.randn(200),
            "size": np.random.uniform(1, 10, 200),
            "value": np.random.uniform(0, 100, 200),
        }
    ),
}


class DataLoaderNode(Viewer):
    dataset = param.Selector(default="iris", objects=list(DATASETS.keys()))
    data = param.DataFrame()

    @param.depends("dataset", watch=True, on_init=True)
    def _load(self):
        self.data = DATASETS[self.dataset]

    def __panel__(self):
        info = pn.bind(
            lambda d: f"**{len(d)} rows, {len(d.columns)} cols**" if d is not None else "",
            self.param.data,
        )
        return pn.Column(
            pn.widgets.Select.from_param(self.param.dataset, name="Dataset"),
            info,
        )


class ColumnFilterNode(Viewer):
    data = param.DataFrame()
    x_col = param.Selector(default="")
    y_col = param.Selector(default="")

    @param.depends("data", watch=True)
    def _update_columns(self):
        if self.data is not None:
            cols = list(self.data.select_dtypes("number").columns)
            self.param.x_col.objects = cols
            self.param.y_col.objects = cols
            if cols:
                self.x_col = cols[0]
                self.y_col = cols[min(1, len(cols) - 1)]

    def __panel__(self):
        return pn.Column(
            pn.widgets.Select.from_param(self.param.x_col, name="X Column"),
            pn.widgets.Select.from_param(self.param.y_col, name="Y Column"),
        )


class ChartNode(Viewer):
    data = param.DataFrame()
    x_col = param.String(default="")
    y_col = param.String(default="")

    @param.depends("data", "x_col", "y_col")
    def plot(self):
        if self.data is None or not self.x_col or not self.y_col:
            return pn.pane.Markdown("*Waiting for data...*")
        return self.data.hvplot.scatter(x=self.x_col, y=self.y_col, responsive=True)

    def __panel__(self):
        return pn.panel(self.plot, width=500, height=400, sizing_mode="fixed", styles={"border": "1px solid #ddd", "padding": "10px", "box-sizing": "border-box"})


# Create instances and wire them
loader = DataLoaderNode()
filter_node = ColumnFilterNode()
chart = ChartNode()

loader.param.watch(lambda e: setattr(filter_node, "data", e.new), "data")
filter_node.param.watch(lambda e: setattr(chart, "x_col", e.new), "x_col")
filter_node.param.watch(lambda e: setattr(chart, "y_col", e.new), "y_col")
filter_node.param.watch(lambda e: setattr(chart, "data", e.new), "data")

# Build graph
flow = ReactFlow(
    nodes=[
        NodeSpec(id="loader", position={"x": 0, "y": 80}, label="Data Loader").to_dict() | {"view": loader.__panel__()},
        NodeSpec(id="filter", position={"x": 400, "y": 50}, label="Column Filter").to_dict() | {"view": filter_node.__panel__()},
        NodeSpec(id="chart", position={"x": 850, "y": 0}, label="Scatter Chart").to_dict() | {"view": chart.__panel__()},
    ],
    edges=[
        EdgeSpec(id="e1", source="loader", target="filter", label="DataFrame").to_dict(),
        EdgeSpec(id="e2", source="filter", target="chart", label="columns + data").to_dict(),
    ],
    sizing_mode="stretch_both",
)
flow.servable()

In the dropdown select "random"

Image

I've tried all imaginable combinations of width, height and sizing_mode in ChartNode.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions