Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jnumainville committed Oct 23, 2024
1 parent 0d1eea8 commit 99ef028
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 99 deletions.
15 changes: 15 additions & 0 deletions plugins/plotly-express/docs/bar.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ bar_plot_smoke = dx.bar(sorted_tips, x="Day", y="TotalBill", by="Smoker")
bar_plot_sex = dx.bar(sorted_tips, x="Day", y="TotalBill", by="Sex")
```

### Frequency of categories

Visualize the frequency of categories in a column by passing to either the `x` or `y` argument.

```python
import deephaven.plot.express as dx
tips = dx.data.tips()

# count the number of occurrences of each day with a vertical bar plot
bar_plot_vertical = dx.bar(tips, x="Day")

# count the number of occurrences of each day with a horizontal bar plot
bar_plot_horizontal = dx.bar(tips, y="Day")
```

## API Reference
```{eval-rst}
.. dhautofunction:: deephaven.plot.express.bar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from .plots import (
area,
bar,
frequency_bar,
timeline,
histogram,
box,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .scatter import scatter, scatter_3d, scatter_polar, scatter_ternary
from .line import line, line_3d, line_polar, line_ternary
from .area import area
from .bar import bar, frequency_bar, timeline
from .bar import bar, timeline
from .distribution import histogram, violin, strip, box
from .financial import candlestick, ohlc
from .hierarchial import treemap, icicle, sunburst, funnel, funnel_area
Expand Down
105 changes: 8 additions & 97 deletions plugins/plotly-express/src/deephaven/plot/express/plots/bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ def bar(
Args:
table: A table to pull data from.
x: A column or list of columns that contain x-axis values.
If only x is specified, the y-axis values are the count of each unique x value.
y: A column or list of columns that contain y-axis values.
If only y is specified, the x-axis values are the count of each unique y value.
by: A column or list of columns that contain values to plot the figure traces by.
All values or combination of values map to a unique design. The variable
by_vars specifies which design elements are used.
Expand Down Expand Up @@ -144,7 +146,12 @@ def bar(
"""
args = locals()

return process_args(args, {"bar", "supports_lists"}, px_func=px.bar)
groups = {"bar", "supports_lists"}

if not x or not y:
groups.add("preprocess_freq")

return process_args(args, groups, px_func=px.bar)


def _bar_polar(
Expand Down Expand Up @@ -299,99 +306,3 @@ def timeline(
args = locals()

return process_args(args, {"bar", "preprocess_time"}, px_func=px.timeline)


def frequency_bar(
table: Table | None = None,
x: str | list[str] | None = None,
y: str | list[str] | None = None,
by: str | list[str] | None = None,
by_vars: str | list[str] = "color",
labels: dict[str, str] | None = None,
color: str | list[str] | None = None,
pattern_shape: str | list[str] | None = None,
color_discrete_sequence: list[str] | None = None,
color_discrete_map: dict[str | tuple[str], str] | None = None,
pattern_shape_sequence: list[str] | None = None,
pattern_shape_map: dict[str | tuple[str], str] | None = None,
opacity: float | None = None,
barmode: str = "relative",
log_x: bool = False,
log_y: bool = False,
range_x: list[int] | None = None,
range_y: list[int] | None = None,
text_auto: bool | str = False,
title: str | None = None,
template: str | None = None,
unsafe_update_figure: Callable = default_callback,
) -> DeephavenFigure:
"""Returns a bar chart that contains the counts of the specified columns
Args:
table: A table to pull data from.
x: A column or list of columns that contain x-axis values.
Only one of x or y can be specified. If x is specified, the bars
are drawn vertically.
y: A column or list of columns that contain y-axis values.
Only one of x or y can be specified. If y is specified, the bars
are drawn horizontally.
by: A column or list of columns that contain values to plot the figure traces by.
All values or combination of values map to a unique design. The variable
by_vars specifies which design elements are used.
This is overriden if any specialized design variables such as color are specified
by_vars: A string or list of string that contain design elements to plot by.
Can contain color and pattern_shape.
If associated maps or sequences are specified, they are used to map by column values
to designs. Otherwise, default values are used.
color: A column or list of columns that contain color values.
The value is used for a plot by on color.
See color_discrete_map for additional behaviors.
pattern_shape: A column or list of columns that contain pattern shape values.
The value is used for a plot by on pattern shape.
See pattern_shape_map for additional behaviors.
labels: A dictionary of labels mapping columns to new labels.
color_discrete_sequence: A list of colors to sequentially apply to
the series. The colors loop, so if there are more series than colors,
colors will be reused.
color_discrete_map: If dict, the keys should be strings of the column values (or a tuple
of combinations of column values) which map to colors.
pattern_shape_sequence: A list of patterns to sequentially apply
to the series. The patterns loop, so if there are more series than
patterns, patterns will be reused.
pattern_shape_map: If dict, the keys should be strings of the column values (or a tuple
of combinations of column values) which map to patterns.
opacity: Opacity to apply to all markers. 0 is completely transparent
and 1 is completely opaque.
barmode: If 'relative', bars are stacked. If 'overlay', bars are drawn on top
of each other. If 'group', bars are drawn next to each other.
log_x: A boolean that specifies if the corresponding axis is a log
axis or not.
log_y: A boolean that specifies if the corresponding axis is a log
axis or not.
range_x: A list of two numbers that specify the range of the x-axis.
range_y: A list of two numbers that specify the range of the y-axis.
text_auto: If True, display the value at each bar.
If a string, specifies a plotly texttemplate.
title: The title of the chart
template: The template for the chart.
unsafe_update_figure: An update function that takes a plotly figure
as an argument and optionally returns a plotly figure. If a figure is
not returned, the plotly figure passed will be assumed to be the return
value. Used to add any custom changes to the underlying plotly figure.
Note that the existing data traces should not be removed. This may lead
to unexpected behavior if traces are modified in a way that break data
mappings.
Returns:
DeephavenFigure: A DeephavenFigure that contains the bar chart
"""

if x and y:
raise ValueError("Cannot specify both x and y")

args = locals()

return process_args(
args, {"bar", "preprocess_freq", "supports_lists"}, px_func=px.bar
)
217 changes: 217 additions & 0 deletions plugins/plotly-express/test/deephaven/plot/express/plots/test_bar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import unittest

from ..BaseTest import BaseTestCase


class BarTestCase(BaseTestCase):
def setUp(self) -> None:
from deephaven import new_table
from deephaven.column import int_col

self.source = new_table(
[
int_col("X", [1, 2, 2, 3, 3, 3, 4, 4, 5]),
int_col("X2", [1, 2, 2, 3, 3, 3, 4, 4, 5]),
int_col("Y", [1, 2, 2, 3, 3, 3, 4, 4, 5]),
int_col("Y2", [1, 2, 2, 3, 3, 3, 4, 4, 5]),
int_col("size", [1, 2, 2, 3, 3, 3, 4, 4, 5]),
int_col("text", [1, 2, 2, 3, 3, 3, 4, 4, 5]),
int_col("hover_name", [1, 2, 2, 3, 3, 3, 4, 4, 5]),
int_col("category", [1, 2, 1, 2, 1, 2, 1, 2, 1]),
]
)

def test_basic_bar_x(self):
import src.deephaven.plot.express as dx
from deephaven.constants import NULL_LONG, NULL_INT

chart = dx.bar(self.source, x="X").to_dict(self.exporter)
plotly, deephaven = chart["plotly"], chart["deephaven"]

# pop template as we currently do not modify it
plotly["layout"].pop("template")

expected_data = [
{
"alignmentgroup": "True",
"hovertemplate": "X=%{x}<br>count=%{y}<extra></extra>",
"legendgroup": "",
"marker": {"color": "#636efa", "pattern": {"shape": ""}},
"name": "",
"offsetgroup": "",
"orientation": "v",
"showlegend": False,
"textposition": "auto",
"type": "bar",
"x": [NULL_INT],
"xaxis": "x",
"y": [NULL_LONG],
"yaxis": "y",
}
]

self.assertEqual(plotly["data"], expected_data)

expected_layout = {
"barmode": "relative",
"legend": {"tracegroupgap": 0},
"margin": {"t": 60},
"xaxis": {
"anchor": "y",
"domain": [0.0, 1.0],
"side": "bottom",
"title": {"text": "X"},
},
"yaxis": {
"anchor": "x",
"domain": [0.0, 1.0],
"side": "left",
"title": {"text": "count"},
},
}

self.assertEqual(plotly["layout"], expected_layout)

expected_mappings = [
{
"data_columns": {
"X": ["/plotly/data/0/x"],
"count": ["/plotly/data/0/y"],
},
"table": 0,
}
]

self.assertEqual(deephaven["mappings"], expected_mappings)

self.assertEqual(deephaven["is_user_set_template"], False)
self.assertEqual(deephaven["is_user_set_color"], False)

def test_basic_bar_y(self):
import src.deephaven.plot.express as dx
from deephaven.constants import NULL_LONG, NULL_INT

chart = dx.bar(self.source, y="Y").to_dict(self.exporter)
plotly, deephaven = chart["plotly"], chart["deephaven"]

# pop template as we currently do not modify it
plotly["layout"].pop("template")

expected_data = [
{
"alignmentgroup": "True",
"hovertemplate": "count=%{x}<br>Y=%{y}<extra></extra>",
"legendgroup": "",
"marker": {"color": "#636efa", "pattern": {"shape": ""}},
"name": "",
"offsetgroup": "",
"orientation": "h",
"showlegend": False,
"textposition": "auto",
"type": "bar",
"x": [NULL_LONG],
"xaxis": "x",
"y": [NULL_INT],
"yaxis": "y",
}
]

self.assertEqual(plotly["data"], expected_data)

expected_layout = {
"barmode": "relative",
"legend": {"tracegroupgap": 0},
"margin": {"t": 60},
"xaxis": {
"anchor": "y",
"domain": [0.0, 1.0],
"side": "bottom",
"title": {"text": "count"},
},
"yaxis": {
"anchor": "x",
"domain": [0.0, 1.0],
"side": "left",
"title": {"text": "Y"},
},
}

self.assertEqual(plotly["layout"], expected_layout)

expected_mappings = [
{
"data_columns": {
"Y": ["/plotly/data/0/y"],
"count": ["/plotly/data/0/x"],
},
"table": 0,
}
]

self.assertEqual(deephaven["mappings"], expected_mappings)

self.assertEqual(deephaven["is_user_set_template"], False)
self.assertEqual(deephaven["is_user_set_color"], False)

def test_basic_bar_x_y(self):
import src.deephaven.plot.express as dx
from deephaven.constants import NULL_INT

chart = dx.bar(self.source, x="X", y="Y").to_dict(self.exporter)
plotly, deephaven = chart["plotly"], chart["deephaven"]

# pop template as we currently do not modify it
plotly["layout"].pop("template")

expected_data = [
{
"alignmentgroup": "True",
"hovertemplate": "X=%{x}<br>Y=%{y}<extra></extra>",
"legendgroup": "",
"marker": {"color": "#636efa", "pattern": {"shape": ""}},
"name": "",
"offsetgroup": "",
"orientation": "v",
"showlegend": False,
"textposition": "auto",
"type": "bar",
"x": [NULL_INT],
"xaxis": "x",
"y": [NULL_INT],
"yaxis": "y",
}
]

self.assertEqual(plotly["data"], expected_data)

expected_layout = {
"barmode": "relative",
"legend": {"tracegroupgap": 0},
"margin": {"t": 60},
"xaxis": {
"anchor": "y",
"domain": [0.0, 1.0],
"side": "bottom",
"title": {"text": "X"},
},
"yaxis": {
"anchor": "x",
"domain": [0.0, 1.0],
"side": "left",
"title": {"text": "Y"},
},
}

self.assertEqual(plotly["layout"], expected_layout)

expected_mappings = [
{
"data_columns": {"X": ["/plotly/data/0/x"], "Y": ["/plotly/data/0/y"]},
"table": 0,
}
]

self.assertEqual(deephaven["mappings"], expected_mappings)

self.assertEqual(deephaven["is_user_set_template"], False)
self.assertEqual(deephaven["is_user_set_color"], False)

0 comments on commit 99ef028

Please sign in to comment.