tesorotools-python 0.0.48__tar.gz → 0.0.50__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 (79) hide show
  1. tesorotools_python-0.0.50/.gitignore +35 -0
  2. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/PKG-INFO +1 -1
  3. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/pyproject.toml +8 -2
  4. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/__init__.py +15 -0
  5. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/artists/__init__.py +2 -0
  6. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/artists/_common.py +144 -11
  7. tesorotools_python-0.0.50/src/tesorotools/artists/barh_plot.py +926 -0
  8. tesorotools_python-0.0.50/src/tesorotools/artists/compact.py +66 -0
  9. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/artists/line_plot.py +93 -70
  10. tesorotools_python-0.0.50/src/tesorotools/artists/shock_plot.py +333 -0
  11. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/artists/stacked.py +48 -44
  12. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/artists/type_curve.py +69 -19
  13. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/artists/waterfall.py +6 -2
  14. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/plots.yaml +18 -1
  15. tesorotools_python-0.0.50/src/tesorotools/assets/template.docx +0 -0
  16. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/__init__.py +2 -0
  17. tesorotools_python-0.0.50/src/tesorotools/render/document.py +32 -0
  18. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/report.py +7 -1
  19. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/utils/globals.py +5 -0
  20. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/utils/matplotlib.py +8 -1
  21. tesorotools_python-0.0.48/.gitignore +0 -29
  22. tesorotools_python-0.0.48/src/tesorotools/artists/barh_plot.py +0 -579
  23. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/_build_context.py +0 -0
  24. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/_registry.py +0 -0
  25. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/artists/matrix.py +0 -0
  26. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/artists/vector_plot.py +0 -0
  27. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/README.md +0 -0
  28. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/fonts/CabinetGrotesk-Black.otf +0 -0
  29. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/fonts/CabinetGrotesk-Bold.otf +0 -0
  30. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/fonts/CabinetGrotesk-Extrabold.otf +0 -0
  31. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/fonts/CabinetGrotesk-Extralight.otf +0 -0
  32. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/fonts/CabinetGrotesk-Light.otf +0 -0
  33. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/fonts/CabinetGrotesk-Medium.otf +0 -0
  34. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/fonts/CabinetGrotesk-Regular.otf +0 -0
  35. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/fonts/CabinetGrotesk-Thin.otf +0 -0
  36. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/fonts/README.md +0 -0
  37. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/assets/tesoro.mplstyle +0 -0
  38. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/data_sources/__init__.py +0 -0
  39. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/data_sources/debug.py +0 -0
  40. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/database/__init__.py +0 -0
  41. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/database/local.py +0 -0
  42. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/database/push.py +0 -0
  43. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/database/shared.py +0 -0
  44. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/dependencies/__init__.py +0 -0
  45. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/dependencies/node.py +0 -0
  46. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/dependencies/resolution.py +0 -0
  47. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/driver.py +0 -0
  48. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/manifest.py +0 -0
  49. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/offsets/__init__.py +0 -0
  50. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/offsets/offsets.py +0 -0
  51. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/offsets/outliers.py +0 -0
  52. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/orchestration.py +0 -0
  53. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/pipeline/__init__.py +0 -0
  54. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/pipeline/diagnose.py +0 -0
  55. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/pipeline/engine.py +0 -0
  56. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/pipeline/rules.py +0 -0
  57. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/providers/__init__.py +0 -0
  58. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/providers/base.py +0 -0
  59. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/providers/bde.py +0 -0
  60. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/providers/ecb.py +0 -0
  61. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/providers/imf_irfcl.py +0 -0
  62. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/providers/lseg.py +0 -0
  63. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/py.typed +0 -0
  64. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/content/__init__.py +0 -0
  65. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/content/content.py +0 -0
  66. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/content/images.py +0 -0
  67. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/content/section.py +0 -0
  68. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/content/subtitle.py +0 -0
  69. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/content/table.py +0 -0
  70. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/content/text.py +0 -0
  71. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/render/content/title.py +0 -0
  72. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/testing/__init__.py +0 -0
  73. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/testing/compare.py +0 -0
  74. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/utils/__init__.py +0 -0
  75. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/utils/config.py +0 -0
  76. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/utils/format.py +0 -0
  77. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/utils/series.py +0 -0
  78. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/utils/shortcuts.py +0 -0
  79. {tesorotools_python-0.0.48 → tesorotools_python-0.0.50}/src/tesorotools/utils/template.py +0 -0
@@ -0,0 +1,35 @@
1
+ .venv/
2
+ .build1/
3
+
4
+ __pycache__
5
+
6
+ .vscode/
7
+
8
+ data/
9
+ config/
10
+ debug/
11
+ tablas/
12
+
13
+ dist/
14
+
15
+ *.png
16
+ *.feather
17
+ *.csv
18
+ *.docx
19
+ *.docx#
20
+ # ...but the bundled base template must ship in the package/wheel.
21
+ !src/tesorotools/assets/template.docx
22
+
23
+ test/
24
+
25
+ # coverage
26
+ .coverage
27
+
28
+ # ruff
29
+ .ruff_cache/
30
+
31
+ # uv cache (CI restores it into the repo root)
32
+ .uv-cache/
33
+
34
+ demo_compacto/
35
+ demo/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tesorotools-python
3
- Version: 0.0.48
3
+ Version: 0.0.50
4
4
  Requires-Python: >=3.13
5
5
  Requires-Dist: babel>=2.17
6
6
  Requires-Dist: matplotlib>=3.10
@@ -48,11 +48,17 @@ source = "vcs"
48
48
 
49
49
  [tool.hatch.build.targets.wheel]
50
50
  packages = ["src/tesorotools"]
51
- artifacts = ["src/tesorotools/assets/fonts/*.otf"]
51
+ artifacts = [
52
+ "src/tesorotools/assets/fonts/*.otf",
53
+ "src/tesorotools/assets/template.docx",
54
+ ]
52
55
 
53
56
  [tool.hatch.build.targets.sdist]
54
57
  include = ["src/tesorotools"]
55
- artifacts = ["src/tesorotools/assets/fonts/*.otf"]
58
+ artifacts = [
59
+ "src/tesorotools/assets/fonts/*.otf",
60
+ "src/tesorotools/assets/template.docx",
61
+ ]
56
62
 
57
63
  [tool.coverage.run]
58
64
  source = ["tesorotools"]
@@ -17,8 +17,17 @@ plural variants). See ``docs/extending.md`` for the
17
17
  recommended idioms.
18
18
  """
19
19
 
20
+ from importlib.metadata import PackageNotFoundError, version
20
21
  from typing import TYPE_CHECKING, Any
21
22
 
23
+ try:
24
+ #: Installed distribution version (set by hatch-vcs from the git tag).
25
+ #: Falls back to ``"0.0.0"`` when the package is not installed (e.g.
26
+ #: running straight from a source checkout with no metadata).
27
+ __version__ = version("tesorotools-python")
28
+ except PackageNotFoundError: # pragma: no cover - source-only checkout
29
+ __version__ = "0.0.0"
30
+
22
31
  if TYPE_CHECKING:
23
32
  from tesorotools.providers.bde import BdeProvider
24
33
  from tesorotools.providers.ecb import EcbProvider
@@ -50,6 +59,7 @@ from tesorotools.artists import (
50
59
  Legend,
51
60
  LinePlot,
52
61
  MatrixChart,
62
+ ShockChart,
53
63
  StackedAreaPlot,
54
64
  StackedBarPlot,
55
65
  TypeCurve,
@@ -72,6 +82,7 @@ from tesorotools.render import (
72
82
  Table,
73
83
  Text,
74
84
  Title,
85
+ new_document,
75
86
  )
76
87
 
77
88
 
@@ -84,6 +95,7 @@ def _register_builtins() -> None:
84
95
  register_artist("type_curve", TypeCurve)
85
96
  register_artist("vector_plot", VectorPlot)
86
97
  register_artist("matrix", MatrixChart)
98
+ register_artist("shock_plot", ShockChart)
87
99
  register_artist("waterfall", Waterfall)
88
100
 
89
101
  register_tag("format", Format)
@@ -102,6 +114,7 @@ _register_builtins()
102
114
 
103
115
 
104
116
  __all__ = [
117
+ "__version__",
105
118
  "Artist",
106
119
  "BdeProvider",
107
120
  "BuildContext",
@@ -121,6 +134,7 @@ __all__ = [
121
134
  "RegistryProtocol",
122
135
  "Report",
123
136
  "Section",
137
+ "ShockChart",
124
138
  "StackedAreaPlot",
125
139
  "StackedBarPlot",
126
140
  "Subtitle",
@@ -141,6 +155,7 @@ __all__ = [
141
155
  "iter_contexts",
142
156
  "iter_providers",
143
157
  "iter_tags",
158
+ "new_document",
144
159
  "register_artist",
145
160
  "register_artists",
146
161
  "register_provider",
@@ -29,6 +29,7 @@ from tesorotools.artists._common import Artist, Format, Legend
29
29
  from tesorotools.artists.barh_plot import GroupedBarChart, HorizontalBarChart
30
30
  from tesorotools.artists.line_plot import LinePlot
31
31
  from tesorotools.artists.matrix import MatrixChart
32
+ from tesorotools.artists.shock_plot import ShockChart
32
33
  from tesorotools.artists.stacked import StackedAreaPlot, StackedBarPlot
33
34
  from tesorotools.artists.type_curve import TypeCurve
34
35
  from tesorotools.artists.vector_plot import VectorPlot
@@ -42,6 +43,7 @@ __all__ = [
42
43
  "Legend",
43
44
  "LinePlot",
44
45
  "MatrixChart",
46
+ "ShockChart",
45
47
  "StackedAreaPlot",
46
48
  "StackedBarPlot",
47
49
  "TypeCurve",
@@ -156,12 +156,20 @@ class Format:
156
156
 
157
157
  Used by every artist as ``fmt`` and by tick formatters /
158
158
  annotations. ``decimals`` is forwarded to ``round`` and
159
- ``units`` is appended to the formatted number.
159
+ ``units`` is appended to the formatted number. ``signed``
160
+ prefixes a ``+`` to positive numbers (negatives already
161
+ carry ``-``); useful for a variation/change annotation so
162
+ its direction reads at a glance. It is opt-in and ignored
163
+ by axis-tick formatting (a row of ``+`` on the axis is
164
+ noise) -- set it on the ``annot_fmt`` that labels the bars.
160
165
  """
161
166
 
162
- def __init__(self, units: str = "", decimals: int = 0) -> None:
167
+ def __init__(
168
+ self, units: str = "", decimals: int = 0, signed: bool = False
169
+ ) -> None:
163
170
  self.units = units
164
171
  self.decimals = decimals
172
+ self.signed = signed
165
173
 
166
174
  @classmethod
167
175
  def from_yaml(cls, loader: TemplateLoader, node: MappingNode) -> Self:
@@ -381,7 +389,7 @@ def compact_figsize() -> tuple[float, float]:
381
389
  return (width_cm * CM_TO_IN, height_cm * CM_TO_IN)
382
390
 
383
391
 
384
- def compact_font_pt() -> float | None:
392
+ def compact_font_pt(override: float | None = None) -> float | None:
385
393
  """Font size (points) for compact charts, or ``None`` to keep the style.
386
394
 
387
395
  Because the compact figure is rendered at its true
@@ -389,7 +397,17 @@ def compact_font_pt() -> float | None:
389
397
  these points equal the points the reader sees in Word --
390
398
  set ``compact.font_pt`` in ``plots.yaml`` to the document
391
399
  body-text size so chart text matches running text.
400
+
401
+ ``override`` lets a single chart pick its own size, taking
402
+ precedence over the config: a chart that sits inside a Word
403
+ table wants the **table** content size (often smaller than
404
+ body text), and a denser chart -- many long-named bars -- may
405
+ need a smaller size so the value labels and category names
406
+ stop colliding. ``None`` (the default) falls back to
407
+ ``compact.font_pt``.
392
408
  """
409
+ if override is not None:
410
+ return float(override)
393
411
  raw: Any = COMPACT_CONFIG.get("font_pt")
394
412
  return None if raw is None else float(raw)
395
413
 
@@ -620,17 +638,132 @@ def legend_above(
620
638
  )
621
639
 
622
640
 
623
- def declutter_spines(ax: Axes) -> None:
624
- """Hide the spines that carry no ticks (top and right).
641
+ # ----------------------------------------------------------------------
642
+ # Shared compact toolkit
643
+ # ----------------------------------------------------------------------
644
+ #
645
+ # The three helpers below pack the policy ``LinePlot`` / ``Waterfall``
646
+ # had inline so *every* image artist can opt into compact uniformly --
647
+ # fixed physical size, body-size ticks, the spine side and the
648
+ # above-the-axes legend -- instead of copy-pasting from this module's
649
+ # internals. They are re-exported publicly from
650
+ # :mod:`tesorotools.artists.compact`.
651
+
652
+
653
+ def compact_figure_kwargs(
654
+ compact: bool, figsize: tuple[float, float] | None = None
655
+ ) -> dict[str, Any]:
656
+ """``FIG_CONFIG`` with the compact figure size wired in.
657
+
658
+ An explicit ``figsize`` always wins; otherwise a compact chart with no
659
+ ``figsize`` gets :func:`compact_figsize` (the fixed 7.4 cm x 5.5 cm box
660
+ read from ``plots.yaml``). Mirrors the ``fig_kw`` block every artist
661
+ opened by hand.
662
+ """
663
+ fig_kw = dict(FIG_CONFIG)
664
+ if figsize is not None:
665
+ fig_kw["figsize"] = figsize
666
+ elif compact:
667
+ fig_kw["figsize"] = compact_figsize()
668
+ return fig_kw
669
+
670
+
671
+ def compact_barh_figsize(n_bars: int) -> tuple[float, float]:
672
+ """Compact figure size for a horizontal-bar chart: width fixed, height grows.
673
+
674
+ The fixed compact height crushes the y-labels of a many-category barh,
675
+ so compact bar charts keep the compact **width** but scale **height**
676
+ with the bar count: ``margin + per_bar * n_bars`` centimetres
677
+ (``compact.barh_margin_cm`` / ``compact.barh_per_bar_cm``), floored at
678
+ the compact height so a one- or two-bar chart is not absurdly short.
679
+ """
680
+ width_in, height_in = compact_figsize()
681
+ per_bar_cm: float = float(COMPACT_CONFIG.get("barh_per_bar_cm", 0.55))
682
+ margin_cm: float = float(COMPACT_CONFIG.get("barh_margin_cm", 1.6))
683
+ h_cm = margin_cm + per_bar_cm * max(1, n_bars)
684
+ return (width_in, max(height_in, h_cm * CM_TO_IN))
685
+
686
+
687
+ def style_compact_axes(
688
+ ax: Axes, font_pt: float | None, *, side: str = "right"
689
+ ) -> None:
690
+ """Body-size ticks plus the compact spine policy for *ax*.
691
+
692
+ The stylesheet pins ``xtick.labelsize`` / ``ytick.labelsize`` to 12, so
693
+ setting ``font.size`` alone does **not** resize the ticks -- this calls
694
+ ``tick_params(labelsize=font_pt)`` explicitly (when ``font_pt`` is set).
695
+ It then puts the y-ticks on ``side`` (``"right"`` -- the house side, the
696
+ default -- or ``"left"``, which frees the right edge for end-of-series
697
+ value labels) and drops the now-tickless top and opposite spines via
698
+ :func:`declutter_spines`.
699
+ """
700
+ if font_pt is not None:
701
+ ax.tick_params( # type: ignore[reportUnknownMemberType]
702
+ axis="both", labelsize=font_pt
703
+ )
704
+ if side == "right":
705
+ ax.yaxis.tick_right()
706
+ else:
707
+ ax.yaxis.tick_left()
708
+ declutter_spines(ax, side=side)
709
+
710
+
711
+ def place_legend(
712
+ fig: Figure,
713
+ ax: Axes,
714
+ *,
715
+ compact: bool,
716
+ ncol: int | None = None,
717
+ ) -> MplLegend | None:
718
+ """Place the figure legend, compact-aware, from the labelled artists.
719
+
720
+ Compact charts get the band **above** the axes spanning the figure
721
+ width (:func:`legend_above`) with the compact legend metrics; ``ncol``
722
+ is auto-fitted to the full figure width and hard-capped by
723
+ :func:`compact_legend_max_ncol` unless the caller passes an explicit
724
+ ``ncol``. Non-compact charts get the house ``outside lower center``
725
+ band. Returns ``None`` (drawing nothing) when there are no labels.
726
+ """
727
+ handles, labels = ax.get_legend_handles_labels()
728
+ if not labels:
729
+ return None
730
+ fig_w_px: float = fig.get_size_inches()[0] * fig.dpi
731
+ if compact:
732
+ legend_kw = compact_legend_kwargs()
733
+ if ncol is None:
734
+ ncol = auto_ncol(
735
+ ax, labels, available_width_px=fig_w_px, **legend_kw
736
+ )
737
+ max_ncol = compact_legend_max_ncol()
738
+ if max_ncol is not None:
739
+ ncol = min(ncol, max_ncol)
740
+ return legend_above(ax, handles, labels, ncol=ncol, **legend_kw)
741
+ if ncol is None:
742
+ ncol = auto_ncol(ax, labels, available_width_px=fig_w_px)
743
+ return fig.legend( # type: ignore[reportUnknownMemberType]
744
+ handles,
745
+ labels,
746
+ loc="outside lower center",
747
+ ncol=ncol,
748
+ )
749
+
750
+
751
+ def declutter_spines(ax: Axes, side: str = "left") -> None:
752
+ """Hide the spines that carry no ticks (top, plus the untickled side).
753
+
754
+ Compact charts keep x-ticks on the bottom and the y-ticks on a single
755
+ side, leaving the top spine and the *opposite* vertical spine as pure
756
+ clutter -- drop them to free space and reduce visual noise.
625
757
 
626
- Compact line charts move the y-ticks to the **left** (so
627
- the right edge is free for the end-of-series value labels)
628
- and keep x-ticks on the bottom, leaving the top and right
629
- spines as pure clutter -- drop them to free space and
630
- reduce visual noise.
758
+ ``side`` is the side the y-ticks live on: ``"left"`` (the historic
759
+ default, used by the annotating line chart and the bar/waterfall
760
+ charts) drops top+right; ``"right"`` (the house side every non-compact
761
+ chart keeps) drops top+left. The side became a choice with the compact
762
+ y-axis-side knob, so the dropped spine has to follow it -- otherwise a
763
+ right-ticked compact chart would lose the spine its ticks sit on.
631
764
  """
632
765
  ax.spines["top"].set_visible(False)
633
- ax.spines["right"].set_visible(False)
766
+ ax.spines["right" if side == "left" else "left"].set_visible(False)
634
767
 
635
768
 
636
769
  # ----------------------------------------------------------------------