openbb-charting 2.1.0__tar.gz → 2.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/PKG-INFO +2 -4
  2. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/__init__.py +3 -0
  3. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/charting_router.py +175 -23
  4. openbb_charting-2.1.1/openbb_charting/core/assets/plotly-2.32.0.min.js +8 -0
  5. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/backend.py +1 -12
  6. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/openbb_figure.py +4 -2
  7. openbb_charting-2.1.1/openbb_charting/core/plotly.html +3621 -0
  8. openbb_charting-2.1.1/openbb_charting/core/table.html +166 -0
  9. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/query_params.py +17 -0
  10. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/utils/helpers.py +19 -0
  11. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/utils/relative_rotation.py +4 -7
  12. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/pyproject.toml +2 -4
  13. openbb_charting-2.1.0/openbb_charting/core/assets/plotly-2.24.2.min.js +0 -8
  14. openbb_charting-2.1.0/openbb_charting/core/plotly.html +0 -5285
  15. openbb_charting-2.1.0/openbb_charting/core/table.html +0 -326
  16. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/README.md +0 -0
  17. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/builder.py +0 -0
  18. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/__init__.py +0 -0
  19. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/assets/Terminal_icon.png +0 -0
  20. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/chart_style.py +0 -0
  21. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/config/__init__.py +0 -0
  22. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/config/openbb_styles.py +0 -0
  23. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/dummy_backend.py +0 -0
  24. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/__init__.py +0 -0
  25. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/base.py +0 -0
  26. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/data_classes.py +0 -0
  27. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/plugins/__init__.py +0 -0
  28. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/plugins/custom_indicators_plugin.py +0 -0
  29. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/plugins/momentum_plugin.py +0 -0
  30. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/plugins/overlap_plugin.py +0 -0
  31. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/plugins/trend_indicators_plugin.py +0 -0
  32. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/plugins/volatility_plugin.py +0 -0
  33. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/plugins/volume_plugin.py +0 -0
  34. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/ta_class.py +0 -0
  35. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/plotly_ta/ta_helpers.py +0 -0
  36. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/core/to_chart.py +0 -0
  37. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/styles/__init__.py +0 -0
  38. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/styles/colors.py +0 -0
  39. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/styles/default/dark.pltstyle.json +0 -0
  40. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/styles/default/light.pltstyle.json +0 -0
  41. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/styles/default/tables.pltstyle.json +0 -0
  42. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/utils/__init__.py +0 -0
  43. {openbb_charting-2.1.0 → openbb_charting-2.1.1}/openbb_charting/utils/generic_charts.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openbb-charting
3
- Version: 2.1.0
3
+ Version: 2.1.1
4
4
  Summary: Charting extension for OpenBB
5
5
  License: AGPL-3.0-only
6
6
  Author: OpenBB Team
@@ -13,14 +13,12 @@ Classifier: Programming Language :: Python :: 3.9
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
15
  Requires-Dist: nbformat (>=5.9.2,<6.0.0)
16
- Requires-Dist: openbb-core (>=1.2.1,<2.0.0)
16
+ Requires-Dist: openbb-core (>=1.2.3,<2.0.0)
17
17
  Requires-Dist: pandas-ta (>=0.3.14b,<0.4.0)
18
18
  Requires-Dist: plotly (>=5.17.0,<6.0.0)
19
19
  Requires-Dist: pywry (>=0.6.1,<0.7.0)
20
- Requires-Dist: reportlab (>=4.0.4,<5.0.0)
21
20
  Requires-Dist: scipy (>=1.10.0,<2.0.0)
22
21
  Requires-Dist: statsmodels (>=0.14.0,<0.15.0)
23
- Requires-Dist: svglib (>=1.5.1,<2.0.0)
24
22
  Description-Content-Type: text/markdown
25
23
 
26
24
  # OpenBB Charting extension
@@ -459,6 +459,9 @@ class Charting:
459
459
  )
460
460
  kwargs["provider"] = self._obbject.provider # pylint: disable=protected-access
461
461
  kwargs["extra"] = self._obbject.extra # pylint: disable=protected-access
462
+ kwargs["extra_params"] = kwargs["extra"]["metadata"].arguments.get(
463
+ "extra_params"
464
+ )
462
465
  if "kwargs" in kwargs:
463
466
  _kwargs = kwargs.pop("kwargs")
464
467
  kwargs.update(_kwargs.get("chart_params", {}))
@@ -8,6 +8,7 @@ from warnings import warn
8
8
  import pandas as pd
9
9
  from openbb_core.app.model.charts.chart import ChartFormat
10
10
  from openbb_core.app.utils import basemodel_to_df
11
+ from openbb_core.provider.abstract.data import Data
11
12
  from plotly.graph_objs import Figure
12
13
 
13
14
  from openbb_charting.core.chart_style import ChartStyle
@@ -19,6 +20,7 @@ from openbb_charting.utils import relative_rotation
19
20
  from openbb_charting.utils.generic_charts import bar_chart
20
21
  from openbb_charting.utils.helpers import (
21
22
  calculate_returns,
23
+ duration_sorter,
22
24
  heikin_ashi,
23
25
  should_share_axis,
24
26
  z_score_standardization,
@@ -31,7 +33,6 @@ def equity_price_performance(
31
33
  **kwargs,
32
34
  ) -> Tuple[Union[OpenBBFigure, Figure], Dict[str, Any]]: # noqa: PLR0912
33
35
  """Equity Price Performance Chart."""
34
-
35
36
  if "data" in kwargs and isinstance(kwargs["data"], pd.DataFrame):
36
37
  data = kwargs["data"]
37
38
  elif "data" in kwargs and isinstance(kwargs["data"], list):
@@ -83,7 +84,7 @@ def equity_price_performance(
83
84
  limit = kwargs.pop("limit", 10)
84
85
  chart_df = chart_df.head(limit) # type: ignore
85
86
 
86
- layout_kwargs: Dict[str, Any] = kwargs["layout_kwargs"] if "layout_kwargs" in kwargs else {} # type: ignore
87
+ layout_kwargs: Dict[str, Any] = kwargs.get("layout_kwargs", {})
87
88
 
88
89
  title = (
89
90
  f"{kwargs.pop('title')}" if "title" in kwargs else "Equity Price Performance"
@@ -140,7 +141,6 @@ def etf_price_performance(
140
141
 
141
142
  def etf_holdings(**kwargs) -> Tuple[Union[OpenBBFigure, Figure], Dict[str, Any]]:
142
143
  """Equity Compare Groups Chart."""
143
-
144
144
  if "data" in kwargs and isinstance(kwargs["data"], pd.DataFrame):
145
145
  data = kwargs["data"]
146
146
  elif "data" in kwargs and isinstance(kwargs["data"], list):
@@ -198,7 +198,6 @@ def equity_price_historical( # noqa: PLR0912
198
198
  **kwargs,
199
199
  ) -> Tuple[OpenBBFigure, Dict[str, Any]]:
200
200
  """Equity Price Historical Chart."""
201
-
202
201
  if "data" in kwargs and isinstance(kwargs["data"], pd.DataFrame):
203
202
  data = kwargs["data"]
204
203
  elif "data" in kwargs and isinstance(kwargs["data"], list):
@@ -406,7 +405,7 @@ def equity_price_historical( # noqa: PLR0912
406
405
  name=data[col].name,
407
406
  mode="lines",
408
407
  hovertemplate=hovertemplate,
409
- line=dict(width=1, color=LARGE_CYCLER[i % len(LARGE_CYCLER)]),
408
+ line=dict(width=2, color=LARGE_CYCLER[i % len(LARGE_CYCLER)]),
410
409
  yaxis=yaxis,
411
410
  )
412
411
 
@@ -512,7 +511,6 @@ def crypto_price_historical(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
512
511
 
513
512
  def _ta_ma(**kwargs):
514
513
  """Plot moving average helper."""
515
-
516
514
  index = (
517
515
  kwargs.get("index")
518
516
  if "index" in kwargs and kwargs.get("index") is not None
@@ -587,8 +585,6 @@ def _ta_ma(**kwargs):
587
585
  ma_df = ma_df.dropna()
588
586
  data = data.iloc[-len(ma_df) :]
589
587
 
590
- color = 0
591
-
592
588
  if (
593
589
  "candles" in kwargs
594
590
  and kwargs.get("candles") is True
@@ -600,7 +596,7 @@ def _ta_ma(**kwargs):
600
596
  else:
601
597
  ma_df[f"{target}".title()] = data[target]
602
598
 
603
- for col in ma_df.columns:
599
+ for i, col in enumerate(ma_df.columns):
604
600
  name = col.replace("_", " ")
605
601
  fig.add_scatter(
606
602
  x=ma_df.index,
@@ -608,10 +604,9 @@ def _ta_ma(**kwargs):
608
604
  name=name,
609
605
  mode="lines",
610
606
  hovertemplate=f"{name}: %{{y}}<extra></extra>",
611
- line=dict(width=1, color=LARGE_CYCLER[color]),
607
+ line=dict(width=1, color=LARGE_CYCLER[i]),
612
608
  showlegend=True,
613
609
  )
614
- color += 1
615
610
 
616
611
  fig.update_layout(
617
612
  title=dict(text=title, x=0.5, font=dict(size=16)),
@@ -685,7 +680,6 @@ def technical_zlma(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
685
680
 
686
681
  def technical_aroon(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
687
682
  """Technical Aroon Chart."""
688
-
689
683
  if "data" in kwargs and isinstance(kwargs["data"], pd.DataFrame):
690
684
  data = kwargs["data"]
691
685
  else:
@@ -726,7 +720,6 @@ def technical_aroon(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
726
720
 
727
721
  def technical_macd(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
728
722
  """Plot moving average convergence divergence chart."""
729
-
730
723
  if "data" in kwargs and isinstance(kwargs["data"], pd.DataFrame):
731
724
  data = kwargs["data"]
732
725
  else:
@@ -765,7 +758,6 @@ def technical_macd(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
765
758
 
766
759
  def technical_adx(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
767
760
  """Average directional movement index chart."""
768
-
769
761
  if "data" in kwargs and isinstance(kwargs["data"], pd.DataFrame):
770
762
  data = kwargs["data"]
771
763
  else:
@@ -801,7 +793,6 @@ def technical_adx(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
801
793
 
802
794
  def technical_rsi(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
803
795
  """Relative strength index chart."""
804
-
805
796
  if "data" in kwargs and isinstance(kwargs["data"], pd.DataFrame):
806
797
  data = kwargs["data"]
807
798
  else:
@@ -875,7 +866,6 @@ def technical_cones(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
875
866
  "orange",
876
867
  "blue",
877
868
  ]
878
- color = 0
879
869
 
880
870
  fig = OpenBBFigure()
881
871
 
@@ -883,7 +873,7 @@ def technical_cones(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
883
873
 
884
874
  text_color = "black" if ChartStyle().plt_style == "light" else "white"
885
875
 
886
- for col in df_ta.columns:
876
+ for i, col in enumerate(df_ta.columns):
887
877
  fig.add_scatter(
888
878
  x=df_ta.index,
889
879
  y=df_ta[col],
@@ -891,11 +881,10 @@ def technical_cones(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
891
881
  mode="lines+markers",
892
882
  hovertemplate=f"{col}: %{{y}}<extra></extra>",
893
883
  marker=dict(
894
- color=colors[color],
884
+ color=colors[i],
895
885
  size=11,
896
886
  ),
897
887
  )
898
- color += 1
899
888
 
900
889
  fig.set_title(title)
901
890
 
@@ -1064,7 +1053,7 @@ def economy_fred_series( # noqa: PLR0912
1064
1053
  if normalize:
1065
1054
  y1title = None
1066
1055
  title = f"{title} - Normalized" if title else "Normalized"
1067
- bar_mode = kwargs["barmode"] if "barmode" in kwargs else "group"
1056
+ bar_mode = kwargs.get("barmode", "group")
1068
1057
  fig = bar_chart(
1069
1058
  df_ta.reset_index(),
1070
1059
  "date",
@@ -1119,7 +1108,7 @@ def economy_fred_series( # noqa: PLR0912
1119
1108
  name=df_ta[col].name,
1120
1109
  mode="lines",
1121
1110
  hovertemplate=f"{df_ta[col].name}: %{{y}}<extra></extra>",
1122
- line=dict(width=1, color=LARGE_CYCLER[i % len(LARGE_CYCLER)]),
1111
+ line=dict(width=2, color=LARGE_CYCLER[i % len(LARGE_CYCLER)]),
1123
1112
  yaxis="y1" if kwargs.get("same_axis") is True else yaxes,
1124
1113
  )
1125
1114
 
@@ -1228,7 +1217,6 @@ def technical_relative_rotation(
1228
1217
  **kwargs: Any,
1229
1218
  ) -> Tuple["OpenBBFigure", Dict[str, Any]]:
1230
1219
  """Relative Rotation Chart."""
1231
-
1232
1220
  ratios_df = basemodel_to_df(kwargs["obbject_item"].rs_ratios, index="date") # type: ignore
1233
1221
  momentum_df = basemodel_to_df(kwargs["obbject_item"].rs_momentum, index="date") # type: ignore
1234
1222
  benchmark_symbol = kwargs["obbject_item"].benchmark # type: ignore
@@ -1253,7 +1241,7 @@ def technical_relative_rotation(
1253
1241
  ratios_df, momentum_df, benchmark_symbol, study, date # type: ignore
1254
1242
  )
1255
1243
 
1256
- figure = OpenBBFigure(fig)
1244
+ figure = OpenBBFigure(fig) # pylint: disable=E0606
1257
1245
  font_color = "black" if ChartStyle().plt_style == "light" else "white"
1258
1246
  figure.update_layout(
1259
1247
  paper_bgcolor="rgba(0,0,0,0)",
@@ -1292,3 +1280,167 @@ def technical_relative_rotation(
1292
1280
  content = figure.to_plotly_json()
1293
1281
 
1294
1282
  return figure, content
1283
+
1284
+
1285
+ def fixedincome_government_yield_curve( # noqa: PLR0912
1286
+ **kwargs,
1287
+ ) -> Tuple[OpenBBFigure, Dict[str, Any]]:
1288
+ """Government Yield Curve Chart."""
1289
+ data = kwargs.get("data", None)
1290
+ df: pd.DataFrame = pd.DataFrame()
1291
+ if data:
1292
+ if isinstance(data, pd.DataFrame) and not data.empty: # noqa: SIM108
1293
+ df = data
1294
+ elif isinstance(data, (list, Data)):
1295
+ df = basemodel_to_df(data, index=None) # type: ignore
1296
+ else:
1297
+ pass
1298
+ else:
1299
+ df = pd.DataFrame([d.model_dump() for d in kwargs["obbject_item"]]) # type: ignore
1300
+
1301
+ if df.empty:
1302
+ raise ValueError("Error: No data to plot.")
1303
+
1304
+ if "maturity" not in df.columns:
1305
+ raise ValueError("Error: Maturity column not found in the data.")
1306
+
1307
+ if "rate" not in df.columns:
1308
+ raise ValueError("Error: Rate column not found in the data.")
1309
+
1310
+ if "date" not in df.columns:
1311
+ raise ValueError("Error: Date column not found in the data.")
1312
+
1313
+ provider = kwargs.get("provider")
1314
+ df["date"] = df["date"].astype(str)
1315
+ maturities = duration_sorter(df["maturity"].unique().tolist())
1316
+
1317
+ # Use the supplied colors, if any.
1318
+ colors = kwargs.get("colors", [])
1319
+ if not colors:
1320
+ colors = LARGE_CYCLER
1321
+ color_count = 0
1322
+
1323
+ figure = OpenBBFigure().create_subplots(shared_xaxes=True)
1324
+ figure.update_layout(ChartStyle().plotly_template.get("layout", {}))
1325
+
1326
+ def create_fig(figure, df, dates, color_count, country: Optional[str] = None):
1327
+ """Create a scatter for each date in the data."""
1328
+ for date in dates:
1329
+ color = colors[color_count % len(colors)]
1330
+ plot_df = df[df["date"] == date].copy()
1331
+ plot_df["rate"] = plot_df["rate"].apply(lambda x: x * 100)
1332
+ plot_df = (
1333
+ plot_df.drop(columns=["date"])
1334
+ .set_index("maturity")
1335
+ .filter(items=maturities, axis=0)
1336
+ .reset_index()
1337
+ .rename(columns={"maturity": "Maturity", "rate": "Yield"})
1338
+ )
1339
+ plot_df["Maturity"] = [
1340
+ (
1341
+ d.split("_")[1] + " " + d.split("_")[0].title()
1342
+ if d != "long_term"
1343
+ else "Long Term"
1344
+ )
1345
+ for d in plot_df["Maturity"]
1346
+ ]
1347
+ figure.add_scatter(
1348
+ x=plot_df["Maturity"],
1349
+ y=plot_df["Yield"],
1350
+ # fill=fill,
1351
+ mode="lines+markers",
1352
+ name=f"{country} - {date}" if country else date,
1353
+ line=dict(width=3, color=color),
1354
+ marker=dict(size=10, color=color),
1355
+ hovertemplate=(
1356
+ "Maturity: %{x}<br>Yield: %{y}%<extra></extra>"
1357
+ if len(dates) == 1
1358
+ else "%{fullData.name}<br>Maturity: %{x}<br>Yield: %{y}%<extra></extra>"
1359
+ ),
1360
+ )
1361
+ color_count += 1
1362
+ return figure, color_count
1363
+
1364
+ dates = df.date.unique().tolist()
1365
+ figure, color_count = create_fig(figure, df, dates, color_count)
1366
+ extra_params = kwargs.get("extra_params")
1367
+ extra_params = (
1368
+ extra_params if isinstance(extra_params, dict) else extra_params.__dict__
1369
+ )
1370
+ # Set the title for the chart
1371
+ country: str = ""
1372
+ if provider in ("federal_reserve", "fmp"):
1373
+ country = "United States"
1374
+ elif provider == "ecb":
1375
+ curve_type = extra_params.get("yield_curve_type", "").replace("_", " ").title()
1376
+ grade = extra_params.get("rating", "").replace("_", " ")
1377
+ grade = grade.upper() if grade == "aaa" else "All Ratings"
1378
+ country = f"Euro Area ({grade}) {curve_type}"
1379
+ elif provider == "fred":
1380
+ curve_type = extra_params.get("yield_curve_type", "")
1381
+ curve_type = (
1382
+ "Real Rates"
1383
+ if curve_type == "real"
1384
+ else curve_type.replace("_", " ").title()
1385
+ )
1386
+ country = f"United States {curve_type}"
1387
+ elif provider == "econdb":
1388
+ country = extra_params.get("country", "")
1389
+ country = country.replace("_", " ").title() if country else "United States"
1390
+ country = country + " " if country else ""
1391
+ title = kwargs.get("title", "")
1392
+ if not title:
1393
+ title = f"{country}Yield Curve"
1394
+ if len(dates) == 1:
1395
+ title = f"{country} Yield Curve - {dates[0]}"
1396
+
1397
+ # Update the layout of the figure.
1398
+ figure.update_layout(
1399
+ title=dict(text=title, x=0.5, font=dict(size=20)),
1400
+ plot_bgcolor="rgba(255,255,255,0)",
1401
+ xaxis=dict(
1402
+ title="Maturity",
1403
+ ticklen=0,
1404
+ showgrid=False,
1405
+ type="category",
1406
+ categoryorder="array",
1407
+ categoryarray=(
1408
+ [
1409
+ (
1410
+ d.split("_")[1] + " " + d.split("_")[0].title()
1411
+ if d != "long_term"
1412
+ else "Long Term"
1413
+ )
1414
+ for d in maturities
1415
+ ]
1416
+ ),
1417
+ ),
1418
+ yaxis=dict(
1419
+ title="Yield (%)",
1420
+ ticklen=0,
1421
+ showgrid=True,
1422
+ gridcolor="rgba(128,128,128,0.3)",
1423
+ ),
1424
+ legend=dict(
1425
+ orientation="v",
1426
+ yanchor="top",
1427
+ xanchor="right",
1428
+ y=0.95,
1429
+ x=0,
1430
+ xref="paper",
1431
+ font=dict(size=12),
1432
+ bgcolor="rgba(0,0,0,0)",
1433
+ ),
1434
+ margin=dict(
1435
+ b=25,
1436
+ t=10,
1437
+ ),
1438
+ )
1439
+
1440
+ layout_kwargs = kwargs.get("layout_kwargs", {})
1441
+ if layout_kwargs:
1442
+ figure.update_layout(layout_kwargs)
1443
+
1444
+ content = figure.show(external=True)
1445
+
1446
+ return figure, content