diff --git a/pyproject.toml b/pyproject.toml index f1ee514f..09d1b050 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,11 @@ dependencies = [ "webcolors", ] +[project.optional-dependencies] +dev = [ + "seaborn" +] + [project.urls] Code = "https://github.com/nschloe/tikzplotlib" Issues = "https://github.com/nschloe/tikzplotlib/issues" diff --git a/src/tikzplotlib/_path.py b/src/tikzplotlib/_path.py index 11381d59..5fc858f8 100644 --- a/src/tikzplotlib/_path.py +++ b/src/tikzplotlib/_path.py @@ -194,21 +194,25 @@ def draw_pathcollection(data, obj): ls = None if add_individual_color_code: - draw_options.extend( - [ - "scatter", - "visualization depends on={value \\thisrow{draw} \\as \\drawcolor}", - "visualization depends on={value \\thisrow{fill} \\as \\fillcolor}", - "scatter/@pre marker code/.code={%\n" - + " \\expanded{%\n" - + " \\noexpand\\definecolor{thispointdrawcolor}{RGB}{\\drawcolor}%\n" - + " \\noexpand\\definecolor{thispointfillcolor}{RGB}{\\fillcolor}%\n" - + " }%\n" - + " \\scope[draw=thispointdrawcolor, fill=thispointfillcolor]%\n" - + "}", - "scatter/@post marker code/.code={%\n \\endscope\n}", - ] - ) + draw_options.append("scatter") + if "draw" in labels or "fill" in labels: + if "draw" in labels: + draw_options.append("visualization depends on={value \\thisrow{draw} \\as \\drawcolor}") + if "fill" in labels: + draw_options.append("visualization depends on={value \\thisrow{fill} \\as \\fillcolor}") + scope_vars = ", ".join(f"{var}=thispoint{var}color" for var in ("draw", "fill") if var in labels) + draw_options.extend( + [ + "scatter/@pre marker code/.code={%\n" + + " \\expanded{%\n" + + (" \\noexpand\\definecolor{thispointdrawcolor}{RGB}{\\drawcolor}%\n" if "draw" in labels else "") + + (" \\noexpand\\definecolor{thispointfillcolor}{RGB}{\\fillcolor}%\n" if "fill" in labels else "") + + " }%\n" + + " \\scope[" + scope_vars + "]%\n" + + "}", + "scatter/@post marker code/.code={%\n \\endscope\n}", + ] + ) # "solution" from # @@ -249,7 +253,11 @@ def draw_pathcollection(data, obj): if legend_text is None and has_legend(obj.axes): draw_options.append("forget plot") + # track content that's been seen so we can de-duplicate (this is a bit of a kludge) + code_seen = set() + table_map = {} for path in obj.get_paths(): + cur_content = [] if is_contour: dd = path.vertices # https://matplotlib.org/stable/api/path_api.html @@ -289,7 +297,7 @@ def draw_pathcollection(data, obj): len_row = sum(len(item) for item in draw_options) j0, j1, j2 = ("", ", ", "") if len_row < 80 else ("\n ", ",\n ", "\n") do = f" [{j0}{{}}{j2}]".format(j1.join(draw_options)) if draw_options else "" - content.append(f"\\addplot{do}\n") + cur_content.append(f"\\addplot{do}\n") if data["externals search path"] is not None: esp = data["externals search path"] @@ -297,9 +305,9 @@ def draw_pathcollection(data, obj): if len(table_options) > 0: table_options_str = ", ".join(table_options) - content.append(f"table [{table_options_str}]{{") + cur_content.append(f"table [{table_options_str}]{{") else: - content.append("table{") + cur_content.append("table{") plot_table = [] plot_table.append(" ".join(labels) + "\n") @@ -307,16 +315,23 @@ def draw_pathcollection(data, obj): plot_table.append(" ".join(row) + "\n") if data["externalize tables"]: - filepath, rel_filepath = _files.new_filepath(data, "table", ".dat") - with open(filepath, "w") as f: - # No encoding handling required: plot_table is only ASCII - f.write("".join(plot_table)) - content.append(str(rel_filepath)) + plot_table_str = "".join(plot_table) + if plot_table_str not in table_map: + filepath, rel_filepath = _files.new_filepath(data, "table", ".dat") + with open(filepath, "w") as f: + # No encoding handling required: plot_table is only ASCII + f.write("".join(plot_table)) + table_map[plot_table_str] = str(rel_filepath) + cur_content.append(table_map[plot_table_str]) else: - content.append("%\n") - content.extend(plot_table) - - content.append("};\n") + cur_content.append("%\n") + cur_content.extend(plot_table) + + cur_content.append("};\n") + # very dumb kludge: skip duplicates + if tuple(cur_content) not in code_seen: + content.extend(cur_content) + code_seen.add(tuple(cur_content)) if legend_text is not None: content.append(f"\\addlegendentry{{{legend_text}}}\n") diff --git a/tests/test_seaborn_scatter.py b/tests/test_seaborn_scatter.py new file mode 100644 index 00000000..25f1cf5e --- /dev/null +++ b/tests/test_seaborn_scatter.py @@ -0,0 +1,18 @@ +def plot(): + import numpy as np + from matplotlib import pyplot as plt + import seaborn as sns + + np.random.seed(123) + data = np.random.rand(4, 64) + + fig, ax = plt.subplots() + sns.scatterplot({str(i): d for i, d in enumerate(data)}, ax=ax) + + return fig + + +def test(): + from .helpers import assert_equality + + assert_equality(plot, __file__[:-3] + "_reference.tex") diff --git a/tests/test_seaborn_scatter_reference.tex b/tests/test_seaborn_scatter_reference.tex new file mode 100644 index 00000000..2328bb49 --- /dev/null +++ b/tests/test_seaborn_scatter_reference.tex @@ -0,0 +1,303 @@ +\begin{tikzpicture} + +\definecolor{darkgray176}{RGB}{176,176,176} +\definecolor{lightgray204}{RGB}{204,204,204} + +\begin{axis}[ +legend cell align={left}, +legend style={ + fill opacity=0.8, + draw opacity=1, + text opacity=1, + at={(0.5,0.09)}, + anchor=south, + draw=lightgray204 +}, +tick align=outside, +tick pos=left, +x grid style={darkgray176}, +xmin=-3.15, xmax=66.15, +xtick style={color=black}, +y grid style={darkgray176}, +ymin=-0.046981849, ymax=1.0457562, +ytick style={color=black} +] +\addplot [ + draw=white, + forget plot, + mark=*, + only marks, + scatter, + scatter/@post marker code/.code={% + \endscope +}, + scatter/@pre marker code/.code={% + \expanded{% + \noexpand\definecolor{thispointfillcolor}{RGB}{\fillcolor}% + }% + \scope[fill=thispointfillcolor]% +}, + visualization depends on={value \thisrow{fill} \as \fillcolor} +] +table{% +x y fill +0 0.69646919 31,119,180 +1 0.28613933 31,119,180 +2 0.22685145 31,119,180 +3 0.55131477 31,119,180 +4 0.71946897 31,119,180 +5 0.42310646 31,119,180 +6 0.9807642 31,119,180 +7 0.68482974 31,119,180 +8 0.4809319 31,119,180 +9 0.39211752 31,119,180 +10 0.34317802 31,119,180 +11 0.72904971 31,119,180 +12 0.43857224 31,119,180 +13 0.059677897 31,119,180 +14 0.39804426 31,119,180 +15 0.73799541 31,119,180 +16 0.18249173 31,119,180 +17 0.17545176 31,119,180 +18 0.53155137 31,119,180 +19 0.53182759 31,119,180 +20 0.63440096 31,119,180 +21 0.84943179 31,119,180 +22 0.72445532 31,119,180 +23 0.61102351 31,119,180 +24 0.72244338 31,119,180 +25 0.32295891 31,119,180 +26 0.36178866 31,119,180 +27 0.22826323 31,119,180 +28 0.29371405 31,119,180 +29 0.63097612 31,119,180 +30 0.09210494 31,119,180 +31 0.43370117 31,119,180 +32 0.43086276 31,119,180 +33 0.4936851 31,119,180 +34 0.42583029 31,119,180 +35 0.31226122 31,119,180 +36 0.42635131 31,119,180 +37 0.89338916 31,119,180 +38 0.94416002 31,119,180 +39 0.50183668 31,119,180 +40 0.62395295 31,119,180 +41 0.1156184 31,119,180 +42 0.31728548 31,119,180 +43 0.41482621 31,119,180 +44 0.86630916 31,119,180 +45 0.25045537 31,119,180 +46 0.48303426 31,119,180 +47 0.98555979 31,119,180 +48 0.51948512 31,119,180 +49 0.61289453 31,119,180 +50 0.12062867 31,119,180 +51 0.8263408 31,119,180 +52 0.60306013 31,119,180 +53 0.54506801 31,119,180 +54 0.34276383 31,119,180 +55 0.30412079 31,119,180 +56 0.41702221 31,119,180 +57 0.68130077 31,119,180 +58 0.87545684 31,119,180 +59 0.51042234 31,119,180 +60 0.66931378 31,119,180 +61 0.58593655 31,119,180 +62 0.6249035 31,119,180 +63 0.67468905 31,119,180 +0 0.84234244 255,127,14 +1 0.083194988 255,127,14 +2 0.76368284 255,127,14 +3 0.24366637 255,127,14 +4 0.19422296 255,127,14 +5 0.57245696 255,127,14 +6 0.095712517 255,127,14 +7 0.88532683 255,127,14 +8 0.62724897 255,127,14 +9 0.72341636 255,127,14 +10 0.016129207 255,127,14 +11 0.59443188 255,127,14 +12 0.55678519 255,127,14 +13 0.15895964 255,127,14 +14 0.15307052 255,127,14 +15 0.69552953 255,127,14 +16 0.31876643 255,127,14 +17 0.6919703 255,127,14 +18 0.55438325 255,127,14 +19 0.38895057 255,127,14 +20 0.92513249 255,127,14 +21 0.84167 255,127,14 +22 0.35739757 255,127,14 +23 0.043591464 255,127,14 +24 0.30476807 255,127,14 +25 0.39818568 255,127,14 +26 0.70495883 255,127,14 +27 0.99535848 255,127,14 +28 0.35591487 255,127,14 +29 0.76254781 255,127,14 +30 0.59317692 255,127,14 +31 0.6917018 255,127,14 +32 0.15112745 255,127,14 +33 0.39887629 255,127,14 +34 0.2408559 255,127,14 +35 0.34345601 255,127,14 +36 0.51312815 255,127,14 +37 0.66662455 255,127,14 +38 0.10590849 255,127,14 +39 0.13089495 255,127,14 +40 0.32198061 255,127,14 +41 0.66156434 255,127,14 +42 0.84650623 255,127,14 +43 0.55325734 255,127,14 +44 0.85445249 255,127,14 +45 0.38483781 255,127,14 +46 0.3167879 255,127,14 +47 0.35426468 255,127,14 +48 0.17108183 255,127,14 +49 0.82911263 255,127,14 +50 0.33867085 255,127,14 +51 0.55237008 255,127,14 +52 0.57855147 255,127,14 +53 0.52153306 255,127,14 +54 0.0026880646 255,127,14 +55 0.98834542 255,127,14 +56 0.90534158 255,127,14 +57 0.20763586 255,127,14 +58 0.29248941 255,127,14 +59 0.52001015 255,127,14 +60 0.90191137 255,127,14 +61 0.98363088 255,127,14 +62 0.25754206 255,127,14 +63 0.56435904 255,127,14 +0 0.80696868 44,160,44 +1 0.39437005 44,160,44 +2 0.73107304 44,160,44 +3 0.16106901 44,160,44 +4 0.60069857 44,160,44 +5 0.86586446 44,160,44 +6 0.98352161 44,160,44 +7 0.07936579 44,160,44 +8 0.42834727 44,160,44 +9 0.20454286 44,160,44 +10 0.45063649 44,160,44 +11 0.54776357 44,160,44 +12 0.09332671 44,160,44 +13 0.29686078 44,160,44 +14 0.92758424 44,160,44 +15 0.56900373 44,160,44 +16 0.457412 44,160,44 +17 0.75352599 44,160,44 +18 0.74186215 44,160,44 +19 0.048579033 44,160,44 +20 0.7086974 44,160,44 +21 0.83924335 44,160,44 +22 0.16593788 44,160,44 +23 0.78099794 44,160,44 +24 0.28653662 44,160,44 +25 0.30646975 44,160,44 +26 0.66526147 44,160,44 +27 0.11139217 44,160,44 +28 0.66487245 44,160,44 +29 0.88785679 44,160,44 +30 0.69631127 44,160,44 +31 0.44032788 44,160,44 +32 0.43821438 44,160,44 +33 0.7650961 44,160,44 +34 0.565642 44,160,44 +35 0.084904163 44,160,44 +36 0.58267109 44,160,44 +37 0.8148437 44,160,44 +38 0.33706638 44,160,44 +39 0.92757658 44,160,44 +40 0.750717 44,160,44 +41 0.57406383 44,160,44 +42 0.75164399 44,160,44 +43 0.079148961 44,160,44 +44 0.85938908 44,160,44 +45 0.82150411 44,160,44 +46 0.90987166 44,160,44 +47 0.1286312 44,160,44 +48 0.081780087 44,160,44 +49 0.13841557 44,160,44 +50 0.39937871 44,160,44 +51 0.42430686 44,160,44 +52 0.56221838 44,160,44 +53 0.12224355 44,160,44 +54 0.2013995 44,160,44 +55 0.81164435 44,160,44 +56 0.46798757 44,160,44 +57 0.80793821 44,160,44 +58 0.0074263785 44,160,44 +59 0.55159273 44,160,44 +60 0.93193215 44,160,44 +61 0.58217546 44,160,44 +62 0.20609573 44,160,44 +63 0.71775756 44,160,44 +0 0.37898585 214,39,40 +1 0.66838395 214,39,40 +2 0.029319723 214,39,40 +3 0.63590036 214,39,40 +4 0.032197935 214,39,40 +5 0.74478066 214,39,40 +6 0.472913 214,39,40 +7 0.12175436 214,39,40 +8 0.54263593 214,39,40 +9 0.066774443 214,39,40 +10 0.65336487 214,39,40 +11 0.99608633 214,39,40 +12 0.76939734 214,39,40 +13 0.57377411 214,39,40 +14 0.10263526 214,39,40 +15 0.69983407 214,39,40 +16 0.66116787 214,39,40 +17 0.049097131 214,39,40 +18 0.7922993 214,39,40 +19 0.51871659 214,39,40 +20 0.42586769 214,39,40 +21 0.78818717 214,39,40 +22 0.41156922 214,39,40 +23 0.48102628 214,39,40 +24 0.18162884 214,39,40 +25 0.3213189 214,39,40 +26 0.845533 214,39,40 +27 0.18690375 214,39,40 +28 0.41729106 214,39,40 +29 0.98903451 214,39,40 +30 0.23659981 214,39,40 +31 0.91683233 214,39,40 +32 0.91839747 214,39,40 +33 0.091296342 214,39,40 +34 0.46365272 214,39,40 +35 0.50221634 214,39,40 +36 0.31366895 214,39,40 +37 0.047339537 214,39,40 +38 0.24168564 214,39,40 +39 0.095529642 214,39,40 +40 0.23824991 214,39,40 +41 0.80779109 214,39,40 +42 0.89497829 214,39,40 +43 0.043222892 214,39,40 +44 0.30194684 214,39,40 +45 0.9805822 214,39,40 +46 0.53950482 214,39,40 +47 0.62630936 214,39,40 +48 0.0055454084 214,39,40 +49 0.48490944 214,39,40 +50 0.98832853 214,39,40 +51 0.37518553 214,39,40 +52 0.097038159 214,39,40 +53 0.46190876 214,39,40 +54 0.96300447 214,39,40 +55 0.34183061 214,39,40 +56 0.79892273 214,39,40 +57 0.79884633 214,39,40 +58 0.2082483 214,39,40 +59 0.4433677 214,39,40 +60 0.71560128 214,39,40 +61 0.41051979 214,39,40 +62 0.19100696 214,39,40 +63 0.96749431 214,39,40 +}; +\end{axis} + +\end{tikzpicture}