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

provide plotly subpackages #4776

Merged
merged 1 commit into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions reflex/compiler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,24 +119,34 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
validate_imports(collapsed_import_dict)
import_dicts = []
for lib, fields in collapsed_import_dict.items():
default, rest = compile_import_statement(fields)

# prevent lib from being rendered on the page if all imports are non rendered kind
if not any(f.render for f in fields):
continue

if not lib:
if default:
raise ValueError("No default field allowed for empty library.")
if rest is None or len(rest) == 0:
raise ValueError("No fields to import.")
import_dicts.extend(get_import_dict(module) for module in sorted(rest))
continue
lib_paths: dict[str, list[ImportVar]] = {}

for field in fields:
lib_paths.setdefault(field.package_path, []).append(field)

# remove the version before rendering the package imports
lib = format.format_library_name(lib)
compiled = {
path: compile_import_statement(fields) for path, fields in lib_paths.items()
}

for path, (default, rest) in compiled.items():
if not lib:
if default:
raise ValueError("No default field allowed for empty library.")
if rest is None or len(rest) == 0:
raise ValueError("No fields to import.")
import_dicts.extend(get_import_dict(module) for module in sorted(rest))
continue

# remove the version before rendering the package imports
formatted_lib = format.format_library_name(lib) + (
path if path != "/" else ""
)

import_dicts.append(get_import_dict(lib, default, rest))
import_dicts.append(get_import_dict(formatted_lib, default, rest))
return import_dicts


Expand Down
31 changes: 29 additions & 2 deletions reflex/components/plotly/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
"""Plotly components."""

from .plotly import Plotly
from reflex.components.component import ComponentNamespace

plotly = Plotly.create
from .plotly import (
Plotly,
PlotlyBasic,
PlotlyCartesian,
PlotlyFinance,
PlotlyGeo,
PlotlyGl2d,
PlotlyGl3d,
PlotlyMapbox,
PlotlyStrict,
)


class PlotlyNamespace(ComponentNamespace):
"""Plotly namespace."""

__call__ = Plotly.create
basic = PlotlyBasic.create
cartesian = PlotlyCartesian.create
geo = PlotlyGeo.create
gl2d = PlotlyGl2d.create
gl3d = PlotlyGl3d.create
finance = PlotlyFinance.create
mapbox = PlotlyMapbox.create
strict = PlotlyStrict.create


plotly = PlotlyNamespace()
235 changes: 235 additions & 0 deletions reflex/components/plotly/plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from reflex.components.core.cond import color_mode_cond
from reflex.event import EventHandler, no_args_event_spec
from reflex.utils import console
from reflex.utils.imports import ImportDict, ImportVar
from reflex.vars.base import LiteralVar, Var

try:
Expand Down Expand Up @@ -278,3 +279,237 @@ def _render(self):
# Spread the figure dict over props, nothing to merge.
tag.special_props.append(Var(_js_expr=f"{{...{figure!s}}}"))
return tag


CREATE_PLOTLY_COMPONENT: ImportDict = {
"react-plotly.js": [
ImportVar(
tag="createPlotlyComponent",
is_default=True,
package_path="/factory",
),
]
}


def dynamic_plotly_import(name: str, package: str) -> str:
"""Create a dynamic import for a plotly component.

Args:
name: The name of the component.
package: The package path of the component.

Returns:
The dynamic import for the plotly component.
"""
return f"""
const {name} = dynamic(() => import('{package}').then(mod => createPlotlyComponent(mod)), {{ssr: false}})
"""


class PlotlyBasic(Plotly):
"""Display a basic plotly graph."""

tag: str = "BasicPlotlyPlot"

library = "[email protected]"

lib_dependencies: list[str] = ["[email protected]"]

def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports for the plotly basic component.

Returns:
The imports for the plotly basic component.
"""
return CREATE_PLOTLY_COMPONENT

def _get_dynamic_imports(self) -> str:
"""Get the dynamic imports for the plotly basic component.

Returns:
The dynamic imports for the plotly basic component.
"""
return dynamic_plotly_import(self.tag, "plotly.js-basic-dist-min")


class PlotlyCartesian(Plotly):
"""Display a plotly cartesian graph."""

tag: str = "CartesianPlotlyPlot"

library = "[email protected]"

lib_dependencies: list[str] = ["[email protected]"]

def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports for the plotly cartesian component.

Returns:
The imports for the plotly cartesian component.
"""
return CREATE_PLOTLY_COMPONENT

def _get_dynamic_imports(self) -> str:
"""Get the dynamic imports for the plotly cartesian component.

Returns:
The dynamic imports for the plotly cartesian component.
"""
return dynamic_plotly_import(self.tag, "plotly.js-cartesian-dist-min")


class PlotlyGeo(Plotly):
"""Display a plotly geo graph."""

tag: str = "GeoPlotlyPlot"

library = "[email protected]"

lib_dependencies: list[str] = ["[email protected]"]

def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports for the plotly geo component.

Returns:
The imports for the plotly geo component.
"""
return CREATE_PLOTLY_COMPONENT

def _get_dynamic_imports(self) -> str:
"""Get the dynamic imports for the plotly geo component.

Returns:
The dynamic imports for the plotly geo component.
"""
return dynamic_plotly_import(self.tag, "plotly.js-geo-dist-min")


class PlotlyGl3d(Plotly):
"""Display a plotly 3d graph."""

tag: str = "Gl3dPlotlyPlot"

library = "[email protected]"

lib_dependencies: list[str] = ["[email protected]"]

def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports for the plotly 3d component.

Returns:
The imports for the plotly 3d component.
"""
return CREATE_PLOTLY_COMPONENT

def _get_dynamic_imports(self) -> str:
"""Get the dynamic imports for the plotly 3d component.

Returns:
The dynamic imports for the plotly 3d component.
"""
return dynamic_plotly_import(self.tag, "plotly.js-gl3d-dist-min")


class PlotlyGl2d(Plotly):
"""Display a plotly 2d graph."""

tag: str = "Gl2dPlotlyPlot"

library = "[email protected]"

lib_dependencies: list[str] = ["[email protected]"]

def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports for the plotly 2d component.

Returns:
The imports for the plotly 2d component.
"""
return CREATE_PLOTLY_COMPONENT

def _get_dynamic_imports(self) -> str:
"""Get the dynamic imports for the plotly 2d component.

Returns:
The dynamic imports for the plotly 2d component.
"""
return dynamic_plotly_import(self.tag, "plotly.js-gl2d-dist-min")


class PlotlyMapbox(Plotly):
"""Display a plotly mapbox graph."""

tag: str = "MapboxPlotlyPlot"

library = "[email protected]"

lib_dependencies: list[str] = ["[email protected]"]

def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports for the plotly mapbox component.

Returns:
The imports for the plotly mapbox component.
"""
return CREATE_PLOTLY_COMPONENT

def _get_dynamic_imports(self) -> str:
"""Get the dynamic imports for the plotly mapbox component.

Returns:
The dynamic imports for the plotly mapbox component.
"""
return dynamic_plotly_import(self.tag, "plotly.js-mapbox-dist-min")


class PlotlyFinance(Plotly):
"""Display a plotly finance graph."""

tag: str = "FinancePlotlyPlot"

library = "[email protected]"

lib_dependencies: list[str] = ["[email protected]"]

def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports for the plotly finance component.

Returns:
The imports for the plotly finance component.
"""
return CREATE_PLOTLY_COMPONENT

def _get_dynamic_imports(self) -> str:
"""Get the dynamic imports for the plotly finance component.

Returns:
The dynamic imports for the plotly finance component.
"""
return dynamic_plotly_import(self.tag, "plotly.js-finance-dist-min")


class PlotlyStrict(Plotly):
"""Display a plotly strict graph."""

tag: str = "StrictPlotlyPlot"

library = "[email protected]"

lib_dependencies: list[str] = ["[email protected]"]

def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports for the plotly strict component.

Returns:
The imports for the plotly strict component.
"""
return CREATE_PLOTLY_COMPONENT

def _get_dynamic_imports(self) -> str:
"""Get the dynamic imports for the plotly strict component.

Returns:
The dynamic imports for the plotly strict component.
"""
return dynamic_plotly_import(self.tag, "plotly.js-strict-dist-min")
Loading