tesorotools-python 0.1.3__tar.gz → 0.1.4__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.
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/PKG-INFO +1 -1
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/pyproject.toml +1 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/__init__.py +6 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/__init__.py +4 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/_common.py +55 -1
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/bar_line.py +2 -1
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/box_plot.py +2 -1
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/intraday_plot.py +2 -1
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/line_plot.py +4 -1
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/plotly_backend.py +142 -1
- tesorotools_python-0.1.4/src/tesorotools/artists/sankey.py +436 -0
- tesorotools_python-0.1.4/src/tesorotools/artists/scatter.py +469 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/shock_plot.py +2 -1
- tesorotools_python-0.1.4/src/tesorotools/artists/tikz_backend.py +172 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/waterfall.py +2 -1
- tesorotools_python-0.1.4/src/tesorotools/assets/nota_template.dotx +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/plots.yaml +40 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/style/tesoro.sty +3 -0
- tesorotools_python-0.1.4/src/tesorotools/note/__init__.py +40 -0
- tesorotools_python-0.1.4/src/tesorotools/note/builder.py +749 -0
- tesorotools_python-0.1.4/src/tesorotools/note/cli.py +168 -0
- tesorotools_python-0.1.4/src/tesorotools/note/inline.py +129 -0
- tesorotools_python-0.1.4/src/tesorotools/note/lint.py +291 -0
- tesorotools_python-0.1.4/src/tesorotools/note/markdown.py +613 -0
- tesorotools_python-0.1.4/src/tesorotools/note/skeleton.md +75 -0
- tesorotools_python-0.1.4/src/tesorotools/note/skill/SKILL.md +171 -0
- tesorotools_python-0.1.4/src/tesorotools/note/skill/reglas.md +120 -0
- tesorotools_python-0.1.4/src/tesorotools/note/template.py +120 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/utils/globals.py +4 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/app.py +11 -2
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/brand.py +10 -1
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/components.py +32 -12
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/theme.py +29 -6
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/.gitignore +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/_build_context.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/_registry.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/barh_plot.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/compact.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/matrix.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/sharing.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/stacked.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/type_curve.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/vector_plot.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/README.md +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/fonts/CabinetGrotesk-Black.otf +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/fonts/CabinetGrotesk-Bold.otf +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/fonts/CabinetGrotesk-Extrabold.otf +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/fonts/CabinetGrotesk-Extralight.otf +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/fonts/CabinetGrotesk-Light.otf +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/fonts/CabinetGrotesk-Medium.otf +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/fonts/CabinetGrotesk-Regular.otf +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/fonts/CabinetGrotesk-Thin.otf +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/fonts/README.md +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/template.docx +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/assets/tesoro.mplstyle +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/data_sources/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/data_sources/debug.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/database/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/database/local.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/database/push.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/database/shared.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/dependencies/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/dependencies/node.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/dependencies/resolution.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/driver.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/cli.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/scaffold.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/article/main.tex.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/article/sections/01-introduccion.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/article/sections/02-analisis.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/article/sections/03-conclusiones.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/beamer/main.tex.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/beamer/slides/01-contexto.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/beamer/slides/02-analisis.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/beamer/slides/03-conclusiones.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/beamer/style/beamerthemeTesoro.sty +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/book/appendices/a-fuentes.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/book/chapters/01-introduccion.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/book/chapters/02-analisis.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/book/frontmatter/resumen.tex +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/book/main.tex.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/README.md.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/dot-gitignore +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/dot-vscode/settings.json +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/figures/dot-gitkeep +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/fonts/README.md +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/latexmkrc +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/refs.bib +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/style/tesorobrand.sty.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/latex/templates/common/style/tesorolocal.sty.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/manifest.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/offsets/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/offsets/offsets.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/offsets/outliers.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/orchestration.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/palette.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/pipeline/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/pipeline/diagnose.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/pipeline/engine.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/pipeline/rules.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/providers/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/providers/base.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/providers/bde.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/providers/ecb.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/providers/fred.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/providers/imf_irfcl.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/providers/lseg.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/py.typed +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/content/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/content/content.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/content/images.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/content/section.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/content/subtitle.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/content/table.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/content/text.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/content/title.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/document.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/render/report.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/scaffold.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/testing/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/testing/compare.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/utils/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/utils/config.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/utils/format.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/utils/matplotlib.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/utils/series.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/utils/shortcuts.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/utils/template.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/__init__.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/cli.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/formatting.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/launcher.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/palette.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/plotting.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/scaffold.py +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/Dockerfile.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/README.md.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/dot-dockerignore.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/dot-gitignore.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/dot-streamlit/config.toml.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/pyproject.toml.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/src/$package/__init__.py.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/src/$package/cli.py.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/src/$package/main.py.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/src/$package/sections.py.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/tests/__init__.py.tmpl +0 -0
- {tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/web/templates/tests/test_app.py.tmpl +0 -0
|
@@ -66,6 +66,8 @@ from tesorotools.artists import (
|
|
|
66
66
|
Legend,
|
|
67
67
|
LinePlot,
|
|
68
68
|
MatrixChart,
|
|
69
|
+
SankeyPlot,
|
|
70
|
+
ScatterPlot,
|
|
69
71
|
ShockChart,
|
|
70
72
|
StackedAreaPlot,
|
|
71
73
|
StackedBarPlot,
|
|
@@ -108,6 +110,8 @@ def _register_builtins() -> None:
|
|
|
108
110
|
register_artist("shock_plot", ShockChart)
|
|
109
111
|
register_artist("intraday", IntradayPlot)
|
|
110
112
|
register_artist("waterfall", Waterfall)
|
|
113
|
+
register_artist("sankey", SankeyPlot)
|
|
114
|
+
register_artist("scatter", ScatterPlot)
|
|
111
115
|
|
|
112
116
|
register_tag("format", Format)
|
|
113
117
|
register_tag("legend", Legend)
|
|
@@ -149,6 +153,8 @@ __all__ = [
|
|
|
149
153
|
"MatrixChart",
|
|
150
154
|
"RegistryProtocol",
|
|
151
155
|
"Report",
|
|
156
|
+
"SankeyPlot",
|
|
157
|
+
"ScatterPlot",
|
|
152
158
|
"Section",
|
|
153
159
|
"ShockChart",
|
|
154
160
|
"StackedAreaPlot",
|
|
@@ -45,6 +45,8 @@ from tesorotools.artists.box_plot import BoxPlot
|
|
|
45
45
|
from tesorotools.artists.intraday_plot import IntradayPlot
|
|
46
46
|
from tesorotools.artists.line_plot import LinePlot
|
|
47
47
|
from tesorotools.artists.matrix import MatrixChart
|
|
48
|
+
from tesorotools.artists.sankey import SankeyPlot
|
|
49
|
+
from tesorotools.artists.scatter import ScatterPlot
|
|
48
50
|
from tesorotools.artists.sharing import share_y_axes
|
|
49
51
|
from tesorotools.artists.shock_plot import ShockChart
|
|
50
52
|
from tesorotools.artists.stacked import StackedAreaPlot, StackedBarPlot
|
|
@@ -64,6 +66,8 @@ __all__ = [
|
|
|
64
66
|
"Legend",
|
|
65
67
|
"LinePlot",
|
|
66
68
|
"MatrixChart",
|
|
69
|
+
"SankeyPlot",
|
|
70
|
+
"ScatterPlot",
|
|
67
71
|
"ShockChart",
|
|
68
72
|
"StackedAreaPlot",
|
|
69
73
|
"StackedBarPlot",
|
|
@@ -23,11 +23,13 @@ overrides only need to update ``plots.yaml``.
|
|
|
23
23
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
|
+
import math
|
|
26
27
|
from collections.abc import Sequence
|
|
27
28
|
from pathlib import Path
|
|
28
29
|
from typing import Any, Literal, Protocol, Self, cast, runtime_checkable
|
|
29
30
|
|
|
30
31
|
import matplotlib.pyplot as plt
|
|
32
|
+
import numpy as np
|
|
31
33
|
import pandas as pd
|
|
32
34
|
from matplotlib.axes import Axes
|
|
33
35
|
from matplotlib.dates import (
|
|
@@ -152,7 +154,7 @@ def plotly_unsupported(artist: object) -> frozenset[str]:
|
|
|
152
154
|
|
|
153
155
|
|
|
154
156
|
class FigureLifecycle:
|
|
155
|
-
"""``save()`` and ``
|
|
157
|
+
"""``save()``, ``plot()`` and ``to_tikz()`` on top of ``build()``.
|
|
156
158
|
|
|
157
159
|
Gives an artist the same three-step life cycle as the rest:
|
|
158
160
|
``build()`` returns the figure in memory, ``save()`` writes it
|
|
@@ -194,6 +196,17 @@ class FigureLifecycle:
|
|
|
194
196
|
plt.close(fig)
|
|
195
197
|
return ax
|
|
196
198
|
|
|
199
|
+
def to_tikz(self, path: Path | None = None) -> Path:
|
|
200
|
+
"""Write the chart as PGF code for LaTeX and return the path.
|
|
201
|
+
|
|
202
|
+
By default next to the PNG, with a ``.pgf`` suffix; the document
|
|
203
|
+
includes it with ``\\input``. Needs a TeX installation (see
|
|
204
|
+
:mod:`tesorotools.artists.tikz_backend`).
|
|
205
|
+
"""
|
|
206
|
+
from tesorotools.artists.tikz_backend import render_tikz
|
|
207
|
+
|
|
208
|
+
return render_tikz(self, path)
|
|
209
|
+
|
|
197
210
|
|
|
198
211
|
# ----------------------------------------------------------------------
|
|
199
212
|
# Structural contract for image artists
|
|
@@ -980,6 +993,40 @@ def apply_date_axis(
|
|
|
980
993
|
label.set_rotation_mode("anchor")
|
|
981
994
|
|
|
982
995
|
|
|
996
|
+
class DecimalsLocator(MaxNLocator):
|
|
997
|
+
"""Matplotlib's default y ticks, kept printable at *decimals*.
|
|
998
|
+
|
|
999
|
+
The default locator steps by 1, 2, 2.5 or 5 of a decade, so with a
|
|
1000
|
+
tick format of two decimals it can put ticks every 0.005, and two
|
|
1001
|
+
neighbours print alike (``1,17`` twice). When the step is not a
|
|
1002
|
+
whole multiple of ``10 ** -decimals`` (the unit) the next of 1, 2 or
|
|
1003
|
+
5 units takes its place: fewer ticks, all different. Otherwise the
|
|
1004
|
+
ticks are exactly the default ones.
|
|
1005
|
+
"""
|
|
1006
|
+
|
|
1007
|
+
def __init__(self, decimals: int, nbins: int | Literal["auto"] = "auto"):
|
|
1008
|
+
super().__init__( # type: ignore[reportUnknownMemberType]
|
|
1009
|
+
nbins=nbins, steps=[1, 2, 2.5, 5, 10]
|
|
1010
|
+
)
|
|
1011
|
+
self.decimals = decimals
|
|
1012
|
+
|
|
1013
|
+
def tick_values(self, vmin: float, vmax: float) -> Any:
|
|
1014
|
+
ticks = super().tick_values(vmin, vmax)
|
|
1015
|
+
if len(ticks) < 2:
|
|
1016
|
+
return ticks
|
|
1017
|
+
unit = 10.0**-self.decimals
|
|
1018
|
+
step = float(ticks[1] - ticks[0])
|
|
1019
|
+
ratio = step / unit
|
|
1020
|
+
if round(ratio) >= 1 and math.isclose(ratio, round(ratio)):
|
|
1021
|
+
return ticks
|
|
1022
|
+
# The default steps are 1, 2, 2.5 or 5 times a power of ten, so a
|
|
1023
|
+
# step that is no whole multiple of the unit is below 5 units.
|
|
1024
|
+
new = next(f * unit for f in (1, 2, 5) if f * unit >= step)
|
|
1025
|
+
low = math.floor(min(vmin, vmax) / new) * new
|
|
1026
|
+
high = math.ceil(max(vmin, vmax) / new) * new
|
|
1027
|
+
return np.arange(low, high + new / 2, new)
|
|
1028
|
+
|
|
1029
|
+
|
|
983
1030
|
def compact_y_axis(ax: Axes) -> None:
|
|
984
1031
|
"""Denser y-ticks for compact charts (more reference numbers).
|
|
985
1032
|
|
|
@@ -994,6 +1041,12 @@ def compact_y_axis(ax: Axes) -> None:
|
|
|
994
1041
|
raw: Any = COMPACT_CONFIG.get("y_max_ticks")
|
|
995
1042
|
if raw is None:
|
|
996
1043
|
return
|
|
1044
|
+
current = ax.yaxis.get_major_locator()
|
|
1045
|
+
if isinstance(current, DecimalsLocator):
|
|
1046
|
+
ax.yaxis.set_major_locator(
|
|
1047
|
+
DecimalsLocator(current.decimals, nbins=int(raw))
|
|
1048
|
+
)
|
|
1049
|
+
return
|
|
997
1050
|
ax.yaxis.set_major_locator(
|
|
998
1051
|
MaxNLocator(nbins=int(raw), steps=[1, 2, 2.5, 5, 10])
|
|
999
1052
|
)
|
|
@@ -1288,6 +1341,7 @@ def style_spines(
|
|
|
1288
1341
|
return format_annotation(y, decimals, units)
|
|
1289
1342
|
|
|
1290
1343
|
ax.yaxis.set_major_formatter(FuncFormatter(_fmt_tick))
|
|
1344
|
+
ax.yaxis.set_major_locator(DecimalsLocator(decimals))
|
|
1291
1345
|
ax.set_xlabel( # type: ignore[reportUnknownMemberType]
|
|
1292
1346
|
""
|
|
1293
1347
|
)
|
|
@@ -42,6 +42,7 @@ from matplotlib.figure import Figure
|
|
|
42
42
|
from yaml.nodes import MappingNode
|
|
43
43
|
|
|
44
44
|
from tesorotools.artists._common import (
|
|
45
|
+
FigureLifecycle,
|
|
45
46
|
AX_CONFIG,
|
|
46
47
|
Format,
|
|
47
48
|
Legend,
|
|
@@ -66,7 +67,7 @@ __all__ = ["BarLinePlot"]
|
|
|
66
67
|
BAR_LINE_CONFIG: dict[str, Any] = PLOT_CONFIG["bar_line"]
|
|
67
68
|
|
|
68
69
|
|
|
69
|
-
class BarLinePlot:
|
|
70
|
+
class BarLinePlot(FigureLifecycle):
|
|
70
71
|
"""Combo chart: vertical bars and marked lines, optionally on two axes.
|
|
71
72
|
|
|
72
73
|
Parameters mirror the other time-series artists where they overlap
|
|
@@ -44,6 +44,7 @@ from matplotlib.patches import Patch
|
|
|
44
44
|
from yaml.nodes import MappingNode
|
|
45
45
|
|
|
46
46
|
from tesorotools.artists._common import (
|
|
47
|
+
FigureLifecycle,
|
|
47
48
|
AX_CONFIG,
|
|
48
49
|
Format,
|
|
49
50
|
Legend,
|
|
@@ -105,7 +106,7 @@ def _weighted_quantile(
|
|
|
105
106
|
return float(np.interp(q, cum, v))
|
|
106
107
|
|
|
107
108
|
|
|
108
|
-
class BoxPlot:
|
|
109
|
+
class BoxPlot(FigureLifecycle):
|
|
109
110
|
"""Box-and-whisker chart, one box per category.
|
|
110
111
|
|
|
111
112
|
Parameters mirror the other artists where they overlap (``out_path``,
|
{tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/intraday_plot.py
RENAMED
|
@@ -42,6 +42,7 @@ from matplotlib.figure import Figure
|
|
|
42
42
|
from yaml.nodes import MappingNode
|
|
43
43
|
|
|
44
44
|
from tesorotools.artists._common import (
|
|
45
|
+
FigureLifecycle,
|
|
45
46
|
AX_CONFIG,
|
|
46
47
|
Format,
|
|
47
48
|
Legend,
|
|
@@ -66,7 +67,7 @@ __all__ = ["IntradayPlot"]
|
|
|
66
67
|
_MAX_XTICKS = 10
|
|
67
68
|
|
|
68
69
|
|
|
69
|
-
class IntradayPlot:
|
|
70
|
+
class IntradayPlot(FigureLifecycle):
|
|
70
71
|
"""Single-instrument intraday line chart on a gap-free ordinal axis.
|
|
71
72
|
|
|
72
73
|
Parameters mirror the other image artists where they overlap
|
|
@@ -23,6 +23,8 @@ from matplotlib.ticker import FuncFormatter
|
|
|
23
23
|
from yaml.nodes import MappingNode
|
|
24
24
|
|
|
25
25
|
from tesorotools.artists._common import (
|
|
26
|
+
DecimalsLocator,
|
|
27
|
+
FigureLifecycle,
|
|
26
28
|
AX_CONFIG,
|
|
27
29
|
DATE_DENSITY_LEVELS,
|
|
28
30
|
Format,
|
|
@@ -56,7 +58,7 @@ locale.setlocale(locale.LC_ALL, "")
|
|
|
56
58
|
__all__ = ["LinePlot"]
|
|
57
59
|
|
|
58
60
|
|
|
59
|
-
class LinePlot:
|
|
61
|
+
class LinePlot(FigureLifecycle):
|
|
60
62
|
"""Time-series line chart with the tesorotools visual style.
|
|
61
63
|
|
|
62
64
|
Parameters mirror the other image artists where they
|
|
@@ -542,6 +544,7 @@ class LinePlot:
|
|
|
542
544
|
return format_annotation(y, axis_decimals, units)
|
|
543
545
|
|
|
544
546
|
ax.yaxis.set_major_formatter(FuncFormatter(_fmt_axis_tick))
|
|
547
|
+
ax.yaxis.set_major_locator(DecimalsLocator(axis_decimals))
|
|
545
548
|
if self.baseline:
|
|
546
549
|
reference = 100 if self.base_100 else 0
|
|
547
550
|
style_baseline(ax, reference, **AX_CONFIG["baseline"])
|
{tesorotools_python-0.1.3 → tesorotools_python-0.1.4}/src/tesorotools/artists/plotly_backend.py
RENAMED
|
@@ -20,7 +20,7 @@ never depends on plotly.
|
|
|
20
20
|
|
|
21
21
|
Coverage: every image artist except ``IntradayPlot`` -- line, type
|
|
22
22
|
curve, stacked area, stacked bar, bar+line, box, shock, waterfall,
|
|
23
|
-
horizontal bar, grouped bar, matrix and
|
|
23
|
+
horizontal bar, grouped bar, matrix, vector, sankey and scatter.
|
|
24
24
|
|
|
25
25
|
Known mimicry caveats (the styling that does NOT transfer for free between
|
|
26
26
|
backends, per the dual-backend research):
|
|
@@ -64,6 +64,8 @@ if TYPE_CHECKING:
|
|
|
64
64
|
)
|
|
65
65
|
from tesorotools.artists.line_plot import LinePlot
|
|
66
66
|
from tesorotools.artists.matrix import MatrixChart
|
|
67
|
+
from tesorotools.artists.sankey import SankeyPlot
|
|
68
|
+
from tesorotools.artists.scatter import ScatterPlot
|
|
67
69
|
from tesorotools.artists.shock_plot import ShockChart
|
|
68
70
|
from tesorotools.artists.stacked import StackedAreaPlot, StackedBarPlot
|
|
69
71
|
from tesorotools.artists.type_curve import TypeCurve
|
|
@@ -78,6 +80,8 @@ __all__ = [
|
|
|
78
80
|
"house_template",
|
|
79
81
|
"line_plot_to_figure",
|
|
80
82
|
"matrix_to_figure",
|
|
83
|
+
"sankey_to_figure",
|
|
84
|
+
"scatter_to_figure",
|
|
81
85
|
"shock_chart_to_figure",
|
|
82
86
|
"stacked_area_to_figure",
|
|
83
87
|
"stacked_bar_to_figure",
|
|
@@ -1092,3 +1096,140 @@ def vector_plot_to_figure(chart: VectorPlot) -> go.Figure:
|
|
|
1092
1096
|
ticksuffix=chart.y_fmt.units or "",
|
|
1093
1097
|
)
|
|
1094
1098
|
return fig
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
def sankey_to_figure(chart: SankeyPlot) -> go.Figure:
|
|
1102
|
+
"""Interactive ``Figure`` from a :class:`SankeyPlot` (``go.Sankey``).
|
|
1103
|
+
|
|
1104
|
+
Consumes the same layout as ``SankeyPlot.build``: one Plotly node per
|
|
1105
|
+
(stage, node) pair, pinned at its column and at the vertical centre
|
|
1106
|
+
the static chart gives it (``arrangement="fixed"``), and one link per
|
|
1107
|
+
flow coloured like its source node with ``sankey.flow_alpha``. Node
|
|
1108
|
+
labels carry the node value, as the end columns of the PNG do.
|
|
1109
|
+
"""
|
|
1110
|
+
from tesorotools.artists.sankey import SANKEY_CONFIG
|
|
1111
|
+
|
|
1112
|
+
lay = chart._layout()
|
|
1113
|
+
n_col = len(lay.columns)
|
|
1114
|
+
alpha = float(SANKEY_CONFIG.get("flow_alpha", 0.45))
|
|
1115
|
+
index: dict[tuple[int, str], int] = {}
|
|
1116
|
+
labels: list[str] = []
|
|
1117
|
+
colors: list[str] = []
|
|
1118
|
+
xs: list[float] = []
|
|
1119
|
+
ys: list[float] = []
|
|
1120
|
+
for (c, n), top in lay.tops.items():
|
|
1121
|
+
index[(c, n)] = len(labels)
|
|
1122
|
+
height = lay.heights[(c, n)]
|
|
1123
|
+
labels.append(f"{chart.label(n)} {chart.value_text(height)}")
|
|
1124
|
+
colors.append(_color(chart.color(n)))
|
|
1125
|
+
# Plotly pins nodes strictly inside (0, 1); y grows downwards.
|
|
1126
|
+
xs.append(min(max(c / (n_col - 1), 0.001), 0.999))
|
|
1127
|
+
centre = 1 - (top - height / 2) / lay.total_height
|
|
1128
|
+
ys.append(min(max(centre, 0.001), 0.999))
|
|
1129
|
+
fig = _new_figure()
|
|
1130
|
+
fig.add_trace(
|
|
1131
|
+
go.Sankey(
|
|
1132
|
+
arrangement="fixed",
|
|
1133
|
+
valueformat=f".{chart.fmt.decimals}f",
|
|
1134
|
+
valuesuffix=chart.fmt.units or "",
|
|
1135
|
+
node={
|
|
1136
|
+
"label": labels,
|
|
1137
|
+
"color": colors,
|
|
1138
|
+
"x": xs,
|
|
1139
|
+
"y": ys,
|
|
1140
|
+
"pad": 10,
|
|
1141
|
+
"thickness": 12,
|
|
1142
|
+
"line": {"width": 0},
|
|
1143
|
+
},
|
|
1144
|
+
link={
|
|
1145
|
+
"source": [index[(f.column, f.source)] for f in lay.flows],
|
|
1146
|
+
"target": [index[(f.column + 1, f.target)] for f in lay.flows],
|
|
1147
|
+
"value": [f.value for f in lay.flows],
|
|
1148
|
+
"color": [
|
|
1149
|
+
_color(chart.color(f.source), alpha) for f in lay.flows
|
|
1150
|
+
],
|
|
1151
|
+
},
|
|
1152
|
+
)
|
|
1153
|
+
)
|
|
1154
|
+
for c, text in enumerate(lay.stage_labels):
|
|
1155
|
+
fig.add_annotation(
|
|
1156
|
+
x=c / (n_col - 1),
|
|
1157
|
+
y=1.06,
|
|
1158
|
+
xref="paper",
|
|
1159
|
+
yref="paper",
|
|
1160
|
+
text=f"<b>{text}</b>",
|
|
1161
|
+
showarrow=False,
|
|
1162
|
+
)
|
|
1163
|
+
return fig
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
#: ``ScatterPlot`` label side -> Plotly ``textposition``.
|
|
1167
|
+
_TEXT_POSITION = {
|
|
1168
|
+
"above right": "top right",
|
|
1169
|
+
"below right": "bottom right",
|
|
1170
|
+
"above left": "top left",
|
|
1171
|
+
"below left": "bottom left",
|
|
1172
|
+
"right": "middle right",
|
|
1173
|
+
"left": "middle left",
|
|
1174
|
+
"above": "top center",
|
|
1175
|
+
"below": "bottom center",
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
|
|
1179
|
+
def scatter_to_figure(chart: ScatterPlot) -> go.Figure:
|
|
1180
|
+
"""Interactive ``Figure`` from a :class:`ScatterPlot`.
|
|
1181
|
+
|
|
1182
|
+
One ``go.Scatter`` trace per group (so the legend lists the groups),
|
|
1183
|
+
each point labelled on the side the PNG chose
|
|
1184
|
+
(:meth:`ScatterPlot.placements`), with the same colours and limits.
|
|
1185
|
+
"""
|
|
1186
|
+
from tesorotools.artists.scatter import SCATTER_CONFIG
|
|
1187
|
+
|
|
1188
|
+
rows = chart._rows()
|
|
1189
|
+
order = chart.group_order(rows)
|
|
1190
|
+
sides = chart.placements() if chart.labels else {}
|
|
1191
|
+
fig = _new_figure()
|
|
1192
|
+
for group in order:
|
|
1193
|
+
points = rows[rows["group"] == group]
|
|
1194
|
+
color = _color(chart.color(group, order))
|
|
1195
|
+
fig.add_trace(
|
|
1196
|
+
go.Scatter(
|
|
1197
|
+
x=points["x"],
|
|
1198
|
+
y=points["y"],
|
|
1199
|
+
mode="markers+text" if chart.labels else "markers",
|
|
1200
|
+
name=chart.group_label(group),
|
|
1201
|
+
showlegend=bool(chart.group) and chart.legend is not None,
|
|
1202
|
+
text=[chart.series[c] for c in points.index],
|
|
1203
|
+
textposition=[
|
|
1204
|
+
_TEXT_POSITION[sides.get(str(c), "above right")]
|
|
1205
|
+
for c in points.index
|
|
1206
|
+
],
|
|
1207
|
+
textfont={"color": color},
|
|
1208
|
+
marker={
|
|
1209
|
+
"color": color,
|
|
1210
|
+
"size": float(SCATTER_CONFIG.get("marker_size", 60)) ** 0.5,
|
|
1211
|
+
"line": {
|
|
1212
|
+
"color": _color(
|
|
1213
|
+
SCATTER_CONFIG.get("edge_color", "#333333")
|
|
1214
|
+
),
|
|
1215
|
+
"width": float(SCATTER_CONFIG.get("edge_width", 0.8)),
|
|
1216
|
+
},
|
|
1217
|
+
},
|
|
1218
|
+
hovertemplate="%{text}: %{x}, %{y}<extra></extra>",
|
|
1219
|
+
)
|
|
1220
|
+
)
|
|
1221
|
+
fig.update_layout(
|
|
1222
|
+
xaxis={
|
|
1223
|
+
"range": list(chart.limits(rows["x"], "x")),
|
|
1224
|
+
"title_text": chart.xlabel,
|
|
1225
|
+
"ticksuffix": chart.x_fmt.units,
|
|
1226
|
+
"showgrid": True,
|
|
1227
|
+
},
|
|
1228
|
+
yaxis={
|
|
1229
|
+
"range": list(chart.limits(rows["y"], "y")),
|
|
1230
|
+
"title_text": chart.ylabel,
|
|
1231
|
+
"ticksuffix": chart.y_fmt.units,
|
|
1232
|
+
},
|
|
1233
|
+
)
|
|
1234
|
+
_legend_side(fig, chart.legend)
|
|
1235
|
+
return fig
|