tikzplotly 0.1.0__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.
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 @thomas-saigre
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.1
2
+ Name: tikzplotly
3
+ Version: 0.1.0
4
+ Summary: Convert plotly figures to LaTeX / tikz figures
5
+ Author-email: Thomas Saigre <tikzplotly@outlook.fr>
6
+ License: The MIT License (MIT)
7
+
8
+ Copyright (c) 2023 @thomas-saigre
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Project-URL: Code, https://github.com/thomas-saigre/tikzplotly
28
+ Project-URL: Issues, https://github.com/thomas-saigre/tikzplotly/issues
29
+ Keywords: plotly,latex,tikz,figure,conversion,graphics
30
+ Classifier: Development Status :: 5 - Production/Stable
31
+ Classifier: Programming Language :: Python
32
+ Classifier: Programming Language :: Python :: 3
33
+ Classifier: Programming Language :: Python :: 3.7
34
+ Classifier: Programming Language :: Python :: 3.8
35
+ Classifier: Programming Language :: Python :: 3.9
36
+ Classifier: Programming Language :: Python :: 3.10
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Operating System :: OS Independent
39
+ Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
40
+ Classifier: Topic :: Scientific/Engineering :: Visualization
41
+ Description-Content-Type: text/markdown
42
+ Provides-Extra: dev
43
+ License-File: LICENSE
44
+
45
+ ![alt text](doc/img/logo.svg "Tikzplotly")
46
+
47
+ # Tikzplotly
48
+
49
+ Convert [plotly](https://plotly.com/python/) figures to tikz code for inclusion into [PGFPlots](https://www.ctan.org/pkg/pgfplots) ([PGF/TikZ](https://www.ctan.org/pkg/pgf)) figures.
50
+
51
+ This results in a ti*k*z code, that can be easily included into your LaTeX document.
52
+ This also allow to easily edit the content of the figure.
53
+
54
+ ## Example
55
+
56
+ The following Python code
57
+
58
+ ```python
59
+ import plotly.express as px
60
+ import tikzplotly
61
+
62
+ df = px.data.gapminder().query("country=='Canada'")
63
+ fig = px.line(df, x="year", y="lifeExp", title='Life expectancy in Canada')
64
+ tikzplotly.save("example.tex", fig)
65
+ ```
66
+
67
+ will result in the following ti*k*z code
68
+
69
+ ```latex
70
+ % This file was created with tikzplotly version 0.0.1.
71
+ \begin{tikzpicture}
72
+
73
+ \definecolor{636efa}{HTML}{636efa}
74
+
75
+ \begin{axis}[
76
+ title=Life expectancy in Canada,
77
+ xlabel=year,
78
+ ylabel=lifeExp,
79
+ ]
80
+ \addplot+ [mark=none, solid, color=636efa, forget plot] table {%
81
+ 1952 68.75
82
+ 1957 69.96
83
+ 1962 71.3
84
+ 1967 72.13
85
+ 1972 72.88
86
+ 1977 74.21
87
+ 1982 75.76
88
+ 1987 76.86
89
+ 1992 77.95
90
+ 1997 78.61
91
+ 2002 79.77
92
+ 2007 80.653
93
+ };
94
+ \end{axis}
95
+ \end{tikzpicture}
96
+ ```
97
+
98
+
99
+ ## Note
100
+
101
+ * This module is in development and new features are added bit by bit, when needed. If you have a feature request, please open an issue with the plotly figure you want to convert and the desired output.
102
+ You can also submit a pull request with the desired feature !
103
+ * Some feature can result in different output between the plotly figure and the tikz figure, for instance the size of markers.
104
+
105
+
106
+ ## References
107
+
108
+ * [plotly](https://plotly.com/python/)
109
+ * [PGFPlots](https://www.ctan.org/pkg/pgfplots)
110
+ * [PGF/TikZ](https://www.ctan.org/pkg/pgf)
111
+ * [tikzplotlib](https://github.com/nschloe/tikzplotlib) : a similar project for matplotlib figures from which this one is inspired.
112
+
113
+
114
+ ## License
115
+
116
+ This project is licensed under the MIT [License](LICENSE).
@@ -0,0 +1,72 @@
1
+ ![alt text](doc/img/logo.svg "Tikzplotly")
2
+
3
+ # Tikzplotly
4
+
5
+ Convert [plotly](https://plotly.com/python/) figures to tikz code for inclusion into [PGFPlots](https://www.ctan.org/pkg/pgfplots) ([PGF/TikZ](https://www.ctan.org/pkg/pgf)) figures.
6
+
7
+ This results in a ti*k*z code, that can be easily included into your LaTeX document.
8
+ This also allow to easily edit the content of the figure.
9
+
10
+ ## Example
11
+
12
+ The following Python code
13
+
14
+ ```python
15
+ import plotly.express as px
16
+ import tikzplotly
17
+
18
+ df = px.data.gapminder().query("country=='Canada'")
19
+ fig = px.line(df, x="year", y="lifeExp", title='Life expectancy in Canada')
20
+ tikzplotly.save("example.tex", fig)
21
+ ```
22
+
23
+ will result in the following ti*k*z code
24
+
25
+ ```latex
26
+ % This file was created with tikzplotly version 0.0.1.
27
+ \begin{tikzpicture}
28
+
29
+ \definecolor{636efa}{HTML}{636efa}
30
+
31
+ \begin{axis}[
32
+ title=Life expectancy in Canada,
33
+ xlabel=year,
34
+ ylabel=lifeExp,
35
+ ]
36
+ \addplot+ [mark=none, solid, color=636efa, forget plot] table {%
37
+ 1952 68.75
38
+ 1957 69.96
39
+ 1962 71.3
40
+ 1967 72.13
41
+ 1972 72.88
42
+ 1977 74.21
43
+ 1982 75.76
44
+ 1987 76.86
45
+ 1992 77.95
46
+ 1997 78.61
47
+ 2002 79.77
48
+ 2007 80.653
49
+ };
50
+ \end{axis}
51
+ \end{tikzpicture}
52
+ ```
53
+
54
+
55
+ ## Note
56
+
57
+ * This module is in development and new features are added bit by bit, when needed. If you have a feature request, please open an issue with the plotly figure you want to convert and the desired output.
58
+ You can also submit a pull request with the desired feature !
59
+ * Some feature can result in different output between the plotly figure and the tikz figure, for instance the size of markers.
60
+
61
+
62
+ ## References
63
+
64
+ * [plotly](https://plotly.com/python/)
65
+ * [PGFPlots](https://www.ctan.org/pkg/pgfplots)
66
+ * [PGF/TikZ](https://www.ctan.org/pkg/pgf)
67
+ * [tikzplotlib](https://github.com/nschloe/tikzplotlib) : a similar project for matplotlib figures from which this one is inspired.
68
+
69
+
70
+ ## License
71
+
72
+ This project is licensed under the MIT [License](LICENSE).
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tikzplotly"
7
+ version = "0.1.0"
8
+ description = "Convert plotly figures to LaTeX / tikz figures"
9
+ readme = "README.md"
10
+ authors = [{name = "Thomas Saigre", email = "tikzplotly@outlook.fr"}]
11
+ license = { file = "LICENSE" }
12
+ classifiers = [
13
+ "Development Status :: 5 - Production/Stable",
14
+ "Programming Language :: Python",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.7",
17
+ "Programming Language :: Python :: 3.8",
18
+ "Programming Language :: Python :: 3.9",
19
+ "Programming Language :: Python :: 3.10",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Topic :: Multimedia :: Graphics :: Graphics Conversion",
23
+ "Topic :: Scientific/Engineering :: Visualization",
24
+ ]
25
+ keywords = ["plotly", "latex", "tikz", "figure", "conversion", "graphics"]
26
+ dependencies = [
27
+ "numpy",
28
+ "plotly"
29
+ ]
30
+
31
+ [project.optional-dependencies]
32
+ dev = ["pandas"]
33
+
34
+ [project.urls]
35
+ Code = "https://github.com/thomas-saigre/tikzplotly"
36
+ Issues = "https://github.com/thomas-saigre/tikzplotly/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from .__about__ import __version__
2
+ from ._save import get_tikz_code, save
3
+
4
+ __all__ = ["__version__", "get_tikz_code", "save"]
@@ -0,0 +1,82 @@
1
+ from ._axis import Axis
2
+ from ._tex import *
3
+ from ._color import convert_color
4
+
5
+ anchor_dict = {
6
+ "left": "west",
7
+ "right": "east",
8
+ "top": "north",
9
+ "bottom": "south",
10
+ "middle": "",
11
+ "center": "",
12
+ None: ""
13
+ }
14
+
15
+
16
+ def get_coordinates(x, y, x_ref, y_ref):
17
+ """Computed the coordinates of an annotation. The coordinates can be relative to the axis or absolute.
18
+ If only one coordinate is relative and the other is absolute, the relative coordinate is converted to absolute,
19
+ using the axis limits : x_return = xmin + x * (xmax - xmin) (idem for y)
20
+
21
+ Parameters
22
+ ----------
23
+ x
24
+ input x coordinate
25
+ y
26
+ input y coordinate
27
+ x_ref
28
+ reference of the x coordinate
29
+ y_ref
30
+ reference of the y coordinate
31
+
32
+ Returns
33
+ -------
34
+ x coordinate, y coordinate, relative (boolean indicating if the coordinates are relative to the axis)
35
+ """
36
+ if x_ref == "paper" and y_ref == "paper":
37
+ return x, y, True
38
+ elif x_ref == "paper" and y_ref != "paper":
39
+ x_text = "\\pgfkeysvalueof{/pgfplots/xmin} + " + str(x) + "*\\pgfkeysvalueof{/pgfplots/xmax}-" + str(x) + "*\\pgfkeysvalueof{/pgfplots/xmin}"
40
+ return x_text, y, False
41
+ elif x_ref != "paper" and y_ref == "paper":
42
+ y_text = "\\pgfkeysvalueof{/pgfplots/ymin} + " + str(y) + "*\\pgfkeysvalueof{/pgfplots/ymax}-" + str(y) + "*\\pgfkeysvalueof{/pgfplots/ymin}"
43
+ return x, y_text, False
44
+ else:
45
+ return x, y, False
46
+
47
+ def str_from_annotation(annotation_list, axis: Axis, colors_set):
48
+ """Create a string of LaTeX code for the annotations of a figure.
49
+
50
+ Parameters
51
+ ----------
52
+ annotation_list
53
+ list of annotations from Plotly figure, in fig.layout.annotations
54
+ axis
55
+ Axis object previously created
56
+ colors_set
57
+ colors used in the figure, to be filled with the colors of the annotations
58
+
59
+ Returns
60
+ -------
61
+ string of LaTeX code for the annotations
62
+ """
63
+ annotation_str = ""
64
+ if len(annotation_list) > 0:
65
+ axis.add_option("clip", "false")
66
+ for annotation in annotation_list:
67
+ x_anchor = anchor_dict[annotation.xanchor]
68
+ y_anchor = anchor_dict[annotation.yanchor]
69
+ x_ref = annotation.xref
70
+ y_ref = annotation.yref
71
+ x_coordinate, y_coordinate, relative = get_coordinates(annotation.x, annotation.y, x_ref, y_ref)
72
+ anchor_option = f"{y_anchor} {x_anchor}".rstrip()
73
+
74
+ if anchor_option != "":
75
+ anchor_option = f"anchor={anchor_option}"
76
+ node_options = anchor_option
77
+ if annotation.font.color is not None:
78
+ color_converted = convert_color(annotation.font.color)
79
+ colors_set.add(color_converted[:3])
80
+ node_options += f", color={color_converted[0]}"
81
+ annotation_str += tex_add_text(x_coordinate, y_coordinate, annotation.text, options=node_options, relative=relative)
82
+ return annotation_str
@@ -0,0 +1,114 @@
1
+ from ._color import convert_color
2
+ from ._tex import tex_begin_environment
3
+ class Axis():
4
+
5
+ def __init__(self, layout, colors_set):
6
+ """Initialize an Axis.
7
+
8
+ Parameters
9
+ ----------
10
+ layout
11
+ layout of the figure
12
+ colors_set
13
+ set of colors used in the figure, to be filled with the colors of the axis
14
+ """
15
+ self.x_label = layout.xaxis.title.text
16
+ self.y_label = layout.yaxis.title.text
17
+ self.title = layout.title.text
18
+ self.options = {}
19
+ self.environment = "axis"
20
+
21
+ if layout.xaxis.visible is False:
22
+ self.x_label = None
23
+ self.add_option("hide x axis", None)
24
+ if layout.yaxis.visible is False:
25
+ self.y_label = None
26
+ self.add_option("hide y axis", None)
27
+
28
+ # Handle log axes
29
+ if layout.xaxis.type == "log":
30
+ self.add_option("xmode", "log")
31
+ if layout.yaxis.type == "log":
32
+ self.add_option("ymode", "log")
33
+
34
+ if layout.plot_bgcolor is not None:
35
+ bg_color = convert_color(layout.plot_bgcolor)
36
+ colors_set.add(bg_color[:3])
37
+ opacity = bg_color[3]
38
+ if opacity < 1:
39
+ self.add_option("axis background/.style", f"{{fill={bg_color[0]}, opacity={opacity}}}")
40
+ else:
41
+ self.add_option("axis background/.style", f"{{fill={bg_color[0]}}}")
42
+
43
+ def set_x_label(self, x_label):
44
+ """Set the x label.
45
+
46
+ Parameters
47
+ ----------
48
+ x_label
49
+ x label
50
+ """
51
+ self.x_label = x_label
52
+
53
+ def set_y_label(self, y_label):
54
+ """Set the y label.
55
+
56
+ Parameters
57
+ ----------
58
+ y_label
59
+ y label
60
+ """
61
+ self.y_label = y_label
62
+
63
+ def add_option(self, option, value):
64
+ """Add an option to the axis, to be used in the axis environment.
65
+
66
+ Parameters
67
+ ----------
68
+ option
69
+ name of the option
70
+ value
71
+ value of the option, can be None
72
+ """
73
+ self.options[option] = value
74
+
75
+ def open_environment(self, stack_env):
76
+ """Open the axis environment.
77
+
78
+ Parameters
79
+ ----------
80
+ stack_env
81
+ stack of environments, to be filled with the axis environment
82
+ """
83
+ return tex_begin_environment(self.environment, stack_env, options=self.get_options())
84
+
85
+
86
+ def get_options(self):
87
+ """Get options string for the axis environment.
88
+
89
+ Returns
90
+ -------
91
+ string of all options with their values
92
+ """
93
+ content = False
94
+ options_str = ""
95
+ if self.title is not None:
96
+ options_str += f"title={self.title},\n"
97
+ content = True
98
+ if self.x_label is not None:
99
+ options_str += f"xlabel={self.x_label},\n"
100
+ content = True
101
+ if self.y_label is not None:
102
+ options_str += f"ylabel={self.y_label},\n"
103
+ content = True
104
+ if len(self.options) > 0:
105
+ for option, value in self.options.items():
106
+ if value is None:
107
+ options_str += f"{option},\n"
108
+ else:
109
+ options_str += f"{option}={value},\n"
110
+ content = True
111
+ if content:
112
+ return options_str[:-1]
113
+ else:
114
+ return None