tikzplotly 0.2.1__tar.gz → 0.2.2__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.
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/PKG-INFO +2 -1
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/pyproject.toml +10 -2
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/__about__.py +1 -1
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_color.py +10 -9
- tikzplotly-0.2.1/src/tikzplotly/_dataContainer.py → tikzplotly-0.2.2/src/tikzplotly/_data_container.py +1 -1
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_heatmap.py +3 -2
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_histogram.py +27 -27
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_polar.py +1 -1
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_save.py +4 -4
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_scatter.py +6 -36
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_scatter3d.py +6 -35
- tikzplotly-0.2.2/src/tikzplotly/_trace_utils.py +70 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_utils.py +2 -10
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly.egg-info/PKG-INFO +2 -1
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly.egg-info/SOURCES.txt +3 -1
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly.egg-info/requires.txt +1 -0
- tikzplotly-0.2.2/tests/test_colors.py +53 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/tests/test_heatmap.py +9 -5
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/tests/test_histograms.py +10 -3
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/tests/test_markers.py +7 -1
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/tests/test_polar.py +3 -1
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/tests/test_scatter.py +8 -6
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/tests/test_scatter3d.py +10 -2
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/tests/test_specific.py +16 -12
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/LICENSE +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/README.md +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/setup.cfg +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tests/test_bars.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tests/test_heatmaps.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tests/test_histograms.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tests/test_line_charts.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tests/test_markers.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tests/test_polar.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tests/test_scatter3d.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/__init__.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_annotations.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_axis.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_bar.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_dash.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_data.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_marker.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly/_tex.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly.egg-info/dependency_links.txt +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/src/tikzplotly.egg-info/top_level.txt +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/tests/test_bars.py +0 -0
- {tikzplotly-0.2.1 → tikzplotly-0.2.2}/tests/test_tikzplotly.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tikzplotly
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Convert plotly figures to LaTeX / TikZ figures
|
|
5
5
|
Author-email: Thomas Saigre <tikzplotly@outlook.fr>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -44,6 +44,7 @@ License-File: LICENSE
|
|
|
44
44
|
Requires-Dist: numpy
|
|
45
45
|
Requires-Dist: plotly
|
|
46
46
|
Requires-Dist: pillow
|
|
47
|
+
Requires-Dist: kaleido
|
|
47
48
|
Provides-Extra: dev
|
|
48
49
|
Requires-Dist: pandas; extra == "dev"
|
|
49
50
|
Dynamic: license-file
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tikzplotly"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Convert plotly figures to LaTeX / TikZ figures"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{name = "Thomas Saigre", email = "tikzplotly@outlook.fr"}]
|
|
@@ -27,7 +27,8 @@ keywords = ["plotly", "latex", "tikz", "figure", "conversion", "graphics"]
|
|
|
27
27
|
dependencies = [
|
|
28
28
|
"numpy",
|
|
29
29
|
"plotly",
|
|
30
|
-
"pillow"
|
|
30
|
+
"pillow",
|
|
31
|
+
"kaleido"
|
|
31
32
|
]
|
|
32
33
|
|
|
33
34
|
[project.optional-dependencies]
|
|
@@ -36,3 +37,10 @@ dev = ["pandas"]
|
|
|
36
37
|
[project.urls]
|
|
37
38
|
Code = "https://github.com/thomas-saigre/tikzplotly"
|
|
38
39
|
Issues = "https://github.com/thomas-saigre/tikzplotly/issues"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
[tool.pytest.ini_options]
|
|
43
|
+
filterwarnings = [
|
|
44
|
+
"ignore:png image has not been reduced.*:UserWarning",
|
|
45
|
+
"ignore:Text template is not supported yet.:UserWarning",
|
|
46
|
+
]
|
|
@@ -30,7 +30,7 @@ def convert_color(color):
|
|
|
30
30
|
string from plotly color palette, can be one of the following:
|
|
31
31
|
- hex string : "#______"
|
|
32
32
|
- rgb string : "rgb(__, __, __)" with values between 0 and 255
|
|
33
|
-
- rgba string : "rgba(__, __, __, __)" with values between 0 and 255 and an opacity value between 0 and 1
|
|
33
|
+
- rgba string : "rgba(__, __, __[, __])" with values between 0 and 255 and an opacity value between 0 and 1 (optional)
|
|
34
34
|
- color name : "red", "green", "blue", "yellow", "orange", "purple", "brown", "black", "gray", "white" or any other color name from
|
|
35
35
|
https://github.com/plotly/plotly.py/blob/main/templategen/utils/colors.py
|
|
36
36
|
|
|
@@ -45,20 +45,21 @@ def convert_color(color):
|
|
|
45
45
|
if color is None:
|
|
46
46
|
return None, None, None, 1
|
|
47
47
|
if isinstance(color, numpy.ndarray):
|
|
48
|
-
warn("Color from data is not supported yet. Returning
|
|
49
|
-
return
|
|
48
|
+
warn("Color from data is not supported yet. Returning no color.")
|
|
49
|
+
return None, None, None, 1
|
|
50
50
|
if not isinstance(color, str):
|
|
51
|
-
warn(f"Color {color} type '{color.__class__.__name__}' is not supported yet. Returning
|
|
52
|
-
return
|
|
51
|
+
warn(f"Color {color} type '{color.__class__.__name__}' is not supported yet. Returning no color.")
|
|
52
|
+
return None, None, None, 1
|
|
53
53
|
|
|
54
54
|
if color.startswith("#"):
|
|
55
55
|
return color[1:], "HTML", color[1:], 1
|
|
56
56
|
|
|
57
57
|
if color.startswith("rgba"):
|
|
58
|
-
sp = color.split("(")[1].split(",")
|
|
59
|
-
rgb_color = sp
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
sp = color.split("(")[1].replace(')', '').split(",")
|
|
59
|
+
rgb_color = [s.strip() for s in sp]
|
|
60
|
+
r, g, b = int(rgb_color[0]), int(rgb_color[1]), int(rgb_color[2])
|
|
61
|
+
opacity = float(rgb_color[3]) if len(rgb_color) == 4 else 1.0
|
|
62
|
+
return hashlib.sha1(f"{r}, {g}, {b}".encode('UTF-8')).hexdigest()[:10], "RGB", rgb_str(r, g, b), opacity
|
|
62
63
|
|
|
63
64
|
if color.startswith("rgb"):
|
|
64
65
|
color = color[4:-1].replace("[", "{").replace("]", "}")
|
|
@@ -186,7 +186,7 @@ class DataContainer:
|
|
|
186
186
|
return data.name, data.z_name
|
|
187
187
|
data_obj = Data3D(x, y, z, name)
|
|
188
188
|
self.data.append(data_obj)
|
|
189
|
-
return data_obj.name
|
|
189
|
+
return data_obj.name
|
|
190
190
|
|
|
191
191
|
def export_data(self):
|
|
192
192
|
"""Generate LaTeX code to export the data from DataContainer.
|
|
@@ -102,9 +102,10 @@ def draw_heatmap(data, fig, img_name, axis: Axis):
|
|
|
102
102
|
|
|
103
103
|
img_bytes = fig_copy.to_image(format="png") # The image created by plotly keeps places around the heatmap
|
|
104
104
|
cropped_image = crop_image(Image.open(io.BytesIO(img_bytes))) # so we crop all the white around the figure
|
|
105
|
-
resized_image = resize_image(cropped_image, *figure_data.shape)
|
|
105
|
+
resized_image = resize_image(cropped_image, *figure_data.shape) # and we resize it so each square is a 1px x 1px square
|
|
106
106
|
|
|
107
|
-
os.
|
|
107
|
+
dirname = os.path.dirname(img_name) or '.' # Ensure that dirname is not empty
|
|
108
|
+
os.makedirs(dirname, exist_ok=True) # Make sure the directory exists
|
|
108
109
|
resized_image.save(img_name)
|
|
109
110
|
|
|
110
111
|
|
|
@@ -50,6 +50,27 @@ def formalize_data(data, axis:Axis, row_sep="\\\\"):
|
|
|
50
50
|
|
|
51
51
|
return data_str
|
|
52
52
|
|
|
53
|
+
def treat_histnorm(histnorm: str, hist_options: dict):
|
|
54
|
+
"""Handle the normalization option of the histogram
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
histnorm : str
|
|
59
|
+
The normalization mode for the histogram.
|
|
60
|
+
hist_options : dict
|
|
61
|
+
Dictionary to store histogram options.
|
|
62
|
+
"""
|
|
63
|
+
if histnorm in ("percent", "probability", "density"):
|
|
64
|
+
warn(
|
|
65
|
+
f"Sorry, I did not find an equivalent for histnorm='{histnorm}' in TikZ. "
|
|
66
|
+
"If you need this feature implemented, please open an issue, if possible with a MWE pgfplots code "
|
|
67
|
+
"that would plot this :).\nFor now, the histogram will be plotted without normalization "
|
|
68
|
+
"(as if histnorm='probability density')."
|
|
69
|
+
)
|
|
70
|
+
hist_options["density"] = None
|
|
71
|
+
elif histnorm in ("probability density", ):
|
|
72
|
+
hist_options["density"] = None
|
|
73
|
+
|
|
53
74
|
def draw_histogram(trace, axis: Axis, colors_set, row_sep="\\\\"):
|
|
54
75
|
"""
|
|
55
76
|
Draw a histogram and return the TikZ code.
|
|
@@ -79,7 +100,8 @@ def draw_histogram(trace, axis: Axis, colors_set, row_sep="\\\\"):
|
|
|
79
100
|
|
|
80
101
|
code = ""
|
|
81
102
|
|
|
82
|
-
plot_options = {
|
|
103
|
+
plot_options = {}
|
|
104
|
+
plot_options["hist"] = None
|
|
83
105
|
type_options = {"row sep": row_sep, "y index": 0}
|
|
84
106
|
hist_options = {}
|
|
85
107
|
|
|
@@ -92,36 +114,15 @@ def draw_histogram(trace, axis: Axis, colors_set, row_sep="\\\\"):
|
|
|
92
114
|
axis.add_option("x filter/.expression", "rawy")
|
|
93
115
|
axis.add_option("y filter/.expression", "rawx")
|
|
94
116
|
hist_options["handler/.style"] = "{xbar interval}"
|
|
95
|
-
|
|
117
|
+
else: # trace.x and trace.y are both empty
|
|
118
|
+
warn("Empty histogram. Returning no plot")
|
|
119
|
+
return ""
|
|
96
120
|
|
|
97
121
|
|
|
98
122
|
if trace.nbinsx is not None:
|
|
99
123
|
hist_options["bins"] = trace.nbinsx
|
|
100
124
|
|
|
101
|
-
|
|
102
|
-
warn(
|
|
103
|
-
f"Sorry, I did not find an equivalent for histnorm='{trace.histnorm}' in TikZ. "
|
|
104
|
-
"If you need this feature implemented, please open an issue, if possible with a MWE pgfplots code "
|
|
105
|
-
"that would plot this :).\nFor now, the histogram will be plotted without normalization "
|
|
106
|
-
"(as if histnorm='probability density')."
|
|
107
|
-
)
|
|
108
|
-
hist_options["density"] = None
|
|
109
|
-
elif trace.histnorm == "probability":
|
|
110
|
-
warn(
|
|
111
|
-
f"Sorry, I did not find an equivalent for histnorm='{trace.histnorm}' in TikZ. "
|
|
112
|
-
"If you need this feature implemented, please open an issue, if possible with a MWE pgfplots code that would plot this :).\n"
|
|
113
|
-
"For now, the histogram will be plotted without normalization (as if histnorm='probability density')."
|
|
114
|
-
)
|
|
115
|
-
hist_options["density"] = None
|
|
116
|
-
elif trace.histnorm == "density":
|
|
117
|
-
warn(
|
|
118
|
-
f"Sorry, I did not find an equivalent for histnorm='{trace.histnorm}' in TikZ. "
|
|
119
|
-
"If you need this feature implemented, please open an issue, if possible with a MWE pgfplots code that would plot this :).\n"
|
|
120
|
-
"For now, the histogram will be plotted without normalization (as if histnorm='probability density')."
|
|
121
|
-
)
|
|
122
|
-
hist_options["density"] = None
|
|
123
|
-
elif trace.histnorm == "probability density":
|
|
124
|
-
hist_options["density"] = None
|
|
125
|
+
treat_histnorm(trace.histnorm, hist_options)
|
|
125
126
|
|
|
126
127
|
if trace.cumulative.enabled:
|
|
127
128
|
hist_options["cumulative"] = None
|
|
@@ -152,5 +153,4 @@ def draw_histogram(trace, axis: Axis, colors_set, row_sep="\\\\"):
|
|
|
152
153
|
code += tex_addplot(data_str, plot_type = "table",
|
|
153
154
|
options = option_dict_to_str(plot_options), type_options=option_dict_to_str(type_options))
|
|
154
155
|
|
|
155
|
-
|
|
156
156
|
return code
|
|
@@ -7,7 +7,7 @@ from ._axis import Axis
|
|
|
7
7
|
from ._utils import option_dict_to_str
|
|
8
8
|
from ._tex import tex_addplot
|
|
9
9
|
from ._color import convert_color
|
|
10
|
-
from .
|
|
10
|
+
from ._data_container import DataContainer
|
|
11
11
|
|
|
12
12
|
def get_polar_coord(trace, axis: Axis, data_container: DataContainer):
|
|
13
13
|
"""Get polar coordinates from the trace
|
|
@@ -19,7 +19,7 @@ from ._polar import get_polar_coord, draw_scatterpolar
|
|
|
19
19
|
from ._axis import Axis
|
|
20
20
|
from ._color import convert_color
|
|
21
21
|
from ._annotations import str_from_annotation
|
|
22
|
-
from .
|
|
22
|
+
from ._data_container import DataContainer
|
|
23
23
|
from ._utils import sanitize_tex_text, sanitize_text
|
|
24
24
|
|
|
25
25
|
|
|
@@ -78,13 +78,13 @@ def get_tikz_code(
|
|
|
78
78
|
|
|
79
79
|
# If x is textual => symbolic x coords
|
|
80
80
|
if all(isinstance(v, str) for v in trace.x):
|
|
81
|
-
sanitized_trace_x = [sanitize_text(x, keep_space=-1) for x in trace.x]
|
|
81
|
+
sanitized_trace_x = [sanitize_text(str(x), keep_space=-1) for x in trace.x]
|
|
82
82
|
axis.add_option("symbolic x coords", "{" + ",".join(sanitized_trace_x) + "}")
|
|
83
83
|
axis.add_option("xtick", "data")
|
|
84
84
|
|
|
85
85
|
# If y is textual => symbolic y coords
|
|
86
86
|
if all(isinstance(v, str) for v in trace.y):
|
|
87
|
-
sanitized_trace_y = [sanitize_text(y, keep_space=-1) for y in trace.y]
|
|
87
|
+
sanitized_trace_y = [sanitize_text(str(y), keep_space=-1) for y in trace.y]
|
|
88
88
|
axis.add_option("symbolic y coords", "{" + ",".join(sanitized_trace_y) + "}")
|
|
89
89
|
axis.add_option("ytick", "data")
|
|
90
90
|
|
|
@@ -173,7 +173,7 @@ def get_tikz_code(
|
|
|
173
173
|
if hasattr(figure_layout.scene, "title") and getattr(figure_layout.scene.title, "text", None):
|
|
174
174
|
axis.add_option("title", f"{{{sanitize_tex_text(figure_layout.scene.title.text)}}}")
|
|
175
175
|
|
|
176
|
-
data_name_macro
|
|
176
|
+
data_name_macro = data_container.add_data3d(trace.x, trace.y, trace.z, trace.name)
|
|
177
177
|
data_str.append(draw_scatter3d(data_name_macro, trace, colors_set))
|
|
178
178
|
|
|
179
179
|
if trace.name and trace['showlegend'] is not False:
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
Provides functionality to convert Plotly scatter traces into TikZ/PGFPlots code for LaTeX documents.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from warnings import warn
|
|
6
5
|
import numpy as np
|
|
7
6
|
from ._tex import tex_addplot, tex_add_text
|
|
8
7
|
from ._color import convert_color
|
|
9
|
-
from ._marker import marker_symbol_to_tex
|
|
10
8
|
from ._dash import DASH_PATTERN
|
|
11
9
|
from ._axis import Axis
|
|
12
10
|
from ._data import data_type
|
|
11
|
+
from ._trace_utils import configure_marker_options, finalize_marker_options
|
|
13
12
|
from ._utils import px_to_pt, option_dict_to_str
|
|
14
13
|
|
|
14
|
+
|
|
15
15
|
def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set):
|
|
16
16
|
"""Get code for a scatter trace.
|
|
17
17
|
|
|
@@ -53,15 +53,8 @@ def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set):
|
|
|
53
53
|
options_dict = {}
|
|
54
54
|
mark_option_dict = {}
|
|
55
55
|
|
|
56
|
-
if
|
|
57
|
-
|
|
58
|
-
symbol, symbol_options = marker_symbol_to_tex(marker.symbol)
|
|
59
|
-
options_dict["mark"] = symbol
|
|
60
|
-
options_dict["only marks"] = None
|
|
61
|
-
if symbol_options is not None:
|
|
62
|
-
mark_option_dict[symbol_options[0]] = symbol_options[1]
|
|
63
|
-
else:
|
|
64
|
-
options_dict["only marks"] = None
|
|
56
|
+
if "markers" in mode:
|
|
57
|
+
configure_marker_options(mode, marker, options_dict, mark_option_dict, color_set)
|
|
65
58
|
|
|
66
59
|
if scatter.marker.size is not None:
|
|
67
60
|
options_dict["mark size"] = px_to_pt(marker.size)
|
|
@@ -71,14 +64,7 @@ def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set):
|
|
|
71
64
|
mark_option_dict["solid"] = None
|
|
72
65
|
mark_option_dict["fill"] = convert_color(scatter.marker.color)[0]
|
|
73
66
|
|
|
74
|
-
if (
|
|
75
|
-
if line.color is not None:
|
|
76
|
-
color_set.add(convert_color(line.color)[:3])
|
|
77
|
-
mark_option_dict["draw"] = convert_color(line.color)[0]
|
|
78
|
-
if line.width is not None:
|
|
79
|
-
mark_option_dict["line width"] = px_to_pt(line.width)
|
|
80
|
-
|
|
81
|
-
if (angle:=scatter.marker.angle) is not None:
|
|
67
|
+
if (angle := scatter.marker.angle) is not None:
|
|
82
68
|
mark_option_dict["rotate"] = angle
|
|
83
69
|
|
|
84
70
|
if (opacity := scatter.opacity) is not None:
|
|
@@ -86,22 +72,7 @@ def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set):
|
|
|
86
72
|
if (opacity := scatter.marker.opacity) is not None:
|
|
87
73
|
mark_option_dict["opacity"] = np.round(opacity, 2)
|
|
88
74
|
|
|
89
|
-
|
|
90
|
-
mark_options = option_dict_to_str(mark_option_dict)
|
|
91
|
-
options_dict["mark options"] = f"{{{mark_options}}}"
|
|
92
|
-
|
|
93
|
-
elif mode == "lines":
|
|
94
|
-
options_dict["mark"] = "none"
|
|
95
|
-
|
|
96
|
-
elif "lines" in mode and "markers" in mode:
|
|
97
|
-
if marker.symbol is not None:
|
|
98
|
-
symbol, symbol_options = marker_symbol_to_tex(marker.symbol)
|
|
99
|
-
options_dict["mark"] = symbol
|
|
100
|
-
if symbol_options is not None:
|
|
101
|
-
mark_option_dict[symbol_options[0]] = symbol_options[1]
|
|
102
|
-
|
|
103
|
-
else:
|
|
104
|
-
warn(f"Scatter : Mode {mode} is not supported yet.")
|
|
75
|
+
finalize_marker_options(mode, options_dict, mark_option_dict, "Scatter")
|
|
105
76
|
|
|
106
77
|
if scatter.line.width is not None:
|
|
107
78
|
options_dict["line width"] = px_to_pt(scatter.line.width)
|
|
@@ -110,7 +81,6 @@ def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set):
|
|
|
110
81
|
if scatter.connectgaps in [False, None] and None in scatter.x:
|
|
111
82
|
options_dict["unbounded coords"] = "jump"
|
|
112
83
|
|
|
113
|
-
|
|
114
84
|
if scatter.line.color is not None:
|
|
115
85
|
options_dict["color"] = convert_color(scatter.line.color)[0]
|
|
116
86
|
if "mark" in mode:
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Provides functionality to convert Plotly 3D scatter traces into TikZ/PGFPlots code for LaTeX documents.
|
|
3
3
|
"""
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
import numpy as np
|
|
6
6
|
from ._color import convert_color
|
|
7
|
-
from .
|
|
7
|
+
from ._trace_utils import configure_marker_options, finalize_marker_options
|
|
8
8
|
from ._utils import px_to_pt, option_dict_to_str
|
|
9
9
|
|
|
10
|
+
|
|
10
11
|
def draw_scatter3d(data_name, scatter, color_set):
|
|
11
12
|
"""
|
|
12
13
|
Get code for a scatter3d trace.
|
|
@@ -28,16 +29,8 @@ def draw_scatter3d(data_name, scatter, color_set):
|
|
|
28
29
|
options_dict = {}
|
|
29
30
|
mark_option_dict = {}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if marker.symbol is not None:
|
|
34
|
-
symbol, symbol_options = marker_symbol_to_tex(marker.symbol)
|
|
35
|
-
options_dict["mark"] = symbol
|
|
36
|
-
options_dict["only marks"] = None
|
|
37
|
-
if symbol_options is not None:
|
|
38
|
-
mark_option_dict[symbol_options[0]] = symbol_options[1]
|
|
39
|
-
else:
|
|
40
|
-
options_dict["only marks"] = None
|
|
32
|
+
if "markers" in mode:
|
|
33
|
+
configure_marker_options(mode, marker, options_dict, mark_option_dict, color_set)
|
|
41
34
|
|
|
42
35
|
if marker.size is not None:
|
|
43
36
|
size = marker.size
|
|
@@ -53,34 +46,12 @@ def draw_scatter3d(data_name, scatter, color_set):
|
|
|
53
46
|
mark_option_dict["solid"] = None
|
|
54
47
|
mark_option_dict["fill"] = convert_color(c)[0]
|
|
55
48
|
|
|
56
|
-
if (line := marker.line) is not None:
|
|
57
|
-
if line.color is not None:
|
|
58
|
-
color_set.add(convert_color(line.color)[:3])
|
|
59
|
-
mark_option_dict["draw"] = convert_color(line.color)[0]
|
|
60
|
-
if line.width is not None:
|
|
61
|
-
mark_option_dict["line width"] = px_to_pt(line.width)
|
|
62
|
-
|
|
63
49
|
if (opacity := scatter.opacity) is not None:
|
|
64
50
|
options_dict["opacity"] = opacity
|
|
65
51
|
if (opacity := marker.opacity) is not None:
|
|
66
52
|
mark_option_dict["opacity"] = opacity
|
|
67
53
|
|
|
68
|
-
|
|
69
|
-
mark_options = option_dict_to_str(mark_option_dict)
|
|
70
|
-
options_dict["mark options"] = f"{{{mark_options}}}"
|
|
71
|
-
|
|
72
|
-
elif mode == "lines":
|
|
73
|
-
options_dict["mark"] = "none"
|
|
74
|
-
|
|
75
|
-
elif "lines" in mode and "markers" in mode:
|
|
76
|
-
if marker.symbol is not None:
|
|
77
|
-
symbol, symbol_options = marker_symbol_to_tex(marker.symbol)
|
|
78
|
-
options_dict["mark"] = symbol
|
|
79
|
-
if symbol_options is not None:
|
|
80
|
-
mark_option_dict[symbol_options[0]] = symbol_options[1]
|
|
81
|
-
|
|
82
|
-
else:
|
|
83
|
-
warn(f"Scatter3d : Mode {mode} is not supported yet.")
|
|
54
|
+
finalize_marker_options(mode, options_dict, mark_option_dict, "Scatter3d")
|
|
84
55
|
|
|
85
56
|
if scatter.line is not None:
|
|
86
57
|
if scatter.line.width is not None:
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Shared helpers for Plotly trace to TikZ conversion."""
|
|
2
|
+
|
|
3
|
+
from warnings import warn
|
|
4
|
+
|
|
5
|
+
from ._color import convert_color
|
|
6
|
+
from ._marker import marker_symbol_to_tex
|
|
7
|
+
from ._utils import px_to_pt, option_dict_to_str
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def configure_marker_options(mode, marker, options_dict, mark_option_dict, color_set):
|
|
11
|
+
"""Populate marker-related TikZ options for scatter-like traces.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
mode
|
|
16
|
+
Plotly trace mode string (for example ``markers`` or ``markers+lines``).
|
|
17
|
+
marker
|
|
18
|
+
Plotly marker object from the trace.
|
|
19
|
+
options_dict
|
|
20
|
+
Dictionary collecting top-level PGFPlots options.
|
|
21
|
+
mark_option_dict
|
|
22
|
+
Dictionary collecting nested ``mark options`` for PGFPlots.
|
|
23
|
+
color_set
|
|
24
|
+
Set used to track colors that must be defined in the LaTeX output.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
if marker.symbol is not None:
|
|
28
|
+
symbol, symbol_options = marker_symbol_to_tex(marker.symbol)
|
|
29
|
+
options_dict["mark"] = symbol
|
|
30
|
+
if "lines" not in mode:
|
|
31
|
+
options_dict["only marks"] = None
|
|
32
|
+
if symbol_options is not None:
|
|
33
|
+
mark_option_dict[symbol_options[0]] = symbol_options[1]
|
|
34
|
+
elif "lines" not in mode:
|
|
35
|
+
options_dict["only marks"] = None
|
|
36
|
+
|
|
37
|
+
if (line := marker.line) is not None:
|
|
38
|
+
if line.color is not None:
|
|
39
|
+
color = convert_color(line.color)
|
|
40
|
+
color_set.add(color[:3])
|
|
41
|
+
mark_option_dict["draw"] = color[0]
|
|
42
|
+
if line.width is not None:
|
|
43
|
+
mark_option_dict["line width"] = px_to_pt(line.width)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def finalize_marker_options(mode, options_dict, mark_option_dict, trace_name):
|
|
47
|
+
"""Finalize marker options and handle unsupported modes.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
mode
|
|
52
|
+
Plotly trace mode string.
|
|
53
|
+
options_dict
|
|
54
|
+
Dictionary collecting top-level PGFPlots options.
|
|
55
|
+
mark_option_dict
|
|
56
|
+
Dictionary collecting nested ``mark options`` for PGFPlots.
|
|
57
|
+
trace_name
|
|
58
|
+
Name used in warnings to identify the trace kind.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
if "markers" in mode:
|
|
62
|
+
if mark_option_dict:
|
|
63
|
+
mark_options = option_dict_to_str(mark_option_dict)
|
|
64
|
+
options_dict["mark options"] = f"{{{mark_options}}}"
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
if mode == "lines":
|
|
68
|
+
options_dict["mark"] = "none"
|
|
69
|
+
else:
|
|
70
|
+
warn(f"{trace_name} : Mode {mode} is not supported yet.")
|
|
@@ -93,18 +93,10 @@ def sanitize_char(ch: str, keep_space: int = 0) -> str:
|
|
|
93
93
|
if ch == "@":
|
|
94
94
|
return "at"
|
|
95
95
|
if ch == " ":
|
|
96
|
-
if keep_space == 1
|
|
97
|
-
return " "
|
|
98
|
-
if keep_space == 0:
|
|
99
|
-
return "_"
|
|
100
|
-
return ""
|
|
96
|
+
return " " if keep_space == 1 else "_" if keep_space == 0 else ""
|
|
101
97
|
if ch in "[]{}= ":
|
|
102
98
|
return f"x{ord(ch):x}"
|
|
103
|
-
|
|
104
|
-
if ord(ch) > 127:
|
|
105
|
-
return f"x{ord(ch):x}"
|
|
106
|
-
# if not printable, return hex
|
|
107
|
-
if not ch.isprintable():
|
|
99
|
+
if ord(ch) > 127 or not ch.isprintable(): # not ascii or not printable: return hex
|
|
108
100
|
return f"x{ord(ch):x}"
|
|
109
101
|
return ch
|
|
110
102
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tikzplotly
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Convert plotly figures to LaTeX / TikZ figures
|
|
5
5
|
Author-email: Thomas Saigre <tikzplotly@outlook.fr>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -44,6 +44,7 @@ License-File: LICENSE
|
|
|
44
44
|
Requires-Dist: numpy
|
|
45
45
|
Requires-Dist: plotly
|
|
46
46
|
Requires-Dist: pillow
|
|
47
|
+
Requires-Dist: kaleido
|
|
47
48
|
Provides-Extra: dev
|
|
48
49
|
Requires-Dist: pandas; extra == "dev"
|
|
49
50
|
Dynamic: license-file
|
|
@@ -16,7 +16,7 @@ src/tikzplotly/_bar.py
|
|
|
16
16
|
src/tikzplotly/_color.py
|
|
17
17
|
src/tikzplotly/_dash.py
|
|
18
18
|
src/tikzplotly/_data.py
|
|
19
|
-
src/tikzplotly/
|
|
19
|
+
src/tikzplotly/_data_container.py
|
|
20
20
|
src/tikzplotly/_heatmap.py
|
|
21
21
|
src/tikzplotly/_histogram.py
|
|
22
22
|
src/tikzplotly/_marker.py
|
|
@@ -25,6 +25,7 @@ src/tikzplotly/_save.py
|
|
|
25
25
|
src/tikzplotly/_scatter.py
|
|
26
26
|
src/tikzplotly/_scatter3d.py
|
|
27
27
|
src/tikzplotly/_tex.py
|
|
28
|
+
src/tikzplotly/_trace_utils.py
|
|
28
29
|
src/tikzplotly/_utils.py
|
|
29
30
|
src/tikzplotly.egg-info/PKG-INFO
|
|
30
31
|
src/tikzplotly.egg-info/SOURCES.txt
|
|
@@ -32,6 +33,7 @@ src/tikzplotly.egg-info/dependency_links.txt
|
|
|
32
33
|
src/tikzplotly.egg-info/requires.txt
|
|
33
34
|
src/tikzplotly.egg-info/top_level.txt
|
|
34
35
|
tests/test_bars.py
|
|
36
|
+
tests/test_colors.py
|
|
35
37
|
tests/test_heatmap.py
|
|
36
38
|
tests/test_histograms.py
|
|
37
39
|
tests/test_markers.py
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pathlib
|
|
3
|
+
from contextlib import nullcontext
|
|
4
|
+
|
|
5
|
+
import numpy
|
|
6
|
+
import plotly.graph_objects as go
|
|
7
|
+
import plotly.express as px
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from .helpers import assert_equality
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
this_dir = pathlib.Path(__file__).resolve().parent
|
|
14
|
+
test_name = "test_colors"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def plot_color(color_scheme):
|
|
18
|
+
fig = go.Figure()
|
|
19
|
+
fig.add_trace(go.Scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16], marker_color=color_scheme))
|
|
20
|
+
return fig
|
|
21
|
+
|
|
22
|
+
def plot_transparent_background():
|
|
23
|
+
fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16])
|
|
24
|
+
fig.update_layout(plot_bgcolor='rgba(255, 182, 193, .5)')
|
|
25
|
+
|
|
26
|
+
return fig
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.mark.parametrize(
|
|
30
|
+
"color, warning_match",
|
|
31
|
+
[
|
|
32
|
+
pytest.param(None, None, id="none"),
|
|
33
|
+
pytest.param(numpy.array([1, 2, 3]), "Color from data is not supported yet", id="numpy-array"), # ("blue", "HTML", "0000ff", 1)
|
|
34
|
+
pytest.param(123, "Color 123 type 'int' is not supported yet", id="non-string"), # ("blue", "HTML", "0000ff", 1)
|
|
35
|
+
pytest.param("#ffb6c1", None, id="hex"),
|
|
36
|
+
pytest.param("rgba(255, 182, 193, .2)", None, id="rgba-with-opacity"),
|
|
37
|
+
pytest.param("rgba(255, 182, 193)", None, id="rgba-without-opacity"),
|
|
38
|
+
pytest.param("rgb(255, 182, 193)", None, id="rgb"),
|
|
39
|
+
pytest.param("red", None, id="named-color"),
|
|
40
|
+
pytest.param("LightBlue", None, id="colors-dict-hit"),
|
|
41
|
+
],
|
|
42
|
+
)
|
|
43
|
+
def test_color(color, warning_match, request):
|
|
44
|
+
id = request.node.callspec.id
|
|
45
|
+
if warning_match is None:
|
|
46
|
+
context = nullcontext()
|
|
47
|
+
else:
|
|
48
|
+
context = pytest.warns(UserWarning, match=warning_match)
|
|
49
|
+
with context:
|
|
50
|
+
assert_equality(plot_color(color), os.path.join(this_dir, test_name, f"{test_name}_{id}_reference.tex"))
|
|
51
|
+
|
|
52
|
+
def test_transparent_background():
|
|
53
|
+
assert_equality(plot_transparent_background(), os.path.join(this_dir, test_name, test_name + "_transparent_background_reference.tex"))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import plotly.express as px
|
|
2
2
|
import plotly.graph_objects as go
|
|
3
3
|
import numpy as np
|
|
4
|
+
import pytest
|
|
4
5
|
import os
|
|
5
6
|
from .helpers import assert_equality
|
|
6
7
|
import pathlib
|
|
@@ -22,6 +23,7 @@ def plot_2():
|
|
|
22
23
|
return fig
|
|
23
24
|
|
|
24
25
|
def plot_3():
|
|
26
|
+
# A plot with no colorscale
|
|
25
27
|
fig = go.Figure(data=go.Heatmap(
|
|
26
28
|
z=[[1, None, 30, 50, 1], [20, 1, 60, 80, 30], [30, 60, 1, -10, 20]],
|
|
27
29
|
x=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
|
|
@@ -35,7 +37,7 @@ def plot_4():
|
|
|
35
37
|
programmers = ['Alex','Nicole','Sara','Etienne','Chelsea','Jody','Marianne']
|
|
36
38
|
|
|
37
39
|
base = datetime.datetime(2021, 7, 20, 19, 30, 0)
|
|
38
|
-
dates = base -
|
|
40
|
+
dates = [base - datetime.timedelta(days=int(i)) for i in np.arange(180)]
|
|
39
41
|
np.random.seed(43)
|
|
40
42
|
z = np.random.poisson(size=(len(programmers), len(dates)))
|
|
41
43
|
|
|
@@ -51,7 +53,7 @@ def plot_4():
|
|
|
51
53
|
|
|
52
54
|
return fig
|
|
53
55
|
|
|
54
|
-
def
|
|
56
|
+
def plot_empty_trace():
|
|
55
57
|
fig = px.imshow([[1, 20, 30],
|
|
56
58
|
[20, 1, 60],
|
|
57
59
|
[30, 60, 1]])
|
|
@@ -65,10 +67,12 @@ def test_2():
|
|
|
65
67
|
assert_equality(plot_2(), os.path.join(this_dir, test_name, test_name + "_2_reference.tex"), img_name="/tmp/tikzplotly/fig2.png")
|
|
66
68
|
|
|
67
69
|
def test_3():
|
|
68
|
-
|
|
70
|
+
with pytest.warns(UserWarning, match="No colorscale found, using default"):
|
|
71
|
+
assert_equality(plot_3(), os.path.join(this_dir, test_name, test_name + "_3_reference.tex"), img_name="/tmp/tikzplotly/fig3.png")
|
|
69
72
|
|
|
70
73
|
def test_4():
|
|
71
74
|
assert_equality(plot_4(), os.path.join(this_dir, test_name, test_name + "_4_reference.tex"), img_name="/tmp/tikzplotly/fig4.png")
|
|
72
75
|
|
|
73
|
-
def
|
|
74
|
-
|
|
76
|
+
def test_empty_trace():
|
|
77
|
+
with pytest.warns(UserWarning, match="Adding empty trace."):
|
|
78
|
+
assert_equality(plot_empty_trace(), os.path.join(this_dir, test_name, test_name + "_5_reference.tex"))
|
|
@@ -2,6 +2,7 @@ import plotly.express as px
|
|
|
2
2
|
import plotly.graph_objects as go
|
|
3
3
|
import numpy as np
|
|
4
4
|
import os
|
|
5
|
+
from contextlib import nullcontext
|
|
5
6
|
from .helpers import assert_equality
|
|
6
7
|
import pathlib
|
|
7
8
|
import pytest
|
|
@@ -77,7 +78,12 @@ def test_3():
|
|
|
77
78
|
|
|
78
79
|
@pytest.mark.parametrize("histnorm", ["percent", "probability", "density", "probability density"])
|
|
79
80
|
def test_4(histnorm):
|
|
80
|
-
|
|
81
|
+
if histnorm in ["percent", "probability", "density"]:
|
|
82
|
+
context = pytest.warns(UserWarning, match=r"Sorry, I did not find an equivalent for histnorm='\w+' in TikZ*")
|
|
83
|
+
else:
|
|
84
|
+
context = nullcontext()
|
|
85
|
+
with context:
|
|
86
|
+
assert_equality(plot_4(histnorm), os.path.join(this_dir, test_name, test_name + "_4_reference.tex"))
|
|
81
87
|
|
|
82
88
|
def test_5():
|
|
83
89
|
assert_equality(plot_5(), os.path.join(this_dir, test_name, test_name + "_5_reference.tex"))
|
|
@@ -86,10 +92,11 @@ def test_6():
|
|
|
86
92
|
assert_equality(plot_6(), os.path.join(this_dir, test_name, test_name + "_6_reference.tex"))
|
|
87
93
|
|
|
88
94
|
def test_7():
|
|
89
|
-
|
|
95
|
+
with pytest.warns(UserWarning, match="To the best of our knowledge, other aggregate function than 'count' are not supported in pgfplots.*"):
|
|
96
|
+
assert_equality(plot_7(), os.path.join(this_dir, test_name, test_name + "_7_reference.tex"))
|
|
90
97
|
|
|
91
98
|
def test_8():
|
|
92
99
|
assert_equality(plot_8(), os.path.join(this_dir, test_name, test_name + "_8_reference.tex"))
|
|
93
100
|
|
|
94
101
|
def test_9():
|
|
95
|
-
assert_equality(plot_9(), os.path.join(this_dir, test_name, test_name + "_9_reference.tex"))
|
|
102
|
+
assert_equality(plot_9(), os.path.join(this_dir, test_name, test_name + "_9_reference.tex"))
|
|
@@ -3,6 +3,7 @@ import plotly.graph_objects as go
|
|
|
3
3
|
import pytest
|
|
4
4
|
import numpy as np
|
|
5
5
|
import os
|
|
6
|
+
from contextlib import nullcontext
|
|
6
7
|
from .helpers import assert_equality
|
|
7
8
|
import pathlib
|
|
8
9
|
|
|
@@ -96,7 +97,12 @@ def plot_with_angle():
|
|
|
96
97
|
|
|
97
98
|
@pytest.mark.parametrize("symbol", ["circle", 0, "0", "circle-dot"])
|
|
98
99
|
def test_1(symbol):
|
|
99
|
-
|
|
100
|
+
if symbol == "circle-dot":
|
|
101
|
+
context = pytest.warns(UserWarning, match=r"Dotted markers are not supported \(yet\), the symbol without dot will be used instead.")
|
|
102
|
+
else:
|
|
103
|
+
context = nullcontext()
|
|
104
|
+
with context:
|
|
105
|
+
assert_equality(plot_1(symbol), os.path.join(this_dir, test_name, test_name + "_1_reference.tex"))
|
|
100
106
|
|
|
101
107
|
def test_2():
|
|
102
108
|
assert_equality(plot_2(), os.path.join(this_dir, test_name, test_name + "_2_reference.tex"))
|
|
@@ -5,6 +5,7 @@ import os, pathlib
|
|
|
5
5
|
import plotly.express as px
|
|
6
6
|
import plotly.graph_objects as go
|
|
7
7
|
import pandas as pd
|
|
8
|
+
import pytest
|
|
8
9
|
from .helpers import assert_equality
|
|
9
10
|
|
|
10
11
|
this_dir = pathlib.Path(__file__).resolve().parent
|
|
@@ -275,4 +276,5 @@ def test_polar_1():
|
|
|
275
276
|
assert_equality(fig_polar_1(), os.path.join(this_dir, test_name, test_name + "_1_reference.tex"))
|
|
276
277
|
|
|
277
278
|
def test_polar_matplotlib():
|
|
278
|
-
|
|
279
|
+
with pytest.warns(UserWarning, match="Trace type barpolar is not supported yet"):
|
|
280
|
+
assert_equality(fig_polar_matplotlib(), os.path.join(this_dir, "empty_plot.tex"))
|
|
@@ -2,6 +2,7 @@ import plotly.express as px
|
|
|
2
2
|
import plotly.graph_objects as go
|
|
3
3
|
import numpy as np
|
|
4
4
|
import os
|
|
5
|
+
from contextlib import nullcontext
|
|
5
6
|
from .helpers import assert_equality
|
|
6
7
|
import pathlib
|
|
7
8
|
import pytest
|
|
@@ -220,9 +221,6 @@ def test_2():
|
|
|
220
221
|
def test_tranparent_color():
|
|
221
222
|
assert_equality(plot_transparent_color(), os.path.join(this_dir, test_name, test_name + "_transparent_color_reference.tex"))
|
|
222
223
|
|
|
223
|
-
# def test_tranparent_color_rgba():
|
|
224
|
-
# assert_equality(plot_transparent_color_rgba(), os.path.join(this_dir, test_name, test_name + "_transparent_color_rgba_reference.tex"))
|
|
225
|
-
|
|
226
224
|
def test_3():
|
|
227
225
|
assert_equality(plot_3(), os.path.join(this_dir, test_name, test_name + "_3_reference.tex"))
|
|
228
226
|
|
|
@@ -230,14 +228,18 @@ def test_4():
|
|
|
230
228
|
assert_equality(plot_4(), os.path.join(this_dir, test_name, test_name + "_4_reference.tex"))
|
|
231
229
|
|
|
232
230
|
def test_5():
|
|
233
|
-
|
|
231
|
+
with pytest.warns(UserWarning, match="Assuming this is a date*"):
|
|
232
|
+
assert_equality(plot_5(), os.path.join(this_dir, test_name, test_name + "_5_reference.tex"))
|
|
234
233
|
|
|
235
234
|
@pytest.mark.parametrize("x, y", [(True, True), (True, False), (False, True)])
|
|
236
235
|
def test_6(x, y):
|
|
237
|
-
|
|
236
|
+
context = pytest.warns(UserWarning, match="Adding empty trace.") if x and y else nullcontext()
|
|
237
|
+
with context:
|
|
238
|
+
assert_equality(plot_6(x, y), os.path.join(this_dir, test_name, test_name + f"_6_{x}_{y}_reference.tex"))
|
|
238
239
|
|
|
239
240
|
def test_7():
|
|
240
|
-
|
|
241
|
+
with pytest.warns(UserWarning, match="Assuming data January is a month*"):
|
|
242
|
+
assert_equality(plot_7(), os.path.join(this_dir, test_name, test_name + "_7_reference.tex"))
|
|
241
243
|
|
|
242
244
|
def test_8():
|
|
243
245
|
assert_equality(plot_8(), os.path.join(this_dir, test_name, test_name + "_8_reference.tex"))
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Test of 3D scatter plots https://plotly.com/python/3d-scatter-plots/
|
|
3
3
|
"""
|
|
4
4
|
import os, pathlib
|
|
5
|
+
from contextlib import nullcontext
|
|
5
6
|
import plotly.express as px
|
|
6
7
|
import plotly.graph_objects as go
|
|
7
8
|
import numpy as np
|
|
@@ -88,7 +89,13 @@ def test_scatter_3d_1():
|
|
|
88
89
|
|
|
89
90
|
@pytest.mark.parametrize("mode", ["markers", "markers+lines", "lines"])
|
|
90
91
|
def test_scatter_3d_2(mode):
|
|
91
|
-
|
|
92
|
+
if "markers" in mode:
|
|
93
|
+
context = pytest.warns(UserWarning, match="Color from data is not supported yet*")
|
|
94
|
+
# context = nullcontext()
|
|
95
|
+
else:
|
|
96
|
+
context = nullcontext()
|
|
97
|
+
with context:
|
|
98
|
+
assert_equality(plot_scatter_3d_2(mode), os.path.join(this_dir, test_name, test_name + f"_2_{mode}_reference.tex"))
|
|
92
99
|
|
|
93
100
|
def test_scatter_3d_3():
|
|
94
101
|
assert_equality(plot_scatter_3d_3(), os.path.join(this_dir, test_name, test_name + "_3_reference.tex"))
|
|
@@ -97,4 +104,5 @@ def test_scatter_3d_view():
|
|
|
97
104
|
assert_equality(plot_scatter_3d_view(), os.path.join(this_dir, test_name, test_name + "_view_reference.tex"))
|
|
98
105
|
|
|
99
106
|
def test_scatter_3d_empty():
|
|
100
|
-
|
|
107
|
+
with pytest.warns(UserWarning, match="Adding empty 3D trace."):
|
|
108
|
+
assert_equality(plot_scatter_3d_empty(), os.path.join(this_dir, test_name, test_name + "_empty_reference.tex"))
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
In this file are present the test of some very specific usage case, that should occur very rarely.
|
|
3
3
|
"""
|
|
4
4
|
import os, pathlib
|
|
5
|
-
import
|
|
5
|
+
import pytest
|
|
6
6
|
import plotly.graph_objects as go
|
|
7
|
+
import plotly.express as px
|
|
7
8
|
from .helpers import assert_equality
|
|
8
9
|
|
|
9
10
|
this_dir = pathlib.Path(__file__).resolve().parent
|
|
@@ -29,24 +30,27 @@ def plot_sanitized_text():
|
|
|
29
30
|
|
|
30
31
|
return fig
|
|
31
32
|
|
|
32
|
-
def plot_transparent_background():
|
|
33
|
-
# TODO: move it into test_color (when created)
|
|
34
|
-
fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16])
|
|
35
|
-
fig.update_layout(plot_bgcolor='rgba(255, 182, 193, .5)')
|
|
36
33
|
|
|
37
|
-
return fig
|
|
38
34
|
|
|
39
35
|
def plot_empty_figure():
|
|
40
36
|
fig = go.Figure()
|
|
41
|
-
fig.show()
|
|
42
37
|
return fig
|
|
43
38
|
|
|
39
|
+
def plot_empty_histogram():
|
|
40
|
+
# Normally user shouldn't create this kind on figure, but we never know !
|
|
41
|
+
fig = px.histogram(x=[1])
|
|
42
|
+
fig.data[0].x = None
|
|
43
|
+
return fig
|
|
44
44
|
|
|
45
|
-
def test_sanitized_text():
|
|
46
|
-
assert_equality(plot_sanitized_text(), os.path.join(this_dir, test_name, test_name + "_sanitized_text_reference.tex"))
|
|
47
45
|
|
|
48
|
-
def
|
|
49
|
-
|
|
46
|
+
def test_sanitized_text():
|
|
47
|
+
with pytest.warns(UserWarning, match="Character .+ has been replaced by \"x[0-9a-f]+\" in output file"):
|
|
48
|
+
assert_equality(plot_sanitized_text(), os.path.join(this_dir, test_name, test_name + "_sanitized_text_reference.tex"))
|
|
50
49
|
|
|
51
50
|
def test_empty_figure():
|
|
52
|
-
|
|
51
|
+
with pytest.warns(UserWarning, match="No data in figure."):
|
|
52
|
+
assert_equality(plot_empty_figure(), os.path.join(this_dir, "empty_plot.tex"))
|
|
53
|
+
|
|
54
|
+
def test_empty_histogram():
|
|
55
|
+
with pytest.warns(UserWarning, match="Empty histogram.*"):
|
|
56
|
+
assert_equality(plot_empty_histogram(), os.path.join(this_dir, test_name, test_name + "_empty_histogram_reference.tex"))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|