Skip to content

Commit 46b5b03

Browse files
authored
Merge pull request matplotlib#31714 from timhoffm/doc-gallery_order-txt
DOC: Add file-based listed gallery order for examples
2 parents 7767992 + bc2d2ed commit 46b5b03

11 files changed

Lines changed: 134 additions & 74 deletions

File tree

doc/devel/document.rst

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,24 +1100,18 @@ reference should always be the second to mention; see the example above.
11001100
Order examples
11011101
--------------
11021102

1103-
The order of the sections of the :ref:`tutorials` and the :ref:`gallery`, as
1104-
well as the order of the examples within each section are determined in a
1105-
two step process from within the :file:`/doc/sphinxext/gallery_order.py`:
1106-
1107-
* *Explicit order*: This file contains a list of folders for the section order
1108-
and a list of examples for the subsection order. The order of the items
1109-
shown in the doc pages is the order those items appear in those lists.
1110-
* *Implicit order*: If a folder or example is not in those lists, it will be
1111-
appended after the explicitly ordered items and all of those additional
1112-
items will be ordered by pathname (for the sections) or by filename
1113-
(for the subsections).
1114-
1115-
As a consequence, if you want to let your example appear in a certain
1116-
position in the gallery, extend those lists with your example.
1117-
In case no explicit order is desired or necessary, still make sure
1118-
to name your example consistently, i.e. use the main function or subject
1119-
of the example as first word in the filename; e.g. an image example
1120-
should ideally be named similar to :file:`imshow_mynewexample.py`.
1103+
The order of the sections in :ref:`plot_types`, :ref:`tutorials` and :ref:`gallery`
1104+
are determined through a custom Sphinx Gallery plugin in :file:`/doc/sphinxext/gallery_order.py`
1105+
Configuration happens directly in that file.
1106+
1107+
The order of examples within each gallery section is determined from a file
1108+
:file:`gallery_order.txt` in each folder. If the file is missing, the examples
1109+
are sorted alphabetically by filename.
1110+
1111+
:file:`gallery_order.txt` contains a list of example filenames (without the .py extension)
1112+
in the desired order, with an optional '*' to indicate where not-listed examples should be
1113+
placed. If '*' is not present, all examples must be listed, or an error will be raised.
1114+
Use this if you want to ensure that a full order is intentionally maintained.
11211115

11221116
.. _raw_restructured_gallery:
11231117

doc/sphinxext/gallery_order.py

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
"""
55

66
import itertools
7+
from pathlib import Path
8+
79
from sphinx_gallery.sorting import ExplicitOrder
810

911
# Gallery sections shall be displayed in the following order.
@@ -81,70 +83,87 @@ def __call__(self, item):
8183
else:
8284
return f"{self.ordered_list.index(UNSORTED):04d}{item}"
8385

84-
# Subsection order:
85-
# Subsections are ordered by filename, unless they appear in the following
86-
# lists in which case the list order determines the order within the section.
87-
# Examples/tutorials that do not appear in a list will be appended.
88-
89-
list_all = [
90-
# **Tutorials**
91-
# introductory
92-
"quick_start", "pyplot", "images", "lifecycle", "customizing",
93-
# intermediate
94-
"artists", "legend_guide", "color_cycle",
95-
"constrainedlayout_guide", "tight_layout_guide",
96-
# advanced
97-
# text
98-
"text_intro", "text_props",
99-
# colors
100-
"colors",
101-
102-
# **Examples**
103-
# animation
104-
"simple_anim", # Most basic example
105-
# color
106-
"color_demo",
107-
# pies
108-
"pie_features", "pie_demo2",
109-
# scales
110-
"scales", # Scales overview
111-
112-
# **Plot Types
113-
# Basic
114-
"plot", "scatter_plot", "bar", "stem", "step", "fill_between",
115-
# Arrays
116-
"imshow", "pcolormesh", "contour", "contourf",
117-
"barbs", "quiver", "streamplot",
118-
# Stats
119-
"hist_plot", "boxplot_plot", "errorbar_plot", "violin",
120-
"eventplot", "hist2d", "hexbin", "pie",
121-
# Unstructured
122-
"tricontour", "tricontourf", "tripcolor", "triplot",
123-
# Spines
124-
"spines", "spine_placement_demo", "spines_dropped",
125-
"multiple_yaxis_with_spines", "centered_spines_with_arrows",
126-
]
127-
explicit_subsection_order = [item + ".py" for item in list_all]
128-
129-
130-
class MplExplicitSubOrder(ExplicitOrder):
131-
"""For use within the 'within_subsection_order' key."""
86+
87+
class MplFileExplicitOrder(ExplicitOrder):
88+
"""
89+
An explicit order class that reads the order of examples from 'gallery_order.txt'.
90+
91+
For use with the sphinx_gallery 'within_subsection_order' key.
92+
93+
The file contains a list of example filenames (without the .py extension) in the
94+
desired order, with an optional '*' to indicate where not-listed examples should be
95+
placed.
96+
97+
If '*' is not present, all examples must be listed, or an error will be raised.
98+
Use this if you want to ensure that a full order is intentionally maintained.
99+
"""
132100
def __init__(self, src_dir):
133-
self.src_dir = src_dir # src_dir is unused here
134-
self.ordered_list = explicit_subsection_order
101+
ordered_list = self.read_gallery_order(Path(src_dir)) or []
102+
super().__init__(ordered_list)
103+
104+
@staticmethod
105+
def read_gallery_order(src_dir: Path):
106+
"""Return the list of examples to be sorted; read from 'gallery_order.txt'."""
107+
gallery_order_txt = src_dir / "gallery_order.txt"
108+
if not gallery_order_txt.exists():
109+
return None
110+
lines = [
111+
line.strip()
112+
for line in gallery_order_txt.read_text().splitlines()
113+
if line.strip() and not line.startswith("#")
114+
]
115+
116+
try:
117+
placeholder_index = lines.index("*")
118+
except ValueError:
119+
placeholder_index = None
120+
121+
lines = [line + ".py" for line in lines]
122+
123+
if placeholder_index is None:
124+
front = lines
125+
back = []
126+
else:
127+
front = lines[:placeholder_index]
128+
back = lines[placeholder_index+1:]
129+
130+
listed_examples = {*front, *back}
131+
existing_examples = {
132+
file.name for file in src_dir.iterdir() if file.suffix == ".py"
133+
}
134+
135+
non_existing_examples = listed_examples - existing_examples
136+
missing_examples = existing_examples - listed_examples
137+
print(f"non_existing_examples: {non_existing_examples}")
138+
print(f"missing_examples: {missing_examples}")
139+
140+
if non_existing_examples:
141+
raise ValueError(
142+
f"The following examples listed in {gallery_order_txt} do not exist: "
143+
f"{', '.join(non_existing_examples)}")
144+
if placeholder_index is None and missing_examples:
145+
raise ValueError(
146+
f"The following examples are not listed in {gallery_order_txt}. "
147+
f"Either include them or add a '*' to indicate where not listed "
148+
f"examples should be placed: "
149+
f"{', '.join(missing_examples)}"
150+
)
151+
152+
mid = list(sorted(missing_examples))
153+
return front + mid + back
135154

136155
def __call__(self, item):
137156
"""Return a string determining the sort order."""
138-
if item in self.ordered_list:
139-
return f"{self.ordered_list.index(item):04d}"
140-
else:
141-
# ensure not explicitly listed items come last.
142-
return "zzz" + item
157+
if not self.ordered_list:
158+
return item
159+
return f"{self.ordered_list.index(item):04d}"
143160

161+
def __repr__(self):
162+
return '<%s: %s>' % (self.__class__.__name__, self.ordered_list)
144163

145164
# Provide the above classes for use in conf.py
146165
sectionorder = MplExplicitOrder(explicit_order_folders)
147-
subsectionorder = MplExplicitSubOrder
166+
subsectionorder = MplFileExplicitOrder
148167

149168
_preserve_count = itertools.count()
150169

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Explicit example order. See https://matplotlib.org/devdocs/devel/document.html#order-examples
2+
simple_anim
3+
*
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Explicit example order. See https://matplotlib.org/devdocs/devel/document.html#order-examples
2+
color_demo
3+
*
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Explicit example order. See https://matplotlib.org/devdocs/devel/document.html#order-examples
2+
pie_features
3+
*
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Explicit example order. See https://matplotlib.org/devdocs/devel/document.html#order-examples
2+
scales
3+
*
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Explicit example order. See https://matplotlib.org/devdocs/devel/document.html#order-examples
2+
spines
3+
spine_placement_demo
4+
spines_dropped
5+
multiple_yaxis_with_spines
6+
centered_spines_with_arrows
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Explicit example order. See https://matplotlib.org/devdocs/devel/document.html#order-examples
2+
plot
3+
scatter_plot
4+
bar
5+
stem
6+
fill_between
7+
stackplot
8+
stairs
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Explicit example order. See https://matplotlib.org/devdocs/devel/document.html#order-examples
2+
hist_plot
3+
boxplot_plot
4+
errorbar_plot
5+
violin
6+
eventplot
7+
hist2d
8+
hexbin
9+
pie
10+
ecdf
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Explicit example order. See https://matplotlib.org/devdocs/devel/document.html#order-examples
2+
tricontour
3+
tricontourf
4+
tripcolor
5+
triplot

0 commit comments

Comments
 (0)