Skip to content

Commit ecff469

Browse files
jorgepilotoRevathyvenugopal162pyansys-ci-botMaxJPRey
authored
feat: enable matplotlib and plotly in examples (#567)
Co-authored-by: Revathyvenugopal162 <[email protected]> Co-authored-by: pyansys-ci-bot <[email protected]> Co-authored-by: Revathy Venugopal <[email protected]> Co-authored-by: Maxime Rey <[email protected]>
1 parent 3effe7b commit ecff469

File tree

7 files changed

+1549
-44
lines changed

7 files changed

+1549
-44
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ repos:
1111
rev: v2.3.0
1212
hooks:
1313
- id: codespell
14+
exclude: doc/source/examples/nbsphinx/jupyter-notebook.ipynb
1415
args: ["--ignore-words", "doc/styles/config/vocabularies/ANSYS/accept.txt", "-w"]
1516

1617
- repo: https://github.com/pycontribs/mirrors-prettier

doc/changelog.d/567.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enable matplotlib and plotly in examples

doc/source/conf.py

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
import os
55
from pathlib import Path
66
import subprocess
7-
from typing import List
7+
from typing import Dict, List
88

99
from github import Github
10+
import plotly.io as pio
1011
import pyvista
1112
import requests
13+
from sphinx.application import Sphinx
1214
from sphinx.builders.latex import LaTeXBuilder
1315

1416
from ansys_sphinx_theme import (
@@ -25,6 +27,7 @@
2527
watermark,
2628
)
2729

30+
pio.renderers.default = "sphinx_gallery"
2831
THIS_PATH = Path(__file__).parent.resolve()
2932
PYANSYS_LIGHT_SQUARE = (THIS_PATH / "_static" / "pyansys_light_square.png").resolve()
3033
EXAMPLE_PATH = (THIS_PATH / "examples" / "sphinx_examples").resolve()
@@ -75,6 +78,9 @@
7578
},
7679
}
7780

81+
html_js_files = ["https://cdn.plot.ly/plotly-3.0.1.min.js"]
82+
83+
7884
index_patterns = {
7985
"examples/api/": ALL_NODES,
8086
"examples/sphinx_examples/": TITLES + PARAGRAPHS,
@@ -140,8 +146,8 @@
140146
exclude_patterns = [
141147
"links.rst",
142148
"examples/sphinx-gallery/README.rst",
143-
"examples/gallery-examples/*.ipynb",
144149
"sg_execution_times.rst",
150+
"examples/gallery-examples/*.ipynb",
145151
]
146152
rst_epilog = ""
147153
with Path.open(THIS_PATH / "links.rst", "r") as f:
@@ -245,8 +251,6 @@ def download_and_process_files(example_links: List[str]) -> List[str]:
245251

246252
if not BUILD_EXAMPLES:
247253
exclude_patterns.extend(["examples.rst", "examples/**", "examples/api/**"])
248-
249-
250254
else:
251255
# Autoapi examples
252256
extensions.append("ansys_sphinx_theme.extension.autoapi")
@@ -262,30 +266,29 @@ def download_and_process_files(example_links: List[str]) -> List[str]:
262266
extensions.extend(["nbsphinx", "sphinx_gallery.gen_gallery"])
263267
sphinx_gallery_conf = {
264268
# path to your examples scripts
265-
"examples_dirs": ["examples/sphinx-gallery"],
269+
"examples_dirs": ["examples/sphinx-gallery/"],
266270
# path where to save gallery generated examples
267-
"gallery_dirs": ["examples/gallery-examples"],
271+
"gallery_dirs": ["examples/gallery-examples/"],
268272
# Pattern to search for example files
269-
"filename_pattern": r"sphinx_gallery\.py",
273+
"filename_pattern": r"\.py",
270274
# Remove the "Download all examples" button from the top level gallery
271275
"download_all_examples": False,
272276
# Modules for which function level galleries are created. In
273-
"image_scrapers": ("pyvista", "matplotlib"),
277+
"image_scrapers": ("pyvista", "matplotlib", "plotly.io._sg_scraper.plotly_sg_scraper"),
274278
"default_thumb_file": str(PYANSYS_LIGHT_SQUARE),
275279
}
280+
pyvista.BUILDING_GALLERY = True
281+
pyvista.OFF_SCREEN = True
276282

277283
nbsphinx_prolog = """
278284
Download this example as a :download:`Jupyter notebook </{{ env.docname }}.ipynb>`.
279285
280286
----
281287
"""
282-
nbsphinx_execute = "always"
283288
nbsphinx_thumbnails = {
284289
"examples/nbsphinx/jupyter-notebook": "_static/pyansys_light_square.png",
285290
}
286291

287-
pyvista.BUILDING_GALLERY = True
288-
289292
# Third party examples
290293
example_links = extract_example_links(
291294
"executablebooks/sphinx-design",
@@ -309,3 +312,30 @@ def download_and_process_files(example_links: List[str]) -> List[str]:
309312
jinja_globals = {
310313
"ANSYS_SPHINX_THEME_VERSION": version,
311314
}
315+
316+
317+
def revert_exclude_patterns(app, env):
318+
"""Revert the exclude patterns.
319+
320+
Parameters
321+
----------
322+
app : Sphinx
323+
Sphinx application instance.
324+
env : BuildEnvironment
325+
The build environment.
326+
327+
Notes
328+
-----
329+
Remove the examples/gallery-examples/*.ipynb pattern from the exclude patterns.
330+
When the nbsphinx extension is enabled, the exclude patterns are modified
331+
to exclude the examples/gallery-examples/*.ipynb pattern. This function reverts
332+
the exclude patterns to their original state.
333+
"""
334+
excluded_pattern = env.config.exclude_patterns
335+
excluded_pattern.remove("examples/gallery-examples/*.ipynb")
336+
env.config.exclude_patterns = excluded_pattern
337+
338+
339+
def setup(app: Sphinx) -> Dict:
340+
"""Sphinx hooks to add to the setup."""
341+
app.connect("env-updated", revert_exclude_patterns)

doc/source/examples/nbsphinx/jupyter-notebook.ipynb

Lines changed: 1396 additions & 3 deletions
Large diffs are not rendered by default.

doc/source/examples/sphinx-gallery/sphinx-gallery.py

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,61 @@
6262
plotter.title = "3D Sphere Visualization"
6363
plotter.show()
6464

65+
###############################################################################
66+
# Figures with Matplotlib
67+
# ~~~~~~~~~~~~~~~~~~~~~~~
68+
# This example shows how to render a figure using Matplotlib.
69+
70+
import matplotlib.pyplot as plt
71+
import numpy as np
72+
73+
time = np.linspace(0, 2 * np.pi, 100)
74+
75+
fig, ax = plt.subplots()
76+
ax.plot(time, np.cos(time), color="blue", label=r"$\cos{(t)}$")
77+
ax.plot(time, np.sin(time), color="red", label=r"$\sin{(t)}$")
78+
79+
ax.set_xlabel("Time [time units]")
80+
ax.set_ylabel("Amplitude [distance units]")
81+
ax.set_title("Trigonometric functions")
82+
83+
plt.show()
84+
85+
###############################################################################
86+
# Figures with Plotly
87+
# ~~~~~~~~~~~~~~~~~~~
88+
# This example shows how to render a figure using Plotly.
89+
90+
import plotly.graph_objs as go
91+
92+
# More info: https://plotly.com/python/renderers/
93+
94+
time = np.linspace(0, 2 * np.pi, 100)
95+
96+
cos_trace = go.Scatter(x=time, y=np.cos(time), mode="lines", name="cos(t)")
97+
sin_trace = go.Scatter(x=time, y=np.sin(time), mode="lines", name="sin(t)")
98+
99+
fig = go.Figure(data=[cos_trace, sin_trace])
100+
101+
fig
102+
###############################################################################
103+
104+
import numpy as np
105+
import plotly.express as px
106+
107+
df = px.data.tips()
108+
fig = px.bar(
109+
df,
110+
x="sex",
111+
y="total_bill",
112+
facet_col="day",
113+
color="smoker",
114+
barmode="group",
115+
template="presentation+plotly",
116+
)
117+
fig.update_layout(height=400)
118+
fig
119+
65120
###############################################################################
66121
# Render equations using IPython ``math``
67122
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -80,18 +135,22 @@
80135
Latex(r"This is a \LaTeX{} equation: $a^2 + b^2 = c^2$")
81136

82137
###############################################################################
83-
# Render a table in markdown
84-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
85-
# This is an example to render a table inside the markdown with Sphinx-Gallery.
138+
# Render a table
139+
# ~~~~~~~~~~~~~~
140+
# This is an example to render a table with Sphinx-Gallery.
141+
#
142+
# +--------------------------------+--------------------------------+------------------------------+
143+
# | A | B | A and B |
144+
# +================================+================================+==============================+
145+
# | False | False | False |
146+
# +--------------------------------+--------------------------------+------------------------------+
147+
# | True | False | False |
148+
# +--------------------------------+--------------------------------+------------------------------+
149+
# | False | True | False |
150+
# +--------------------------------+--------------------------------+------------------------------+
151+
# | True | True | True |
152+
# +--------------------------------+--------------------------------+------------------------------+
86153
#
87-
# ====== ====== =======
88-
# A B A and B
89-
# ====== ====== =======
90-
# False False False
91-
# True False False
92-
# False True False
93-
# True True True
94-
# ====== ====== =======
95154

96155
###############################################################################
97156
# Render a table using pandas
@@ -112,3 +171,5 @@
112171
df.head()
113172

114173
###############################################################################
174+
175+
# %%

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ doc = [
5151
"numpydoc==1.8.0",
5252
"pandas==2.2.3",
5353
"Pillow>=9.0",
54+
"plotly==6.0.1",
5455
"PyGitHub==2.6.1",
5556
"pyvista[jupyter]==0.44.2",
5657
"PyYAML==6.0.2",

src/ansys_sphinx_theme/extension/linkcode.py

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,14 @@ def sphinx_linkcode_resolve(
107107
if domain != "py":
108108
return None
109109

110-
modname = info["module"]
111-
fullname = info["fullname"]
110+
modname = info.get("module")
111+
fullname = info.get("fullname")
112112

113-
# Little clean up to avoid library.library
114-
if fullname.startswith(modname):
113+
if not modname or not fullname:
114+
return None
115+
116+
# Cleanup to avoid redundant prefixes like library.library
117+
if fullname.startswith(modname + "."):
115118
fullname = fullname[len(modname) + 1 :]
116119

117120
submod = sys.modules.get(modname)
@@ -122,49 +125,64 @@ def sphinx_linkcode_resolve(
122125
for part in fullname.split("."):
123126
try:
124127
obj = getattr(obj, part)
125-
except Exception:
128+
except AttributeError:
126129
return None
127130

128-
# Deal with our decorators properly
131+
# Handle property decorators properly
129132
while hasattr(obj, "fget"):
130133
obj = obj.fget
131134

135+
# Get the source file path
132136
try:
133137
fn = inspect.getsourcefile(obj)
134-
except Exception: # pragma: no cover
138+
except Exception:
135139
fn = None
136140

137-
if not fn: # pragma: no cover
141+
if not fn:
138142
try:
139143
fn = inspect.getsourcefile(sys.modules[obj.__module__])
140144
except Exception:
141145
return None
142-
return None
143146

144-
fn = Path(fn).resolve().relative_to(Path(__file__).resolve().parent)
145-
fn_components = fn.parts
147+
fn = Path(fn).resolve()
148+
149+
# Ensure fn is within the expected repository directory
150+
base_path = Path(__file__).resolve().parent
151+
if not fn.is_relative_to(base_path):
152+
return None # Avoid errors due to files outside the expected path
153+
154+
try:
155+
fn = fn.relative_to(base_path)
156+
except ValueError:
157+
return None # Avoid errors when the file is not within the base path
158+
159+
fn_components = list(fn.parts)
146160

147161
if not source_path:
148162
module = modname.split(".")[0]
149-
repo_index = fn_components.index(module)
163+
if module in fn_components:
164+
repo_index = fn_components.index(module)
165+
else:
166+
return None # Module name should be in the path
150167
else:
151168
if source_path in fn_components:
152169
repo_index = fn_components.index(source_path)
153170
else:
154171
module = modname.split(".")[0]
155-
repo_index = fn_components.index(module)
156-
fn_components.insert(repo_index, source_path)
172+
if module in fn_components:
173+
repo_index = fn_components.index(module)
174+
fn_components.insert(repo_index, source_path)
175+
else:
176+
return None # Ensure we don't insert at an invalid index
177+
157178
fn = "/".join(fn_components[repo_index:])
158179

159180
try:
160181
source, lineno = inspect.getsourcelines(obj)
161-
except Exception: # pragma: no cover
182+
except Exception:
162183
lineno = None
163184

164-
if lineno and not edit:
165-
linespec = f"#L{lineno}-L{lineno + len(source) - 1}"
166-
else:
167-
linespec = ""
185+
linespec = f"#L{lineno}-L{lineno + len(source) - 1}" if lineno and not edit else ""
168186

169187
blob_or_edit = "edit" if edit else "blob"
170188
return f"http://github.com/{library}/{blob_or_edit}/{github_version}/{fn}{linespec}"

0 commit comments

Comments
 (0)