Skip to content

Commit

Permalink
feat: Allow passing in a pandas dataframe to dx plots (deephaven#967)
Browse files Browse the repository at this point in the history
Fixes deephaven#8 

Allows passing in a pandas dataframe to all plots that take a table.

Example:
```import plotly.express as px
import deephaven.plot.express as dx
df = px.data.iris()
fig = dx.scatter(df, x="sepal_width", y="sepal_length", color="species", symbol="species")
```

Also now require a table (or similar) passed in for all plot types, as
is already done for `density_heatmap`. This was part of deephaven#1, although not
the full changes needed, but made sense to do now. This doesn't break
anything as the plot isn't expected to work without a table anyways.

Additionally adds a test utility for chart comparisons. Not so essential
that all tests need to change per se but reduces future test
boilerplate.
  • Loading branch information
jnumainville authored Oct 29, 2024
1 parent 82f7125 commit cf03ff0
Show file tree
Hide file tree
Showing 16 changed files with 226 additions and 49 deletions.
2 changes: 1 addition & 1 deletion plugins/plotly-express/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Key Features

- **Live Dataframe Support**: Direct integration with real-time Deephaven tables, allowing you to visualize and analyze data as it updates in real time.
- **Live Dataframe Support**: Direct integration with real-time Deephaven tables, allowing you to visualize and analyze data as it updates in real time, in addition to Pandas DataFrames.
- **Automatic Downsampling**: Pixel accurate automatic downsampling that reduces the number of data points displayed, ensuring smooth and responsive visualizations even with large datasets.
- **Server-Side Data Grouping and Aggregation**: Uses server-side processing capabilities to perform data grouping and aggregation directly within Deephaven query engine, enabling efficient analysis of huge datasets without requiring data transfer.
- **Plotly Express Compatibility**: Built on top of Plotly Express, the library inherits its comprehensive set of features, enabling you to create stunning and interactive visualizations effortlessly. In most cases you can directly swap `px` for `dx` for instant compatibility.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
from functools import partial
from collections.abc import Callable
from typing import Any
from pandas import DataFrame

import plotly.express as px

from deephaven.table import Table, PartitionedTable
from deephaven.execution_context import make_user_exec_ctx
import deephaven.pandas as dhpd

from ._layer import atomic_layer
from .PartitionManager import PartitionManager
Expand All @@ -21,6 +23,7 @@
HISTOGRAM_DEFAULTS,
SPREAD_GROUPS,
)
from ..types import PartitionableTableLike


def validate_common_args(args: dict) -> None:
Expand Down Expand Up @@ -252,6 +255,21 @@ def create_deephaven_figure(
)


def convert_to_table(table: PartitionableTableLike) -> Table | PartitionedTable:
"""
Convert a Dataframe to a Table if it is one
Args:
table: The PartitionableTableData to convert
Returns:
The Table or PartitionedTable
"""
if isinstance(table, DataFrame):
return dhpd.to_table(table)
return table


def process_args(
args: dict[str, Any],
groups: set[str] | None = None,
Expand All @@ -278,11 +296,13 @@ def process_args(
DeephavenFigure: The new figure
"""
use_args = locals()
orig_process_args = args_copy(use_args)
render_args = locals()
render_args["args"]["table"] = convert_to_table(render_args["args"]["table"])

orig_process_args = args_copy(render_args)
orig_process_func = lambda **local_args: create_deephaven_figure(**local_args)[0]

new_fig, table, key_column_table, update = create_deephaven_figure(**use_args)
new_fig, table, key_column_table, update = create_deephaven_figure(**render_args)

orig_process_args["args"].update(update)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@

from plotly import express as px

from deephaven.table import Table

from ._private_utils import process_args
from ..shared import default_callback
from ..deephaven_figure import DeephavenFigure
from ..types import PartitionableTableLike


def area(
table: Table | None = None,
table: PartitionableTableLike,
x: str | list[str] | None = None,
y: str | list[str] | None = None,
by: str | list[str] | None = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
from ._private_utils import validate_common_args, process_args
from ..shared import default_callback
from ..deephaven_figure import generate_figure, DeephavenFigure
from ..types import PartitionableTableLike


def bar(
table: Table | None = None,
table: PartitionableTableLike,
x: str | list[str] | None = None,
y: str | list[str] | None = None,
by: str | list[str] | None = None,
Expand Down Expand Up @@ -206,7 +207,7 @@ def _bar_polar(


def timeline(
table: Table | None = None,
table: PartitionableTableLike,
x_start: str | None = None,
x_end: str | None = None,
y: str | None = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
shared_histogram,
)
from ..deephaven_figure import DeephavenFigure

from ..shared import (
VIOLIN_DEFAULTS,
BOX_DEFAULTS,
STRIP_DEFAULTS,
HISTOGRAM_DEFAULTS,
default_callback,
)
from ..types import PartitionableTableLike


def violin(
table: Table | None = None,
table: PartitionableTableLike,
x: str | list[str] | None = None,
y: str | list[str] | None = None,
by: str | list[str] | None = None,
Expand Down Expand Up @@ -103,7 +103,7 @@ def violin(


def box(
table: Table | None = None,
table: PartitionableTableLike,
x: str | list[str] | None = None,
y: str | list[str] | None = None,
by: str | list[str] | None = None,
Expand Down Expand Up @@ -184,7 +184,7 @@ def box(


def strip(
table: Table | None = None,
table: PartitionableTableLike,
x: str | list[str] | None = None,
y: str | list[str] | None = None,
by: str | list[str] | None = None,
Expand Down Expand Up @@ -307,7 +307,7 @@ def _ecdf(


def histogram(
table: Table | None = None,
table: PartitionableTableLike,
x: str | list[str] | None = None,
y: str | list[str] | None = None,
by: str | list[str] | None = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@

from typing import Callable

from deephaven.table import Table

from ._private_utils import process_args
from ..shared import default_callback
from ..deephaven_figure import draw_ohlc, draw_candlestick, DeephavenFigure
from ..types import TableLike


def ohlc(
table: Table | None = None,
table: TableLike,
x: str | None = None,
open: str | list[str] | None = None,
high: str | list[str] | None = None,
Expand Down Expand Up @@ -75,7 +74,7 @@ def ohlc(


def candlestick(
table: Table | None = None,
table: TableLike,
x: str | None = None,
open: str | list[str] | None = None,
high: str | list[str] | None = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

from ._private_utils import process_args
from ..deephaven_figure import DeephavenFigure, draw_density_heatmap
from deephaven.table import Table
from ..types import TableLike


def density_heatmap(
table: Table,
table: TableLike,
x: str | None = None,
y: str | None = None,
z: str | None = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@

from plotly import express as px

from deephaven.table import Table

from ._private_utils import process_args
from ..shared import default_callback
from ..deephaven_figure import DeephavenFigure
from ..types import TableLike


def treemap(
table: Table | None = None,
table: TableLike,
names: str | None = None,
values: str | None = None,
parents: str | None = None,
Expand Down Expand Up @@ -80,7 +79,7 @@ def treemap(


def sunburst(
table: Table | None = None,
table: TableLike,
names: str | None = None,
values: str | None = None,
parents: str | None = None,
Expand Down Expand Up @@ -148,7 +147,7 @@ def sunburst(


def icicle(
table: Table | None = None,
table: TableLike,
names: str | None = None,
values: str | None = None,
parents: str | None = None,
Expand Down Expand Up @@ -216,7 +215,7 @@ def icicle(


def funnel(
table: Table | None = None,
table: TableLike,
x: str | list[str] | None = None,
y: str | list[str] | None = None,
by: str | list[str] | None = None,
Expand Down Expand Up @@ -293,7 +292,7 @@ def funnel(


def funnel_area(
table: Table | None = None,
table: TableLike,
names: str | None = None,
values: str | None = None,
color: str | list[str] | None = None,
Expand Down
11 changes: 5 additions & 6 deletions plugins/plotly-express/src/deephaven/plot/express/plots/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@

from plotly import express as px

from deephaven.table import Table

from ._private_utils import process_args
from ..shared import default_callback
from ..deephaven_figure import DeephavenFigure
from ..types import PartitionableTableLike


def line(
table: Table | None = None,
table: PartitionableTableLike,
x: str | list[str] | None = None,
y: str | list[str] | None = None,
error_x: str | None = None,
Expand Down Expand Up @@ -192,7 +191,7 @@ def line(


def line_3d(
table: Table | None = None,
table: PartitionableTableLike,
x: str | None = None,
y: str | None = None,
z: str | None = None,
Expand Down Expand Up @@ -352,7 +351,7 @@ def line_3d(


def line_polar(
table: Table | None = None,
table: PartitionableTableLike,
r: str | None = None,
theta: str | None = None,
by: str | list[str] | None = None,
Expand Down Expand Up @@ -490,7 +489,7 @@ def line_polar(


def line_ternary(
table: Table | None = None,
table: PartitionableTableLike,
a: str | None = None,
b: str | None = None,
c: str | None = None,
Expand Down
13 changes: 6 additions & 7 deletions plugins/plotly-express/src/deephaven/plot/express/plots/maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@

from plotly import express as px

from deephaven.table import Table

from ._private_utils import process_args
from ..shared import default_callback
from ..deephaven_figure import DeephavenFigure
from ..types import PartitionableTableLike, TableLike


def scatter_geo(
table: Table | None = None,
table: PartitionableTableLike,
lat: str | None = None,
lon: str | None = None,
locations: str | None = None,
Expand Down Expand Up @@ -150,7 +149,7 @@ def scatter_geo(


def scatter_mapbox(
table: Table | None = None,
table: PartitionableTableLike,
lat: str | None = None,
lon: str | None = None,
by: str | list[str] | None = None,
Expand Down Expand Up @@ -264,7 +263,7 @@ def scatter_mapbox(


def line_geo(
table: Table | None = None,
table: PartitionableTableLike,
lat: str | None = None,
lon: str | None = None,
locations: str | None = None,
Expand Down Expand Up @@ -410,7 +409,7 @@ def line_geo(


def line_mapbox(
table: Table | None = None,
table: PartitionableTableLike,
lat: str | None = None,
lon: str | None = None,
by: str | list[str] | None = None,
Expand Down Expand Up @@ -530,7 +529,7 @@ def line_mapbox(


def density_mapbox(
table: Table | None = None,
table: TableLike,
lat: str | None = None,
lon: str | None = None,
z: str | None = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@

from plotly import express as px

from deephaven.table import Table

from ._private_utils import process_args
from ..shared import default_callback
from ..deephaven_figure import DeephavenFigure
from ..types import TableLike


def pie(
table: Table | None = None,
table: TableLike,
names: str | None = None,
values: str | None = None,
color: str | list[str] | None = None,
Expand Down
Loading

0 comments on commit cf03ff0

Please sign in to comment.