From e675f4c1fc8ee5f37c2900f90155852be521d28b Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Tue, 11 Apr 2023 22:48:59 -0700 Subject: [PATCH 1/7] refactor: move plotly and dash components into `contrib` --- pyproject.toml | 12 +- subgrounds/contrib/dash/__init__.py | 9 + subgrounds/contrib/dash/abcs.py | 18 ++ subgrounds/contrib/dash/components.py | 134 +++++++++ subgrounds/contrib/plotly/__init__.py | 77 +++++ subgrounds/contrib/plotly/figure.py | 52 ++++ subgrounds/contrib/plotly/traces.py | 251 +++++++++++++++++ subgrounds/dash_wrappers.py | 165 ++--------- subgrounds/plotly_wrappers.py | 387 ++++++-------------------- 9 files changed, 652 insertions(+), 453 deletions(-) create mode 100644 subgrounds/contrib/dash/__init__.py create mode 100644 subgrounds/contrib/dash/abcs.py create mode 100644 subgrounds/contrib/dash/components.py create mode 100644 subgrounds/contrib/plotly/__init__.py create mode 100644 subgrounds/contrib/plotly/figure.py create mode 100644 subgrounds/contrib/plotly/traces.py diff --git a/pyproject.toml b/pyproject.toml index d0691a7..c8f8ea7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dash = ["dash"] # https://python-poetry.org/docs/managing-dependencies/#dependency-groups [tool.poetry.group.dev.dependencies] black = "^22.3.0" -deepdiff = "^6.2.1" # used for debugging data structures +deepdiff = "^6.2.1" # used for debugging data structures ipykernel = "^6.13.0" mypy = "^0.950" nose2 = "^0.11.0" @@ -36,8 +36,8 @@ python-semantic-release = "^7.33.1" ruff = "^0.0.253" [tool.poe.tasks] -format = { shell = "black subgrounds examples tests"} -check = { shell = "black subgrounds examples tests --check; ruff check subgrounds examples tests"} +format = { shell = "black subgrounds examples tests" } +check = { shell = "black subgrounds examples tests --check; ruff check subgrounds examples tests" } develop = { shell = "mudkip develop" } test = "pytest" generate-api-docs = { shell = "sphinx-apidoc --output docs/api subgrounds --separate --force" } @@ -50,6 +50,12 @@ version_toml = "pyproject.toml:tool.poetry.version" major_on_zero = false build_command = "poetry build" +[tool.ruff] + +[tool.ruff.per-file-ignores] +"subgrounds/plotly_wrappers" = ["F405", "F403"] +"subgrounds/dash_wrappers" = ["F405", "F403"] + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/subgrounds/contrib/dash/__init__.py b/subgrounds/contrib/dash/__init__.py new file mode 100644 index 0000000..9ec172f --- /dev/null +++ b/subgrounds/contrib/dash/__init__.py @@ -0,0 +1,9 @@ +from .abcs import Refreshable +from .components import AutoUpdate, DataTable, Graph + +__all__ = [ + "Refreshable", + "Graph", + "DataTable", + "AutoUpdate", +] diff --git a/subgrounds/contrib/dash/abcs.py b/subgrounds/contrib/dash/abcs.py new file mode 100644 index 0000000..084b75e --- /dev/null +++ b/subgrounds/contrib/dash/abcs.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Any + +from dash.dependencies import Output + + +class Refreshable(ABC): + @property + @abstractmethod + def dash_dependencies(self) -> list[Output]: + raise NotImplementedError + + @property + @abstractmethod + def dash_dependencies_outputs(self) -> list[Any]: + raise NotImplementedError diff --git a/subgrounds/contrib/dash/components.py b/subgrounds/contrib/dash/components.py new file mode 100644 index 0000000..6a5ea9e --- /dev/null +++ b/subgrounds/contrib/dash/components.py @@ -0,0 +1,134 @@ +from __future__ import annotations + +from typing import Any, ClassVar + +import pandas as pd +from dash import dash_table, dcc, html +from dash.dependencies import Input, Output +from pipe import map, where + +from subgrounds import FieldPath, Subgrounds +from subgrounds.contrib.plotly import Figure + +from .abcs import Refreshable + + +class Graph(dcc.Graph, Refreshable): + counter: ClassVar[int] = 0 + wrapped_figure: Figure + + def __init__(self, fig: Figure, **kwargs) -> None: + super().__init__(id=f"graph-{Graph.counter}", figure=fig.figure, **kwargs) + Graph.counter += 1 + self.wrapped_figure = fig + + @property + def dash_dependencies(self) -> list[Output]: + return [Output(self.id, "figure")] + + @property + def dash_dependencies_outputs(self) -> list[Any]: + self.wrapped_figure.refresh() + return [self.wrapped_figure.figure] + + +class DataTable(dash_table.DataTable, Refreshable): + counter: ClassVar[int] = 0 + + subgrounds: Subgrounds + data: list[FieldPath] + columns: list[str] | None + concat: bool + append: bool + df: pd.DataFrame | list[pd.DataFrame] | None + + def __init__( + self, + subgrounds: Subgrounds, + data: FieldPath | list[FieldPath], + columns: list[str] | None = None, + concat: bool = False, + append: bool = False, + **kwargs, + ): + self.subgrounds = subgrounds + self.fpaths = data if type(data) == list else [data] + self.column_names = columns + self.concat = concat + self.append = append + self.df = None + + super().__init__(id=f"datatable-{DataTable.counter}", **kwargs) + DataTable.counter += 1 + + self.refresh() + + def refresh(self) -> None: + match (self.df, self.append): + case (None, _) | (_, False): + self.df = self.subgrounds.query_df( + self.fpaths, columns=self.column_names, concat=self.concat + ) + case (_, True): + self.df = pd.concat( + [ + self.df, + self.subgrounds.query_df( + self.fpaths, columns=self.column_names, concat=self.concat + ), + ], + ignore_index=True, + ) + self.df = self.df.drop_duplicates() + + self.columns = [{"name": i, "id": i} for i in self.df.columns] + self.data = self.df.to_dict("records") + + @property + def dash_dependencies(self) -> list[Output]: + return [Output(self.id, "data")] + + @property + def dash_dependencies_outputs(self) -> list[Output]: + self.refresh() + return [self.df.to_dict("records")] + + +class AutoUpdate(html.Div): + counter: ClassVar[int] = 0 + + def __init__(self, app, sec_interval: int = 1, children=[], **kwargs): + id = f"interval-{AutoUpdate.counter}" + + super().__init__( + children=[ + dcc.Interval(id=id, interval=sec_interval * 1000, n_intervals=0), + *children, + ], + **kwargs, + ) + + AutoUpdate.counter += 1 + + def flatten(input: list[Any]): + return [item for sublist in input for item in sublist] + + subgrounds_children = list( + children | where(lambda child: isinstance(child, Refreshable)) + ) + deps = flatten( + list(subgrounds_children | map(lambda child: child.dash_dependencies)) + ) + + def update(n): + outputs = flatten( + list( + subgrounds_children + | map(lambda child: child.dash_dependencies_outputs) + ) + ) + + return outputs[0] if len(outputs) == 1 else outputs + + # Register callback + app.callback(*deps, Input(id, "n_intervals"))(update) diff --git a/subgrounds/contrib/plotly/__init__.py b/subgrounds/contrib/plotly/__init__.py new file mode 100644 index 0000000..a2f2e7c --- /dev/null +++ b/subgrounds/contrib/plotly/__init__.py @@ -0,0 +1,77 @@ +from .figure import Figure +from .traces import ( + Bar, + Barpolar, + Box, + Candlestick, + Carpet, + Choropleth, + Choroplethmapbox, + Contour, + Contourcarpet, + Densitymapbox, + Funnel, + Heatmap, + Histogram, + Histogram2d, + Histogram2dContour, + Icicle, + Indicator, + Ohlc, + Parcats, + Parcoords, + Pie, + Sankey, + Scatter, + Scatter3d, + Scattercarpet, + Scattergeo, + Scattermapbox, + Scatterpolar, + Sunburst, + Surface, + Table, + TraceWrapper, + Treemap, + Violin, + Waterfall, +) + +__all__ = [ + "Figure", + "TraceWrapper", + "Scatter", + "Pie", + "Bar", + "Heatmap", + "Contour", + "Table", + "Box", + "Violin", + "Histogram", + "Histogram2d", + "Histogram2dContour", + "Ohlc", + "Candlestick", + "Waterfall", + "Funnel", + "Indicator", + "Scatter3d", + "Surface", + "Scattergeo", + "Choropleth", + "Scattermapbox", + "Choroplethmapbox", + "Densitymapbox", + "Scatterpolar", + "Barpolar", + "Sunburst", + "Treemap", + "Icicle", + "Sankey", + "Parcoords", + "Parcats", + "Carpet", + "Scattercarpet", + "Contourcarpet", +] diff --git a/subgrounds/contrib/plotly/figure.py b/subgrounds/contrib/plotly/figure.py new file mode 100644 index 0000000..187dbda --- /dev/null +++ b/subgrounds/contrib/plotly/figure.py @@ -0,0 +1,52 @@ +from typing import Any + +import plotly.graph_objects as go +from pipe import map, traverse + +from subgrounds import Subgrounds +from subgrounds.query import DataRequest + +from .traces import TraceWrapper + + +class Figure: + subgrounds: Subgrounds + traces: list[TraceWrapper] + req: DataRequest | None + data: list[dict[str, Any]] | None + figure: go.Figure + + args: dict[str, Any] + + def __init__( + self, + subgrounds: Subgrounds, + traces: TraceWrapper | list[TraceWrapper], + **kwargs + ) -> None: + self.subgrounds = subgrounds + self.traces = list([traces] | traverse) + + traces = list(self.traces | map(lambda trace: trace.field_paths) | traverse) + + if len(traces) > 0: + self.req = self.subgrounds.mk_request(traces) + self.data = self.subgrounds.execute(self.req) + else: + self.req = None + self.data = None + + self.args = kwargs + self.refresh() + + def refresh(self) -> None: + # TODO: Modify this to support x/y in different documents + self.figure = go.Figure(**self.args) + + if self.req is None: + return + + self.data = self.subgrounds.execute(self.req) + + for trace in self.traces: + self.figure.add_trace(trace.mk_trace(self.data)) diff --git a/subgrounds/contrib/plotly/traces.py b/subgrounds/contrib/plotly/traces.py new file mode 100644 index 0000000..159359e --- /dev/null +++ b/subgrounds/contrib/plotly/traces.py @@ -0,0 +1,251 @@ +from abc import ABC +from typing import Any + +import plotly.graph_objects as go +from plotly.basedatatypes import BaseTraceType + +from subgrounds import FieldPath + + +class TraceWrapper(ABC): + graph_object: BaseTraceType + + fpaths: dict[str, FieldPath] + args: dict[str, Any] + + def __init__(self, **kwargs) -> None: + self.fpaths = {} + self.args = {} + + for key, arg in kwargs.items(): + match arg: + case FieldPath(): + self.fpaths[key] = arg + case _: + self.args[key] = arg + + def mk_trace(self, data: list[dict[str, Any]] | dict[str, Any]) -> BaseTraceType: + fpath_data = {} + for key, fpath in self.fpaths.items(): + item = fpath._extract_data(data) + + if type(item) == list and len(item) == 1: + fpath_data[key] = item[0] + else: + fpath_data[key] = item + + return self.graph_object(**(fpath_data | self.args)) # type: ignore + + @property + def field_paths(self) -> list[FieldPath]: + return [fpath for _, fpath in self.fpaths.items()] + + +# Simple +class Scatter(TraceWrapper): + """See https://plotly.com/python/line-and-scatter/""" + + graph_object = go.Scatter # type: ignore + + +class Pie(TraceWrapper): + """See https://plotly.com/python/pie-charts/""" + + graph_object = go.Pie # type: ignore + + +class Bar(TraceWrapper): + """See https://plotly.com/python/bar-charts/""" + + graph_object = go.Bar # type: ignore + + +class Heatmap(TraceWrapper): + """See https://plotly.com/python/heatmaps/""" + + graph_object = go.Heatmap # type: ignore + + +class Contour(TraceWrapper): + """See https://plotly.com/python/contour-plots/""" + + graph_object = go.Contour # type: ignore + + +class Table(TraceWrapper): + """See https://plotly.com/python/contour-plots/""" + + graph_object = go.Table # type: ignore + + +# Distributions +class Box(TraceWrapper): + """See https://plotly.com/python/box-plots/""" + + graph_object = go.Box # type: ignore + + +class Violin(TraceWrapper): + """See https://plotly.com/python/violin/""" + + graph_object = go.Violin # type: ignore + + +class Histogram(TraceWrapper): + """See https://plotly.com/python/histograms/""" + + graph_object = go.Histogram # type: ignore + + +class Histogram2d(TraceWrapper): + """See https://plotly.com/python/2D-Histogram/""" + + graph_object = go.Histogram2d # type: ignore + + +class Histogram2dContour(TraceWrapper): + """See https://plotly.com/python/2d-histogram-contour/""" + + graph_object = go.Histogram2dContour # type: ignore + + +# Finance +class Ohlc(TraceWrapper): + """See https://plotly.com/python/ohlc-charts/""" + + graph_object = go.Ohlc # type: ignore + + +class Candlestick(TraceWrapper): + """See https://plotly.com/python/candlestick-charts/""" + + graph_object = go.Candlestick # type: ignore + + +class Waterfall(TraceWrapper): + """See https://plotly.com/python/waterfall-charts/""" + + graph_object = go.Waterfall # type: ignore + + +class Funnel(TraceWrapper): + """See https://plotly.com/python/funnel-charts/""" + + graph_object = go.Funnel # type: ignore + + +class Indicator(TraceWrapper): + """See https://plotly.com/python/indicator/""" + + graph_object = go.Indicator # type: ignore + + +# 3d +class Scatter3d(TraceWrapper): + """See https://plotly.com/python/3d-scatter-plots/""" + + graph_object = go.Scatter3d # type: ignore + + +class Surface(TraceWrapper): + """See https://plotly.com/python/3d-surface-plots/""" + + graph_object = go.Surface # type: ignore + + +# Maps +class Scattergeo(TraceWrapper): + """See https://plotly.com/python/scatter-plots-on-maps/""" + + graph_object = go.Scattergeo # type: ignore + + +class Choropleth(TraceWrapper): + """See https://plotly.com/python/choropleth-maps/""" + + graph_object = go.Choropleth # type: ignore + + +class Scattermapbox(TraceWrapper): + """See https://plotly.com/python/scattermapbox/""" + + graph_object = go.Scattermapbox # type: ignore + + +class Choroplethmapbox(TraceWrapper): + """See https://plotly.com/python/mapbox-county-choropleth/""" + + graph_object = go.Choroplethmapbox # type: ignore + + +class Densitymapbox(TraceWrapper): + """See https://plotly.com/python/mapbox-density-heatmaps/""" + + graph_object = go.Densitymapbox # type: ignore + + +# Specialized +class Scatterpolar(TraceWrapper): + """See https://plotly.com/python/polar-chart/""" + + graph_object = go.Scatterpolar # type: ignore + + +class Barpolar(TraceWrapper): + """See https://plotly.com/python/wind-rose-charts/""" + + graph_object = go.Barpolar # type: ignore + + +class Sunburst(TraceWrapper): + """See https://plotly.com/python/sunburst-charts/""" + + graph_object = go.Sunburst # type: ignore + + +class Treemap(TraceWrapper): + """See https://plotly.com/python/treemaps/""" + + graph_object = go.Treemap # type: ignore + + +class Icicle(TraceWrapper): + """See https://plotly.com/python/icicle-charts/""" + + graph_object = go.Icicle # type: ignore + + +class Sankey(TraceWrapper): + """See https://plotly.com/python/sankey-diagram/""" + + graph_object = go.Sankey # type: ignore + + +class Parcoords(TraceWrapper): + """See https://plotly.com/python/parallel-coordinates-plot/""" + + graph_object = go.Parcoords # type: ignore + + +class Parcats(TraceWrapper): + """See https://plotly.com/python/parallel-categories-diagram/""" + + graph_object = go.Parcats # type: ignore + + +class Carpet(TraceWrapper): + """See https://plotly.com/python/carpet-plot/""" + + graph_object = go.Carpet # type: ignore + + +class Scattercarpet(TraceWrapper): + """See https://plotly.com/python/carpet-scatter/""" + + graph_object = go.Scattercarpet # type: ignore + + +class Contourcarpet(TraceWrapper): + """See https://plotly.com/python/carpet-contour/""" + + graph_object = go.Contourcarpet # type: ignore diff --git a/subgrounds/dash_wrappers.py b/subgrounds/dash_wrappers.py index 67c6b00..dbe6b36 100644 --- a/subgrounds/dash_wrappers.py +++ b/subgrounds/dash_wrappers.py @@ -1,149 +1,16 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import Any, ClassVar, Optional - -import pandas as pd -from dash import dash_table, dcc, html -from dash.dependencies import Input, Output -from pipe import map, where - -from subgrounds.plotly_wrappers import Figure -from subgrounds.subgraph import FieldPath -from subgrounds.subgrounds import Subgrounds - - -class Refreshable(ABC): - @property - @abstractmethod - def dash_dependencies(self) -> list[Output]: - raise NotImplementedError - - @property - @abstractmethod - def dash_dependencies_outputs(self) -> list[Any]: - raise NotImplementedError - - -class Graph(dcc.Graph, Refreshable): - counter: ClassVar[int] = 0 - wrapped_figure: Figure - - def __init__(self, fig: Figure, **kwargs) -> None: - super().__init__(id=f"graph-{Graph.counter}", figure=fig.figure, **kwargs) - Graph.counter += 1 - self.wrapped_figure = fig - - @property - def dash_dependencies(self) -> list[Output]: - return [Output(self.id, "figure")] - - @property - def dash_dependencies_outputs(self) -> list[Any]: - self.wrapped_figure.refresh() - return [self.wrapped_figure.figure] - - -class DataTable(dash_table.DataTable, Refreshable): - counter: ClassVar[int] = 0 - - subgrounds: Subgrounds - data: list[FieldPath] - columns: Optional[list[str]] - concat: bool - append: bool - df: Optional[pd.DataFrame | list[pd.DataFrame]] - - def __init__( - self, - subgrounds: Subgrounds, - data: FieldPath | list[FieldPath], - columns: Optional[list[str]] = None, - concat: bool = False, - append: bool = False, - **kwargs, - ): - self.subgrounds = subgrounds - self.fpaths = data if type(data) == list else [data] - self.column_names = columns - self.concat = concat - self.append = append - self.df = None - - super().__init__(id=f"datatable-{DataTable.counter}", **kwargs) - DataTable.counter += 1 - - self.refresh() - - def refresh(self) -> None: - match (self.df, self.append): - case (None, _) | (_, False): - self.df = self.subgrounds.query_df( - self.fpaths, columns=self.column_names, concat=self.concat - ) - case (_, True): - self.df = pd.concat( - [ - self.df, - self.subgrounds.query_df( - self.fpaths, columns=self.column_names, concat=self.concat - ), - ], - ignore_index=True, - ) - self.df = self.df.drop_duplicates() - - self.columns = [{"name": i, "id": i} for i in self.df.columns] - self.data = self.df.to_dict("records") - - @property - def dash_dependencies(self) -> list[Output]: - return [Output(self.id, "data")] - - @property - def dash_dependencies_outputs(self) -> list[Output]: - self.refresh() - return [self.df.to_dict("records")] - - -class AutoUpdate(html.Div): - counter: ClassVar[int] = 0 - - def __init__(self, app, sec_interval: int = 1, children=[], **kwargs): - id = f"interval-{AutoUpdate.counter}" - - super().__init__( - children=[ - dcc.Interval(id=id, interval=sec_interval * 1000, n_intervals=0), - *children, - ], - **kwargs, - ) - - AutoUpdate.counter += 1 - - def flatten(l): - return [item for sublist in l for item in sublist] - - subgrounds_children = list( - children | where(lambda child: isinstance(child, Refreshable)) - ) - deps = flatten( - list(subgrounds_children | map(lambda child: child.dash_dependencies)) - ) - - def update(n): - outputs = flatten( - list( - subgrounds_children - | map(lambda child: child.dash_dependencies_outputs) - ) - ) - - if len(outputs) == 1: - return outputs[0] - else: - return outputs - - # Register callback - app.callback(*deps, Input(id, "n_intervals"))(update) +import warnings + +from subgrounds.contrib.dash import AutoUpdate, DataTable, Graph, Refreshable + +__all__ = [ + "Refreshable", + "Graph", + "DataTable", + "AutoUpdate", +] + +warnings.warn( + "Importing from `subgrounds.plotly_wrappers` is deprecated." + " Use `subgrounds.contrib.plotly` instead.", + DeprecationWarning, +) diff --git a/subgrounds/plotly_wrappers.py b/subgrounds/plotly_wrappers.py index 568d53a..8319445 100644 --- a/subgrounds/plotly_wrappers.py +++ b/subgrounds/plotly_wrappers.py @@ -1,301 +1,86 @@ -from abc import ABC -from typing import Any - -import plotly.graph_objects as go -from pipe import map, traverse -from plotly.basedatatypes import BaseTraceType - -from subgrounds.query import DataRequest -from subgrounds.subgraph import FieldPath -from subgrounds.subgrounds import Subgrounds - - -class TraceWrapper(ABC): - graph_object: BaseTraceType - - fpaths: dict[str, FieldPath] - args: dict[str, Any] - - def __init__(self, **kwargs) -> None: - self.fpaths = {} - self.args = {} - - for key, arg in kwargs.items(): - match arg: - case FieldPath(): - self.fpaths[key] = arg - case _: - self.args[key] = arg - - def mk_trace(self, data: list[dict[str, Any]] | dict[str, Any]) -> BaseTraceType: - fpath_data = {} - for key, fpath in self.fpaths.items(): - item = fpath._extract_data(data) - if type(item) == list and len(item) == 1: - fpath_data[key] = item[0] - else: - fpath_data[key] = item - - # print(f'mk_trace: {fpath_data}') - # for key, item in fpath_data.items(): - # print(f'{key}: {len(item)} datapoints') - - return self.graph_object(**(fpath_data | self.args)) - - @property - def field_paths(self) -> list[FieldPath]: - return [fpath for _, fpath in self.fpaths.items()] - - -# Simple -class Scatter(TraceWrapper): - """See https://plotly.com/python/line-and-scatter/""" - - graph_object = go.Scatter - - -class Pie(TraceWrapper): - """See https://plotly.com/python/pie-charts/""" - - graph_object = go.Pie - - -class Bar(TraceWrapper): - """See https://plotly.com/python/bar-charts/""" - - graph_object = go.Bar - - -class Heatmap(TraceWrapper): - """See https://plotly.com/python/heatmaps/""" - - graph_object = go.Heatmap - - -class Contour(TraceWrapper): - """See https://plotly.com/python/contour-plots/""" - - graph_object = go.Contour - - -class Table(TraceWrapper): - """See https://plotly.com/python/contour-plots/""" - - graph_object = go.Table - - -# Distributions -class Box(TraceWrapper): - """See https://plotly.com/python/box-plots/""" - - graph_object = go.Box - - -class Violin(TraceWrapper): - """See https://plotly.com/python/violin/""" - - graph_object = go.Violin - - -class Histogram(TraceWrapper): - """See https://plotly.com/python/histograms/""" - - graph_object = go.Histogram - - -class Histogram2d(TraceWrapper): - """See https://plotly.com/python/2D-Histogram/""" - - graph_object = go.Histogram2d - - -class Histogram2dContour(TraceWrapper): - """See https://plotly.com/python/2d-histogram-contour/""" - - graph_object = go.Histogram2dContour - - -# Finance -class Ohlc(TraceWrapper): - """See https://plotly.com/python/ohlc-charts/""" - - graph_object = go.Ohlc - - -class Candlestick(TraceWrapper): - """See https://plotly.com/python/candlestick-charts/""" - - graph_object = go.Candlestick - - -class Waterfall(TraceWrapper): - """See https://plotly.com/python/waterfall-charts/""" - - graph_object = go.Waterfall - - -class Funnel(TraceWrapper): - """See https://plotly.com/python/funnel-charts/""" - - graph_object = go.Funnel - - -class Indicator(TraceWrapper): - """See https://plotly.com/python/indicator/""" - - graph_object = go.Indicator - - -# 3d -class Scatter3d(TraceWrapper): - """See https://plotly.com/python/3d-scatter-plots/""" - - graph_object = go.Scatter3d - - -class Surface(TraceWrapper): - """See https://plotly.com/python/3d-surface-plots/""" - - graph_object = go.Surface - - -# Maps -class Scattergeo(TraceWrapper): - """See https://plotly.com/python/scatter-plots-on-maps/""" - - graph_object = go.Scattergeo - - -class Choropleth(TraceWrapper): - """See https://plotly.com/python/choropleth-maps/""" - - graph_object = go.Choropleth - - -class Scattermapbox(TraceWrapper): - """See https://plotly.com/python/scattermapbox/""" - - graph_object = go.Scattermapbox - - -class Choroplethmapbox(TraceWrapper): - """See https://plotly.com/python/mapbox-county-choropleth/""" - - graph_object = go.Choroplethmapbox - - -class Densitymapbox(TraceWrapper): - """See https://plotly.com/python/mapbox-density-heatmaps/""" - - graph_object = go.Densitymapbox - - -# Specialized -class Scatterpolar(TraceWrapper): - """See https://plotly.com/python/polar-chart/""" - - graph_object = go.Scatterpolar - - -class Barpolar(TraceWrapper): - """See https://plotly.com/python/wind-rose-charts/""" - - graph_object = go.Barpolar - - -class Sunburst(TraceWrapper): - """See https://plotly.com/python/sunburst-charts/""" - - graph_object = go.Sunburst - - -class Treemap(TraceWrapper): - """See https://plotly.com/python/treemaps/""" - - graph_object = go.Treemap - - -class Icicle(TraceWrapper): - """See https://plotly.com/python/icicle-charts/""" - - graph_object = go.Icicle - - -class Sankey(TraceWrapper): - """See https://plotly.com/python/sankey-diagram/""" - - graph_object = go.Sankey - - -class Parcoords(TraceWrapper): - """See https://plotly.com/python/parallel-coordinates-plot/""" - - graph_object = go.Parcoords - - -class Parcats(TraceWrapper): - """See https://plotly.com/python/parallel-categories-diagram/""" - - graph_object = go.Parcats - - -class Carpet(TraceWrapper): - """See https://plotly.com/python/carpet-plot/""" - - graph_object = go.Carpet - - -class Scattercarpet(TraceWrapper): - """See https://plotly.com/python/carpet-scatter/""" - - graph_object = go.Scattercarpet - - -class Contourcarpet(TraceWrapper): - """See https://plotly.com/python/carpet-contour/""" - - graph_object = go.Contourcarpet - - -class Figure: - subgrounds: Subgrounds - traces: list[TraceWrapper] - req: DataRequest - data: list[dict[str, Any]] - figure: go.Figure - - args: dict[str, Any] - - def __init__( - self, - subgrounds: Subgrounds, - traces: TraceWrapper | list[TraceWrapper], - **kwargs - ) -> None: - self.subgrounds = subgrounds - self.traces = list([traces] | traverse) - - traces = list(self.traces | map(lambda trace: trace.field_paths) | traverse) - if len(traces) > 0: - self.req = self.subgrounds.mk_request(traces) - self.data = self.subgrounds.execute(self.req) - else: - self.req = None - self.data = None - - self.args = kwargs - self.refresh() - - def refresh(self) -> None: - # TODO: Modify this to support x/y in different documents - self.figure = go.Figure(**self.args) - - if self.req is not None: - self.data = self.subgrounds.execute(self.req) - - for trace in self.traces: - self.figure.add_trace(trace.mk_trace(self.data)) - - # @staticmethod - # def mk_subplots(rows, cols, **kwargs): - # return make_subplots(rows, cols, **kwargs) +import warnings + +from subgrounds.contrib.plotly import ( + Bar, + Barpolar, + Box, + Candlestick, + Carpet, + Choropleth, + Choroplethmapbox, + Contour, + Contourcarpet, + Densitymapbox, + Figure, + Funnel, + Heatmap, + Histogram, + Histogram2d, + Histogram2dContour, + Icicle, + Indicator, + Ohlc, + Parcats, + Parcoords, + Pie, + Sankey, + Scatter, + Scatter3d, + Scattercarpet, + Scattergeo, + Scattermapbox, + Scatterpolar, + Sunburst, + Surface, + Table, + TraceWrapper, + Treemap, + Violin, + Waterfall, +) + +__all__ = [ + "Figure", + "TraceWrapper", + "Scatter", + "Pie", + "Bar", + "Heatmap", + "Contour", + "Table", + "Box", + "Violin", + "Histogram", + "Histogram2d", + "Histogram2dContour", + "Ohlc", + "Candlestick", + "Waterfall", + "Funnel", + "Indicator", + "Scatter3d", + "Surface", + "Scattergeo", + "Choropleth", + "Scattermapbox", + "Choroplethmapbox", + "Densitymapbox", + "Scatterpolar", + "Barpolar", + "Sunburst", + "Treemap", + "Icicle", + "Sankey", + "Parcoords", + "Parcats", + "Carpet", + "Scattercarpet", + "Contourcarpet", +] + + +warnings.warn( + "Importing from `subgrounds.plotly_wrappers` is deprecated." + " Use `subgrounds.contrib.plotly` instead.", + DeprecationWarning, +) From 6a7bbecbbd30d926ff7a9c8285b3c7be64b28722 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Tue, 11 Apr 2023 23:00:06 -0700 Subject: [PATCH 2/7] docs: add extra details about `contrib` and deprecation --- subgrounds/contrib/README.md | 17 +++++++++++++++++ subgrounds/dash_wrappers.py | 7 ++++++- subgrounds/plotly_wrappers.py | 7 ++++++- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 subgrounds/contrib/README.md diff --git a/subgrounds/contrib/README.md b/subgrounds/contrib/README.md new file mode 100644 index 0000000..8acd8b0 --- /dev/null +++ b/subgrounds/contrib/README.md @@ -0,0 +1,17 @@ +# Subgrounds Contrib +> Extra parts of subgrounds that may not fit in the main package + +## What is this? +Contrib is a niche concept in some library packs that represent extra / contributed content to a library that may not fit in the main package. This might be due to the maintainer not willing to maintain said content, the content being deemed too experimental, or perhaps it's unknown whether it's a "good idea" or not. + +> Relevant [Stackoverflow](https://softwareengineering.stackexchange.com/questions/252053/whats-in-the-contrib-folder) post + +For us, `subgrounds.contrib` will represent extra features and ideas with `subgrounds` that generally builds upon the core part of `subgrounds`. It allows us to add extensions or features to other libraries (such as `plotly`) without *relying* on the library as a dependency. We might add new concepts to this subpackage in the future, so look out! + +## What's currently here? + +### Plotly +Originally located in `subgrounds.plotly_wrappers`, `subgrounds.contrib.plotly` contains helpful wrappers on `plotly` objects that allow you to use `FieldPaths` directly without creating a `panda`'s `DataFrame`. + +### Dash +Originally located in `subgrounds.dash_wrappers`, `subgrounds.contrib.dash` contains helpful wrappers on `dash` objects that allow you to use other wrapped visualization objects (currently `subgrounds.contrib.plotly`) in `dash` apps without creating `panda`'s `DataFrame`s. diff --git a/subgrounds/dash_wrappers.py b/subgrounds/dash_wrappers.py index dbe6b36..5f8f8d3 100644 --- a/subgrounds/dash_wrappers.py +++ b/subgrounds/dash_wrappers.py @@ -1,3 +1,7 @@ +""" +DEPRECIATED: Use `subgrounds.contrib.dash` instead +""" + import warnings from subgrounds.contrib.dash import AutoUpdate, DataTable, Graph, Refreshable @@ -11,6 +15,7 @@ warnings.warn( "Importing from `subgrounds.plotly_wrappers` is deprecated." - " Use `subgrounds.contrib.plotly` instead.", + " Use `subgrounds.contrib.plotly` instead.\n" + "Will be removed in a future version.", DeprecationWarning, ) diff --git a/subgrounds/plotly_wrappers.py b/subgrounds/plotly_wrappers.py index 8319445..cbd1a3f 100644 --- a/subgrounds/plotly_wrappers.py +++ b/subgrounds/plotly_wrappers.py @@ -1,3 +1,7 @@ +""" +DEPRECIATED: Use `subgrounds.contrib.plotly` instead +""" + import warnings from subgrounds.contrib.plotly import ( @@ -81,6 +85,7 @@ warnings.warn( "Importing from `subgrounds.plotly_wrappers` is deprecated." - " Use `subgrounds.contrib.plotly` instead.", + " Use `subgrounds.contrib.plotly` instead.\n" + "Will be removed in a future version.", DeprecationWarning, ) From 11a047e0a8df0a4cb4d188dfd955564451a5744d Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Tue, 11 Apr 2023 23:03:32 -0700 Subject: [PATCH 3/7] refactor: nest dash examples and add some stub examples --- examples/README.md | 6 ++-- examples/aave_v2.py | 18 ++++++++++ examples/curve.py | 34 +++++++++++++++++++ examples/dash_apps/README.md | 8 +++++ examples/{ => dash_apps}/bar_chart.py | 0 examples/{ => dash_apps}/dashboard.py | 0 examples/{ => dash_apps}/double_query.py | 0 examples/{ => dash_apps}/indicator.py | 0 examples/{ => dash_apps}/indicator2.py | 0 examples/{ => dash_apps}/live_indicator.py | 0 examples/{ => dash_apps}/olympus_dashboard.py | 0 examples/{ => dash_apps}/olympus_voting.py | 0 examples/{ => dash_apps}/synthetic_fields.py | 0 examples/{ => dash_apps}/table.py | 0 .../{ => dash_apps}/uniswapv2_firehose.py | 0 15 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 examples/aave_v2.py create mode 100644 examples/curve.py create mode 100644 examples/dash_apps/README.md rename examples/{ => dash_apps}/bar_chart.py (100%) rename examples/{ => dash_apps}/dashboard.py (100%) rename examples/{ => dash_apps}/double_query.py (100%) rename examples/{ => dash_apps}/indicator.py (100%) rename examples/{ => dash_apps}/indicator2.py (100%) rename examples/{ => dash_apps}/live_indicator.py (100%) rename examples/{ => dash_apps}/olympus_dashboard.py (100%) rename examples/{ => dash_apps}/olympus_voting.py (100%) rename examples/{ => dash_apps}/synthetic_fields.py (100%) rename examples/{ => dash_apps}/table.py (100%) rename examples/{ => dash_apps}/uniswapv2_firehose.py (100%) diff --git a/examples/README.md b/examples/README.md index 28d5eaf..816fc9a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,4 +1,2 @@ -## Running the examples -Install subgrounds with your favorite Python dependency manager. E.g.: `pip install subgrounds`. - -Run the examples, e.g.: `python bar_chart.py` \ No newline at end of file +# Examples +> See [our docs](https://docs.playgrounds.network/examples/) for more examples! diff --git a/examples/aave_v2.py b/examples/aave_v2.py new file mode 100644 index 0000000..6629c84 --- /dev/null +++ b/examples/aave_v2.py @@ -0,0 +1,18 @@ +from subgrounds import Subgrounds + +sg = Subgrounds() + +# Load +aave_v2 = sg.load_subgraph( + "https://api.thegraph.com/subgraphs/name/messari/aave-v2-ethereum" +) + +# Construct the query +latest = aave_v2.Query.markets( + orderBy=aave_v2.Market.totalValueLockedUSD, + orderDirection="desc", + first=5, +) + +# Return query to a dataframe +sg.query_df([latest.name, latest.totalValueLockedUSD]) diff --git a/examples/curve.py b/examples/curve.py new file mode 100644 index 0000000..5bbebba --- /dev/null +++ b/examples/curve.py @@ -0,0 +1,34 @@ +from subgrounds import Subgrounds + +sg = Subgrounds() + +curve = sg.load_subgraph( + "https://api.thegraph.com/subgraphs/name/messari/curve-finance-ethereum" +) + +# Partial FieldPath selecting the top 4 most traded pools on Curve +most_traded_pools = curve.Query.liquidityPools( + orderBy=curve.LiquidityPool.cumulativeVolumeUSD, + orderDirection="desc", + first=4, +) + +# Partial FieldPath selecting the top 2 pools by daily total revenue of +# the top 4 most traded tokens. +# Mote that reuse of `most_traded_pools` in the partial FieldPath +most_traded_snapshots = most_traded_pools.dailySnapshots( + orderBy=curve.LiquidityPoolDailySnapshot.dailyTotalRevenue, + orderDirection="desc", + first=3, +) + +# Querying: +# - the name of the top 4 most traded pools, their 2 most liquid +# pools' token symbols and their 2 most liquid pool's TVL in USD +sg.query_df( + [ + most_traded_pools.name, + most_traded_snapshots.dailyVolumeUSD, + most_traded_snapshots.dailyTotalRevenueUSD, + ] +) diff --git a/examples/dash_apps/README.md b/examples/dash_apps/README.md new file mode 100644 index 0000000..f41f6e7 --- /dev/null +++ b/examples/dash_apps/README.md @@ -0,0 +1,8 @@ +# Dash Examples + +## Instructions + +```bash +pip install "subgrounds[dash]" +python bar_chart.py +``` diff --git a/examples/bar_chart.py b/examples/dash_apps/bar_chart.py similarity index 100% rename from examples/bar_chart.py rename to examples/dash_apps/bar_chart.py diff --git a/examples/dashboard.py b/examples/dash_apps/dashboard.py similarity index 100% rename from examples/dashboard.py rename to examples/dash_apps/dashboard.py diff --git a/examples/double_query.py b/examples/dash_apps/double_query.py similarity index 100% rename from examples/double_query.py rename to examples/dash_apps/double_query.py diff --git a/examples/indicator.py b/examples/dash_apps/indicator.py similarity index 100% rename from examples/indicator.py rename to examples/dash_apps/indicator.py diff --git a/examples/indicator2.py b/examples/dash_apps/indicator2.py similarity index 100% rename from examples/indicator2.py rename to examples/dash_apps/indicator2.py diff --git a/examples/live_indicator.py b/examples/dash_apps/live_indicator.py similarity index 100% rename from examples/live_indicator.py rename to examples/dash_apps/live_indicator.py diff --git a/examples/olympus_dashboard.py b/examples/dash_apps/olympus_dashboard.py similarity index 100% rename from examples/olympus_dashboard.py rename to examples/dash_apps/olympus_dashboard.py diff --git a/examples/olympus_voting.py b/examples/dash_apps/olympus_voting.py similarity index 100% rename from examples/olympus_voting.py rename to examples/dash_apps/olympus_voting.py diff --git a/examples/synthetic_fields.py b/examples/dash_apps/synthetic_fields.py similarity index 100% rename from examples/synthetic_fields.py rename to examples/dash_apps/synthetic_fields.py diff --git a/examples/table.py b/examples/dash_apps/table.py similarity index 100% rename from examples/table.py rename to examples/dash_apps/table.py diff --git a/examples/uniswapv2_firehose.py b/examples/dash_apps/uniswapv2_firehose.py similarity index 100% rename from examples/uniswapv2_firehose.py rename to examples/dash_apps/uniswapv2_firehose.py From 501b480a93834978faa063633060389ef82b5931 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Wed, 12 Apr 2023 11:08:06 -0700 Subject: [PATCH 4/7] docs: adjust wording --- subgrounds/contrib/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subgrounds/contrib/README.md b/subgrounds/contrib/README.md index 8acd8b0..c995fe2 100644 --- a/subgrounds/contrib/README.md +++ b/subgrounds/contrib/README.md @@ -2,7 +2,7 @@ > Extra parts of subgrounds that may not fit in the main package ## What is this? -Contrib is a niche concept in some library packs that represent extra / contributed content to a library that may not fit in the main package. This might be due to the maintainer not willing to maintain said content, the content being deemed too experimental, or perhaps it's unknown whether it's a "good idea" or not. +Contrib is a niche concept in some libraries that represent extra / contributed content to a library that may not fit in the main package. This might be due to the maintainer not willing to maintain said content, the content being deemed too experimental, or perhaps it's unknown whether it's a "good idea" or not. > Relevant [Stackoverflow](https://softwareengineering.stackexchange.com/questions/252053/whats-in-the-contrib-folder) post From 6e14b89dd040d938210827d2defcfa80e397a896 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Thu, 13 Apr 2023 11:51:58 -0700 Subject: [PATCH 5/7] fix: update examples to user modern subgrounds --- examples/aave_v2.py | 4 +- examples/curve.py | 4 +- examples/dash_apps/bar_chart.py | 6 +- examples/dash_apps/dashboard.py | 8 +-- examples/dash_apps/double_query.py | 78 ------------------------ examples/dash_apps/indicator.py | 6 +- examples/dash_apps/indicator2.py | 39 ------------ examples/dash_apps/live_indicator.py | 6 +- examples/dash_apps/olympus_dashboard.py | 8 +-- examples/dash_apps/olympus_voting.py | 9 +-- examples/dash_apps/synthetic_fields.py | 7 +-- examples/dash_apps/table.py | 5 +- examples/dash_apps/uniswapv2_firehose.py | 4 +- subgrounds/contrib/README.md | 4 +- 14 files changed, 33 insertions(+), 155 deletions(-) delete mode 100644 examples/dash_apps/double_query.py delete mode 100644 examples/dash_apps/indicator2.py diff --git a/examples/aave_v2.py b/examples/aave_v2.py index 6629c84..c94169c 100644 --- a/examples/aave_v2.py +++ b/examples/aave_v2.py @@ -15,4 +15,6 @@ ) # Return query to a dataframe -sg.query_df([latest.name, latest.totalValueLockedUSD]) +df = sg.query_df([latest.name, latest.totalValueLockedUSD]) + +print(df) diff --git a/examples/curve.py b/examples/curve.py index 5bbebba..7d1baa9 100644 --- a/examples/curve.py +++ b/examples/curve.py @@ -25,10 +25,12 @@ # Querying: # - the name of the top 4 most traded pools, their 2 most liquid # pools' token symbols and their 2 most liquid pool's TVL in USD -sg.query_df( +df = sg.query_df( [ most_traded_pools.name, most_traded_snapshots.dailyVolumeUSD, most_traded_snapshots.dailyTotalRevenueUSD, ] ) + +print(df) diff --git a/examples/dash_apps/bar_chart.py b/examples/dash_apps/bar_chart.py index 5373115..ca07fdf 100644 --- a/examples/dash_apps/bar_chart.py +++ b/examples/dash_apps/bar_chart.py @@ -1,9 +1,9 @@ import dash from dash import html -from subgrounds.dash_wrappers import Graph -from subgrounds.plotly_wrappers import Bar, Figure -from subgrounds.subgrounds import Subgrounds +from subgrounds import Subgrounds +from subgrounds.contrib.dash import Graph +from subgrounds.contrib.plotly import Bar, Figure sg = Subgrounds() aaveV2 = sg.load_subgraph("https://api.thegraph.com/subgraphs/name/aave/protocol-v2") diff --git a/examples/dash_apps/dashboard.py b/examples/dash_apps/dashboard.py index b0cd812..74279b4 100644 --- a/examples/dash_apps/dashboard.py +++ b/examples/dash_apps/dashboard.py @@ -1,11 +1,9 @@ import dash from dash import html -# from subgrounds.components import AutoUpdate, BarChart, IndicatorWithChange -# from subgrounds.subgraph import Subgraph -from subgrounds.dash_wrappers import AutoUpdate, Graph -from subgrounds.plotly_wrappers import Bar, Figure, Indicator -from subgrounds.subgrounds import Subgrounds +from subgrounds.contrib.dash import AutoUpdate, Graph +from subgrounds.contrib.plotly import Bar, Figure, Indicator +from subgrounds import Subgrounds sg = Subgrounds() uniswapV2 = sg.load_subgraph( diff --git a/examples/dash_apps/double_query.py b/examples/dash_apps/double_query.py deleted file mode 100644 index 7012615..0000000 --- a/examples/dash_apps/double_query.py +++ /dev/null @@ -1,78 +0,0 @@ -from datetime import datetime - -import dash -from dash import html - -from subgrounds.dash_wrappers import Graph -from subgrounds.plotly_wrappers import Figure, Scatter -from subgrounds.schema import TypeRef -from subgrounds.subgraph import SyntheticField -from subgrounds.subgrounds import Subgrounds - -sg = Subgrounds() -uniswapV2 = sg.load_subgraph( - "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2" -) - -# This is unecessary, but nice for brevity -Query = uniswapV2.Query -PairDayData = uniswapV2.PairDayData - -# This is a synthetic field - -PairDayData.exchange_rate = PairDayData.reserve0 / PairDayData.reserve1 - -# This is a synthetic field -PairDayData.datetime = SyntheticField( - lambda timestamp: str(datetime.fromtimestamp(timestamp)), - TypeRef.Named(name="String", kind="SCALAR"), - PairDayData.date, -) - -uni_eth = Query.pairDayDatas( - orderBy=PairDayData.date, - orderDirection="desc", - first=100, - where=[PairDayData.pairAddress == "0xd3d2e2692501a5c9ca623199d38826e513033a17"], -) - -toke_eth = Query.pairDayDatas( - orderBy=PairDayData.date, - orderDirection="desc", - first=100, - where=[PairDayData.pairAddress == "0x5fa464cefe8901d66c09b85d5fcdc55b3738c688"], -) - -# Dashboard -app = dash.Dash(__name__) - -app.layout = html.Div( - html.Div( - [ - html.Div( - [ - Graph( - Figure( - subgrounds=sg, - traces=[ - Scatter( - x=uni_eth.datetime, - y=uni_eth.exchange_rate, - mode="lines", - ), - Scatter( - x=toke_eth.datetime, - y=toke_eth.exchange_rate, - mode="lines", - ), - ], - ) - ) - ] - ) - ] - ) -) - -if __name__ == "__main__": - app.run_server(debug=True) diff --git a/examples/dash_apps/indicator.py b/examples/dash_apps/indicator.py index 5165c9c..db42d90 100644 --- a/examples/dash_apps/indicator.py +++ b/examples/dash_apps/indicator.py @@ -1,9 +1,9 @@ import dash from dash import html -from subgrounds.dash_wrappers import Graph -from subgrounds.plotly_wrappers import Figure, Indicator -from subgrounds.subgrounds import Subgrounds +from subgrounds import Subgrounds +from subgrounds.contrib.dash import Graph +from subgrounds.contrib.plotly import Figure, Indicator sg = Subgrounds() uniswapV2 = sg.load_subgraph( diff --git a/examples/dash_apps/indicator2.py b/examples/dash_apps/indicator2.py deleted file mode 100644 index 4c6ef20..0000000 --- a/examples/dash_apps/indicator2.py +++ /dev/null @@ -1,39 +0,0 @@ -import dash -from dash import html - -from subgrounds.dash_wrappers import Graph -from subgrounds.plotly_wrappers import Figure, Indicator -from subgrounds.subgrounds import Subgrounds - -sg = Subgrounds() -uniswapV2 = sg.load_subgraph( - "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2" -) - -# This is unecessary, but nice for brevity -pair = uniswapV2.Query.pair(id="0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc") - -# Dashboard -app = dash.Dash(__name__) - -app.layout = html.Div( - html.Div( - [ - html.Div( - [ - Graph( - Figure( - subgrounds=sg, - traces=[ - Indicator(value=pair.token0Price), - ], - ) - ) - ] - ) - ] - ) -) - -if __name__ == "__main__": - app.run_server(debug=True) diff --git a/examples/dash_apps/live_indicator.py b/examples/dash_apps/live_indicator.py index 260c773..7407d12 100644 --- a/examples/dash_apps/live_indicator.py +++ b/examples/dash_apps/live_indicator.py @@ -1,9 +1,9 @@ import dash from dash import html -from subgrounds.dash_wrappers import AutoUpdate, Graph -from subgrounds.plotly_wrappers import Figure, Indicator -from subgrounds.subgrounds import Subgrounds +from subgrounds.contrib.dash import AutoUpdate, Graph +from subgrounds.contrib.plotly import Figure, Indicator +from subgrounds import Subgrounds sg = Subgrounds() uniswapV2 = sg.load_subgraph( diff --git a/examples/dash_apps/olympus_dashboard.py b/examples/dash_apps/olympus_dashboard.py index 17641d2..3e3d28e 100644 --- a/examples/dash_apps/olympus_dashboard.py +++ b/examples/dash_apps/olympus_dashboard.py @@ -3,11 +3,9 @@ import dash from dash import html -from subgrounds.dash_wrappers import Graph -from subgrounds.plotly_wrappers import Figure, Indicator, Scatter -from subgrounds.schema import TypeRef -from subgrounds.subgraph import SyntheticField -from subgrounds.subgrounds import Subgrounds +from subgrounds import Subgrounds, SyntheticField +from subgrounds.contrib.dash import Graph +from subgrounds.contrib.plotly import Figure, Indicator, Scatter sg = Subgrounds() olympusDAO = sg.load_subgraph( diff --git a/examples/dash_apps/olympus_voting.py b/examples/dash_apps/olympus_voting.py index bdd28bd..78ef71c 100644 --- a/examples/dash_apps/olympus_voting.py +++ b/examples/dash_apps/olympus_voting.py @@ -1,14 +1,11 @@ from datetime import datetime -from random import choice import dash from dash import html -from subgrounds.dash_wrappers import Graph -from subgrounds.plotly_wrappers import Figure, Indicator, Scatter -from subgrounds.schema import TypeRef -from subgrounds.subgraph import SyntheticField -from subgrounds.subgrounds import Subgrounds +from subgrounds import Subgrounds, SyntheticField +from subgrounds.contrib.dash import Graph +from subgrounds.contrib.plotly import Figure, Scatter sg = Subgrounds() olympusDAO = sg.load_subgraph( diff --git a/examples/dash_apps/synthetic_fields.py b/examples/dash_apps/synthetic_fields.py index 74a828e..af2f08c 100644 --- a/examples/dash_apps/synthetic_fields.py +++ b/examples/dash_apps/synthetic_fields.py @@ -3,11 +3,10 @@ import dash from dash import html -from subgrounds.dash_wrappers import Graph -from subgrounds.plotly_wrappers import Figure, Scatter +from subgrounds import Subgrounds, SyntheticField +from subgrounds.contrib.dash import Graph +from subgrounds.contrib.plotly import Figure, Scatter from subgrounds.schema import TypeRef -from subgrounds.subgraph import SyntheticField -from subgrounds.subgrounds import Subgrounds sg = Subgrounds() uniswapV2 = sg.load_subgraph( diff --git a/examples/dash_apps/table.py b/examples/dash_apps/table.py index 0a401ce..a7d50a7 100644 --- a/examples/dash_apps/table.py +++ b/examples/dash_apps/table.py @@ -1,9 +1,8 @@ import dash from dash import html -from subgrounds.dash_wrappers import DataTable -from subgrounds.plotly_wrappers import Bar, Figure -from subgrounds.subgrounds import Subgrounds +from subgrounds import Subgrounds +from subgrounds.contrib.dash import DataTable sg = Subgrounds() uniswapV2 = sg.load_subgraph( diff --git a/examples/dash_apps/uniswapv2_firehose.py b/examples/dash_apps/uniswapv2_firehose.py index 3f1d223..e34e696 100644 --- a/examples/dash_apps/uniswapv2_firehose.py +++ b/examples/dash_apps/uniswapv2_firehose.py @@ -1,8 +1,8 @@ import dash from dash import html -from subgrounds.dash_wrappers import AutoUpdate, DataTable -from subgrounds.subgrounds import Subgrounds +from subgrounds import Subgrounds +from subgrounds.contrib.dash import AutoUpdate, DataTable sg = Subgrounds() uniswapV2 = sg.load_subgraph( diff --git a/subgrounds/contrib/README.md b/subgrounds/contrib/README.md index c995fe2..9145395 100644 --- a/subgrounds/contrib/README.md +++ b/subgrounds/contrib/README.md @@ -11,7 +11,7 @@ For us, `subgrounds.contrib` will represent extra features and ideas with `subgr ## What's currently here? ### Plotly -Originally located in `subgrounds.plotly_wrappers`, `subgrounds.contrib.plotly` contains helpful wrappers on `plotly` objects that allow you to use `FieldPaths` directly without creating a `panda`'s `DataFrame`. +Originally located in `subgrounds.plotly_wrappers`, `subgrounds.contrib.plotly` contains helpful wrappers on `plotly` objects that allow you to use `FieldPaths` directly without creating a `pandas` `DataFrame`. ### Dash -Originally located in `subgrounds.dash_wrappers`, `subgrounds.contrib.dash` contains helpful wrappers on `dash` objects that allow you to use other wrapped visualization objects (currently `subgrounds.contrib.plotly`) in `dash` apps without creating `panda`'s `DataFrame`s. +Originally located in `subgrounds.dash_wrappers`, `subgrounds.contrib.dash` contains helpful wrappers on `dash` objects that allow you to use other wrapped visualization objects (currently `subgrounds.contrib.plotly`) in `dash` apps without creating `pandas` `DataFrame`s. From 7749f8f378fd5dcad727e2b507a50ed99654fab3 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Thu, 13 Apr 2023 11:52:37 -0700 Subject: [PATCH 6/7] fix: headers bugs w/ non-subgraph apis --- subgrounds/subgrounds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subgrounds/subgrounds.py b/subgrounds/subgrounds.py index 2f35d7e..99b0d1a 100644 --- a/subgrounds/subgrounds.py +++ b/subgrounds/subgrounds.py @@ -191,7 +191,7 @@ def execute_document(doc: Document) -> dict: ) else: return client.query( - doc.url, doc.graphql, variables=doc.variables, headers=headers + doc.url, doc.graphql, variables=doc.variables, headers=self.headers ) def transform_doc(transforms: list[DocumentTransform], doc: Document) -> dict: From f1d79e89f1594bc31d443fa2b248f745974dd468 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Thu, 13 Apr 2023 12:02:49 -0700 Subject: [PATCH 7/7] feat: `subgrounds.contrib.dash` and `subgrounds.contrib.plotly` --- subgrounds/contrib/dash/__init__.py | 6 ++++++ subgrounds/contrib/plotly/__init__.py | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/subgrounds/contrib/dash/__init__.py b/subgrounds/contrib/dash/__init__.py index 9ec172f..d479ad9 100644 --- a/subgrounds/contrib/dash/__init__.py +++ b/subgrounds/contrib/dash/__init__.py @@ -1,3 +1,9 @@ +"""Subgrounds Dash Components + +Extending dash components to be able to understand subgrounds logic. This includes other + extended components of other libraries such as `plotly`. +""" + from .abcs import Refreshable from .components import AutoUpdate, DataTable, Graph diff --git a/subgrounds/contrib/plotly/__init__.py b/subgrounds/contrib/plotly/__init__.py index a2f2e7c..d724cc4 100644 --- a/subgrounds/contrib/plotly/__init__.py +++ b/subgrounds/contrib/plotly/__init__.py @@ -1,3 +1,8 @@ +"""Subgrounds Plotly Components + +Extending plotly components to be able to understand subgrounds logic. +""" + from .figure import Figure from .traces import ( Bar,