Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/rename package #1

Merged
merged 18 commits into from
Feb 9, 2024
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

[Shiny for Python](https://shiny.posit.co/py/) bindings for [ECharts JS](https://echarts.apache.org/)

## Note

This package is still in an early state.

## Installation

```bash
Expand All @@ -16,38 +20,34 @@ pip install git+https://github.com/eodaGmbH/py-shiny-echarts
## Basic usage

```python
from echarts4py.chart import Chart, InitOptions
from echarts4py.option import ChartOption
from echarts4py.renderer import ChartRenderer
from pandas import DataFrame

# Must always be imported, otherwise App is not found
from shiny.express import ui
from shinyecharts import Chart, InitOptions
from shinyecharts.options import Line
from shinyecharts.renderer import ChartRenderer

options = InitOptions(width=600, height=400, renderer="canvas")
init_options = InitOptions(width=600, height=400, renderer="canvas")

data = DataFrame(
[[0, 1, 2, 3], [1, 4, 5, 6], [2, -2, 4, 9]],
columns=["a", "b", "c", "d"],
)


lines = ChartOption(
tooltip={"trigger": "axis"},
legend={},
series=[
{"name": "L1", "type": "line", "encode": {"x": 0, "y": 1}},
{"name": "L2", "type": "line", "encode": {"x": 0, "y": 2}},
{"name": "L3", "type": "line", "encode": {"x": 0, "y": 3}},
],
lines = (
Line(x="a", y="b", tooltip=dict(trigger="axis"), legend=dict())
.add_series("c")
.add_series("d")
)


@ChartRenderer
def render_dataset():
return Chart(options, data=data).set_option(lines)
return Chart(init_options, data=data).set_option(lines)
```

```bash
shiny run docs/examples/getting_started/basic_usage.py --reload
```
```
4 changes: 2 additions & 2 deletions docs/examples/getting_started/app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from echarts4py.chart import Chart, InitOptions
from echarts4py.renderer import ChartRenderer
from pandas import DataFrame
from shiny.express import ui
from shinyecharts import Chart, InitOptions
from shinyecharts.renderer import ChartRenderer

options = InitOptions(width=600, height=400)

Expand Down
22 changes: 9 additions & 13 deletions docs/examples/getting_started/basic_usage.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
from echarts4py.chart import Chart, InitOptions
from echarts4py.option import ChartOption
from echarts4py.renderer import ChartRenderer
from pandas import DataFrame

# Must always be imported, otherwise App is not found
from shiny.express import ui
from shinyecharts import Chart, InitOptions
from shinyecharts.options import Line
from shinyecharts.renderer import ChartRenderer

options = InitOptions(width=600, height=400, renderer="canvas")
init_options = InitOptions(width=600, height=400, renderer="canvas")

data = DataFrame(
[[0, 1, 2, 3], [1, 4, 5, 6], [2, -2, 4, 9]],
columns=["a", "b", "c", "d"],
)


lines = ChartOption(
tooltip={"trigger": "axis"},
legend={},
series=[
{"name": "L1", "type": "line", "encode": {"x": "a", "y": "b"}},
{"name": "L2", "type": "line", "encode": {"x": "a", "y": "d"}},
{"name": "L3", "type": "line", "encode": {"x": 0, "y": "c"}},
],
lines = (
Line(x="a", y="b", tooltip=dict(trigger="axis"), legend=dict())
.add_series("c")
.add_series("d")
)


@ChartRenderer
def render_dataset():
return Chart(options, data=data).set_option(lines)
return Chart(init_options, data=data).set_option(lines)
93 changes: 93 additions & 0 deletions docs/examples/getting_started/basic_usage_express.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from pandas import DataFrame

# Must always be imported, otherwise App is not found
from shiny.express import ui
from shinyecharts import Chart, InitOptions
from shinyecharts.options import Bar, Line, Pie, Scatter
from shinyecharts.renderer import ChartRenderer

# General options
options = InitOptions(width=600, height=400, renderer="canvas")

# Line chart
line_data = DataFrame(
[
[0, 1, 2, 3],
[0.7, 2, 3, 4],
[1, 0.4, 5, 6],
[1.4, 2, 3, 4],
[2, -2, 4, 9],
[3, 1, 6, 7],
],
columns=["a", "b", "c", "d"],
)
lines = (
Line(
x="a", y="b", legend={}, tooltip={"trigger": "axis"}, xAxis={"type": "category"}
)
.add_series("c", series_options={"type": "bar"})
.add_series("d")
)


@ChartRenderer
def render_lines():
return Chart(options, data=line_data).set_option(lines)


# Bar chart
bar_data = DataFrame(
list(
zip(
["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
[23, 24, 18, 25, 27, 28, 25],
[27, 14, 8, 29, 29, 18, 45],
[27, 11, 9, 27, 29, 18, 45],
)
),
columns=["month", "2023", "2024", "2035"],
)

bars = (
Bar(x="month", y="2023", legend={})
.add_series("2024")
.add_series("2025", series_options={"type": "line"})
)


@ChartRenderer
def render_bars():
return Chart(options, data=bar_data).set_option(bars)


# Scatter chart
scatter_data = DataFrame(
[[10, 5, 4], [0, 8, 3], [6, 10, 12], [2, 12, 6], [8, 9, 7]], columns=["x", "y", "z"]
)

scatter = Scatter("x", "y", legend={}, data=scatter_data).add_series(
"z", series_options={"type": "bar"}
)


@ChartRenderer
def render_scatter():
return Chart(options).set_option(scatter)


# Pie chart
pie_data = DataFrame([["A", 10], ["B", 20], ["C", 40]], columns=["name", "value"])
# pie_data = [dict(name=x, value=y) for x, y in zip(["A", "B", "C", "D"], [10, 40, 5, 9])]

pie = Pie(
# data=pie_data
series_options=dict(roseType="area"),
legend=dict(),
tooltip=dict(trigger="item"),
title={"text": "Awesome", "x": "right"},
)


@ChartRenderer
def render_pie():
return Chart(options, data=pie_data).set_option(pie)
Empty file removed echarts4py/__init__.py
Empty file.
16 changes: 0 additions & 16 deletions echarts4py/_core.py

This file was deleted.

27 changes: 0 additions & 27 deletions echarts4py/option.py

This file was deleted.

2 changes: 2 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
filterwarnings = ignore::DeprecationWarning
2 changes: 2 additions & 0 deletions shinyecharts/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .chart import Chart, InitOptions
from .options import ChartOption
68 changes: 68 additions & 0 deletions shinyecharts/_core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from __future__ import annotations

from dataclasses import asdict, dataclass

from pandas import DataFrame


def snake_to_camel_case(snake_str: str) -> str:
return snake_str[0].lower() + snake_str.title()[1:].replace("_", "")


# TODO: Do not check for DataFrame instance here
def df_to_dataset(df: DataFrame = None) -> dict:
return {"dataset": {"source": [df.columns.to_list()] + df.to_numpy().tolist()}}


def df_to_pie_data(df: DataFrame, name: str, value: str) -> list:
return [{"name": row[0], "value": row[1]} for row in df[[name, value]].to_numpy()]


@dataclass
class BaseDataClass(object):
def to_dict(self):
return asdict(
self,
dict_factory=lambda x: {
snake_to_camel_case(k): v for (k, v) in x if v is not None
},
)


class BaseOption(object):
CHART_TYPE: str = None

option = dict()

def to_dict(self) -> dict:
return self.option


class BaseOptionXY(BaseOption):
def _create_series(self, x: str, y: str, series_options: dict = None) -> dict:
return {
"name": y,
"type": self.CHART_TYPE,
"encode": {"x": x, "y": y},
} | (series_options or dict())

def __init__(
self,
x: str = None,
y: str = None,
series_options: dict = None,
data: DataFrame = None,
**kwargs,
) -> None:
self.x = x
x_axis = dict(type="category") if self.CHART_TYPE == "bar" else dict()
series = [self._create_series(x, y, series_options)]
defaults = dict(xAxis=x_axis, yAxis=dict())
if isinstance(data, DataFrame):
defaults.update(df_to_dataset(data))

self.option = defaults | kwargs | {"series": series}

def add_series(self, y: str, series_options: dict = None) -> BaseOptionXY:
self.option["series"].append(self._create_series(self.x, y, series_options))
return self
21 changes: 9 additions & 12 deletions echarts4py/chart.py → shinyecharts/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

from pandas import DataFrame

from .option import ChartOption
from ._core import BaseOption, df_to_dataset
from .options import ChartOption


@dataclass
Expand All @@ -21,28 +22,24 @@ class Chart(object):
def __init__(
self,
init_options: InitOptions = InitOptions(),
theme: str = "dark",
theme: str | None = "dark",
data: DataFrame = None,
) -> None:
self.init_options = init_options
self.theme = theme
self.data = data
self.option = {}
self.option = dict()

def set_option(self, option: dict | ChartOption) -> Chart:
def set_pie_data(self, data: DataFrame) -> Chart:
pass

def set_option(self, option: dict | ChartOption | BaseOption) -> Chart:
self.option = option if isinstance(option, dict) else option.to_dict()
return self

def to_dict(self) -> dict:
dataset = (
{
"dataset": {
"source": [self.data.columns.to_list()]
+ self.data.to_numpy().tolist()
}
}
if isinstance(self.data, DataFrame)
else {}
df_to_dataset(self.data) if isinstance(self.data, DataFrame) else dict()
)
return {
"initOptions": asdict(self.init_options),
Expand Down
Loading
Loading