Skip to content

Commit 9c9491a

Browse files
adhami3310masenf
authored andcommitted
provide plotly subpackages (#4776)
1 parent 8ef6fb5 commit 9c9491a

File tree

5 files changed

+1054
-14
lines changed

5 files changed

+1054
-14
lines changed

reflex/compiler/utils.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,24 +119,34 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
119119
validate_imports(collapsed_import_dict)
120120
import_dicts = []
121121
for lib, fields in collapsed_import_dict.items():
122-
default, rest = compile_import_statement(fields)
123-
124122
# prevent lib from being rendered on the page if all imports are non rendered kind
125123
if not any(f.render for f in fields):
126124
continue
127125

128-
if not lib:
129-
if default:
130-
raise ValueError("No default field allowed for empty library.")
131-
if rest is None or len(rest) == 0:
132-
raise ValueError("No fields to import.")
133-
import_dicts.extend(get_import_dict(module) for module in sorted(rest))
134-
continue
126+
lib_paths: dict[str, list[ImportVar]] = {}
127+
128+
for field in fields:
129+
lib_paths.setdefault(field.package_path, []).append(field)
135130

136-
# remove the version before rendering the package imports
137-
lib = format.format_library_name(lib)
131+
compiled = {
132+
path: compile_import_statement(fields) for path, fields in lib_paths.items()
133+
}
134+
135+
for path, (default, rest) in compiled.items():
136+
if not lib:
137+
if default:
138+
raise ValueError("No default field allowed for empty library.")
139+
if rest is None or len(rest) == 0:
140+
raise ValueError("No fields to import.")
141+
import_dicts.extend(get_import_dict(module) for module in sorted(rest))
142+
continue
143+
144+
# remove the version before rendering the package imports
145+
formatted_lib = format.format_library_name(lib) + (
146+
path if path != "/" else ""
147+
)
138148

139-
import_dicts.append(get_import_dict(lib, default, rest))
149+
import_dicts.append(get_import_dict(formatted_lib, default, rest))
140150
return import_dicts
141151

142152

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
"""Plotly components."""
22

3-
from .plotly import Plotly
3+
from reflex.components.component import ComponentNamespace
44

5-
plotly = Plotly.create
5+
from .plotly import (
6+
Plotly,
7+
PlotlyBasic,
8+
PlotlyCartesian,
9+
PlotlyFinance,
10+
PlotlyGeo,
11+
PlotlyGl2d,
12+
PlotlyGl3d,
13+
PlotlyMapbox,
14+
PlotlyStrict,
15+
)
16+
17+
18+
class PlotlyNamespace(ComponentNamespace):
19+
"""Plotly namespace."""
20+
21+
__call__ = Plotly.create
22+
basic = PlotlyBasic.create
23+
cartesian = PlotlyCartesian.create
24+
geo = PlotlyGeo.create
25+
gl2d = PlotlyGl2d.create
26+
gl3d = PlotlyGl3d.create
27+
finance = PlotlyFinance.create
28+
mapbox = PlotlyMapbox.create
29+
strict = PlotlyStrict.create
30+
31+
32+
plotly = PlotlyNamespace()

reflex/components/plotly/plotly.py

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from reflex.components.core.cond import color_mode_cond
1111
from reflex.event import EventHandler, no_args_event_spec
1212
from reflex.utils import console
13+
from reflex.utils.imports import ImportDict, ImportVar
1314
from reflex.vars.base import LiteralVar, Var
1415

1516
try:
@@ -278,3 +279,237 @@ def _render(self):
278279
# Spread the figure dict over props, nothing to merge.
279280
tag.special_props.append(Var(_js_expr=f"{{...{figure!s}}}"))
280281
return tag
282+
283+
284+
CREATE_PLOTLY_COMPONENT: ImportDict = {
285+
"react-plotly.js": [
286+
ImportVar(
287+
tag="createPlotlyComponent",
288+
is_default=True,
289+
package_path="/factory",
290+
),
291+
]
292+
}
293+
294+
295+
def dynamic_plotly_import(name: str, package: str) -> str:
296+
"""Create a dynamic import for a plotly component.
297+
298+
Args:
299+
name: The name of the component.
300+
package: The package path of the component.
301+
302+
Returns:
303+
The dynamic import for the plotly component.
304+
"""
305+
return f"""
306+
const {name} = dynamic(() => import('{package}').then(mod => createPlotlyComponent(mod)), {{ssr: false}})
307+
"""
308+
309+
310+
class PlotlyBasic(Plotly):
311+
"""Display a basic plotly graph."""
312+
313+
tag: str = "BasicPlotlyPlot"
314+
315+
library = "[email protected]"
316+
317+
lib_dependencies: list[str] = ["[email protected]"]
318+
319+
def add_imports(self) -> ImportDict | list[ImportDict]:
320+
"""Add imports for the plotly basic component.
321+
322+
Returns:
323+
The imports for the plotly basic component.
324+
"""
325+
return CREATE_PLOTLY_COMPONENT
326+
327+
def _get_dynamic_imports(self) -> str:
328+
"""Get the dynamic imports for the plotly basic component.
329+
330+
Returns:
331+
The dynamic imports for the plotly basic component.
332+
"""
333+
return dynamic_plotly_import(self.tag, "plotly.js-basic-dist-min")
334+
335+
336+
class PlotlyCartesian(Plotly):
337+
"""Display a plotly cartesian graph."""
338+
339+
tag: str = "CartesianPlotlyPlot"
340+
341+
library = "[email protected]"
342+
343+
lib_dependencies: list[str] = ["[email protected]"]
344+
345+
def add_imports(self) -> ImportDict | list[ImportDict]:
346+
"""Add imports for the plotly cartesian component.
347+
348+
Returns:
349+
The imports for the plotly cartesian component.
350+
"""
351+
return CREATE_PLOTLY_COMPONENT
352+
353+
def _get_dynamic_imports(self) -> str:
354+
"""Get the dynamic imports for the plotly cartesian component.
355+
356+
Returns:
357+
The dynamic imports for the plotly cartesian component.
358+
"""
359+
return dynamic_plotly_import(self.tag, "plotly.js-cartesian-dist-min")
360+
361+
362+
class PlotlyGeo(Plotly):
363+
"""Display a plotly geo graph."""
364+
365+
tag: str = "GeoPlotlyPlot"
366+
367+
library = "[email protected]"
368+
369+
lib_dependencies: list[str] = ["[email protected]"]
370+
371+
def add_imports(self) -> ImportDict | list[ImportDict]:
372+
"""Add imports for the plotly geo component.
373+
374+
Returns:
375+
The imports for the plotly geo component.
376+
"""
377+
return CREATE_PLOTLY_COMPONENT
378+
379+
def _get_dynamic_imports(self) -> str:
380+
"""Get the dynamic imports for the plotly geo component.
381+
382+
Returns:
383+
The dynamic imports for the plotly geo component.
384+
"""
385+
return dynamic_plotly_import(self.tag, "plotly.js-geo-dist-min")
386+
387+
388+
class PlotlyGl3d(Plotly):
389+
"""Display a plotly 3d graph."""
390+
391+
tag: str = "Gl3dPlotlyPlot"
392+
393+
library = "[email protected]"
394+
395+
lib_dependencies: list[str] = ["[email protected]"]
396+
397+
def add_imports(self) -> ImportDict | list[ImportDict]:
398+
"""Add imports for the plotly 3d component.
399+
400+
Returns:
401+
The imports for the plotly 3d component.
402+
"""
403+
return CREATE_PLOTLY_COMPONENT
404+
405+
def _get_dynamic_imports(self) -> str:
406+
"""Get the dynamic imports for the plotly 3d component.
407+
408+
Returns:
409+
The dynamic imports for the plotly 3d component.
410+
"""
411+
return dynamic_plotly_import(self.tag, "plotly.js-gl3d-dist-min")
412+
413+
414+
class PlotlyGl2d(Plotly):
415+
"""Display a plotly 2d graph."""
416+
417+
tag: str = "Gl2dPlotlyPlot"
418+
419+
library = "[email protected]"
420+
421+
lib_dependencies: list[str] = ["[email protected]"]
422+
423+
def add_imports(self) -> ImportDict | list[ImportDict]:
424+
"""Add imports for the plotly 2d component.
425+
426+
Returns:
427+
The imports for the plotly 2d component.
428+
"""
429+
return CREATE_PLOTLY_COMPONENT
430+
431+
def _get_dynamic_imports(self) -> str:
432+
"""Get the dynamic imports for the plotly 2d component.
433+
434+
Returns:
435+
The dynamic imports for the plotly 2d component.
436+
"""
437+
return dynamic_plotly_import(self.tag, "plotly.js-gl2d-dist-min")
438+
439+
440+
class PlotlyMapbox(Plotly):
441+
"""Display a plotly mapbox graph."""
442+
443+
tag: str = "MapboxPlotlyPlot"
444+
445+
library = "[email protected]"
446+
447+
lib_dependencies: list[str] = ["[email protected]"]
448+
449+
def add_imports(self) -> ImportDict | list[ImportDict]:
450+
"""Add imports for the plotly mapbox component.
451+
452+
Returns:
453+
The imports for the plotly mapbox component.
454+
"""
455+
return CREATE_PLOTLY_COMPONENT
456+
457+
def _get_dynamic_imports(self) -> str:
458+
"""Get the dynamic imports for the plotly mapbox component.
459+
460+
Returns:
461+
The dynamic imports for the plotly mapbox component.
462+
"""
463+
return dynamic_plotly_import(self.tag, "plotly.js-mapbox-dist-min")
464+
465+
466+
class PlotlyFinance(Plotly):
467+
"""Display a plotly finance graph."""
468+
469+
tag: str = "FinancePlotlyPlot"
470+
471+
library = "[email protected]"
472+
473+
lib_dependencies: list[str] = ["[email protected]"]
474+
475+
def add_imports(self) -> ImportDict | list[ImportDict]:
476+
"""Add imports for the plotly finance component.
477+
478+
Returns:
479+
The imports for the plotly finance component.
480+
"""
481+
return CREATE_PLOTLY_COMPONENT
482+
483+
def _get_dynamic_imports(self) -> str:
484+
"""Get the dynamic imports for the plotly finance component.
485+
486+
Returns:
487+
The dynamic imports for the plotly finance component.
488+
"""
489+
return dynamic_plotly_import(self.tag, "plotly.js-finance-dist-min")
490+
491+
492+
class PlotlyStrict(Plotly):
493+
"""Display a plotly strict graph."""
494+
495+
tag: str = "StrictPlotlyPlot"
496+
497+
library = "[email protected]"
498+
499+
lib_dependencies: list[str] = ["[email protected]"]
500+
501+
def add_imports(self) -> ImportDict | list[ImportDict]:
502+
"""Add imports for the plotly strict component.
503+
504+
Returns:
505+
The imports for the plotly strict component.
506+
"""
507+
return CREATE_PLOTLY_COMPONENT
508+
509+
def _get_dynamic_imports(self) -> str:
510+
"""Get the dynamic imports for the plotly strict component.
511+
512+
Returns:
513+
The dynamic imports for the plotly strict component.
514+
"""
515+
return dynamic_plotly_import(self.tag, "plotly.js-strict-dist-min")

0 commit comments

Comments
 (0)