diff --git a/README.md b/README.md index 5871867..d01aaf5 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,8 @@ tikzplotly.save("example.tex", fig) will result in the following ti*k*z code ```latex -\pgfplotstableread{data0 Australia New_Zealand +\pgfplotstableread{ +x Australia NewZealand 1952 69.12 69.39 1957 70.33 70.26 1962 70.93 71.24 @@ -51,7 +52,7 @@ will result in the following ti*k*z code 1997 78.83 77.55 2002 80.37 79.11 2007 81.235 80.204 -}\dataZ +}\dataA \begin{tikzpicture} @@ -60,11 +61,11 @@ will result in the following ti*k*z code \begin{axis}[ xlabel=year, -ylabel=lifeExp, +ylabel=lifeExp ] -\addplot+ [mark=*, solid, color=636efa, mark options={solid, draw=636efa}] table[y=Australia] {\dataZ}; +\addplot+ [mark=*, solid, color=636efa] table[y=Australia] {\dataA}; \addlegendentry{Australia} -\addplot+ [mark=*, solid, color=EF553B, mark options={solid, draw=EF553B}] table[y=New_Zealand] {\dataZ}; +\addplot+ [mark=*, solid, color=EF553B] table[y=NewZealand] {\dataA}; \addlegendentry{New Zealand} \end{axis} \end{tikzpicture} diff --git a/docs/assets/examples/bar.png b/docs/assets/examples/bar.png new file mode 100644 index 0000000..4ea90ce Binary files /dev/null and b/docs/assets/examples/bar.png differ diff --git a/docs/assets/examples/polar.png b/docs/assets/examples/polar.png new file mode 100644 index 0000000..b59fdb0 Binary files /dev/null and b/docs/assets/examples/polar.png differ diff --git a/docs/assets/examples/radar.png b/docs/assets/examples/radar.png new file mode 100644 index 0000000..5287681 Binary files /dev/null and b/docs/assets/examples/radar.png differ diff --git a/docs/assets/examples/scatter3d.png b/docs/assets/examples/scatter3d.png new file mode 100644 index 0000000..05a9266 Binary files /dev/null and b/docs/assets/examples/scatter3d.png differ diff --git a/docs/plot/NB.md b/docs/plot/NB.md index 1720774..272d631 100644 --- a/docs/plot/NB.md +++ b/docs/plot/NB.md @@ -6,3 +6,4 @@ We gather here some points that are different between a plotly figure and the co * By default, the colors or the markers are not the same in plotly and pgfplots. For instance, if nothing is specified, plotly will always use a dot marker, while pgfplot will change for each trace. * The order of displaying the traces may be unconsistent between plotly and pgfplots. For instance, for [this example](https://plotly.com/python/histograms/#several-histograms-for-the-different-values-of-one-column), the two traces are inverted. * The angle of rotation is different between Plotly and Ti*k*Z, but the function Plotly ↦ Ti*k*Z is not know at this current point. +* When tricky names are used in symbolic expression (such as names with a space within), the space is removed by tisk plotly (*e.g.* the text `United Kingdom` in Plotly will be exported as `UnitedKindgon` in Ti*k*Z), fill free to update the exported file to render the figure you wish! \ No newline at end of file diff --git a/docs/plot/supported.md b/docs/plot/supported.md index c7849f3..e903f01 100644 --- a/docs/plot/supported.md +++ b/docs/plot/supported.md @@ -62,3 +62,64 @@ The examples of the page [Histograms in Python](https://plotly.com/python/histog !!! Note - There may be issues when many histograms are plotted on the same figure... + + +## Bar plots + +Some examples of the page [Bar Charts in Python](https://plotly.com/python/bar-charts/) of Plotly documentation are supported (not stacked and aggregated bars). + +??? example "Bar plot" + ```python + wide_df = px.data.medals_wide() + fig = px.bar( + wide_df, + x="nation", + y=["gold", "silver", "bronze"], + color_discrete_map = {"gold": "gold", "silver": "silver", "bronze": "#cd7f32"} + ) + fig.update_traces(marker_line_width=2, marker_line_color="black") + tikzplotly.save("bar.tex", fig) + ``` + ![Bar plot Example](../assets/examples/bar.png) + + +## Polar and radar plots + +The examples from the pages [Polar Charts in Python](https://plotly.com/python/polar-chart/) and [Radar Charts in Python](https://plotly.com/python/radar-chart/) are supported. + + +??? example "Polar plot" + ```python + df = px.data.wind() + fig = px.line_polar(df, r="frequency", theta="direction", color="strength", line_close=True, + color_discrete_sequence=px.colors.sequential.Plasma_r, + template="plotly_dark",) + tikzploylt.save("polar.tex", fig) + ``` + ![Polar plot Example](../assets/examples/polar.png) + + +??? example "Radar plot" + ```python + df = pd.DataFrame(dict( + r=[1, 5, 2, 2, 3], + theta=['processing cost','mechanical properties','chemical stability', + 'thermal stability', 'device integration'])) + fig = px.line_polar(df, r='r', theta='theta', line_close=True) + tikzploylt.save("radar.tex", fig) + ``` + ![Radar plot Example](../assets/examples/radar.png) + + +## 3D scatter plots + +Examples from [3D Scatter Plots in Python ](https://plotly.com/python/3d-scatter-plots/) can be exported with tikzplotly. + + +??? example "3D scatter plot" + ```python + df = px.data.iris() + fig = px.scatter_3d(df, x='sepal_length', y='sepal_width', z='petal_width', color='species') + tikzploylt.save("scatter3d.tex", fig) + ``` + ![3D scatter plot Example](../assets/examples/scatter3d.png) diff --git a/src/tests/test_bars.py b/src/tests/test_bars.py new file mode 100644 index 0000000..bfecbcd --- /dev/null +++ b/src/tests/test_bars.py @@ -0,0 +1,310 @@ +# From https://plotly.com/python/bar-charts/ and https://plotly.com/python/horizontal-bar-charts/ +import plotly +import plotly.express as px +import pandas as pd +import plotly.graph_objects as go +from plotly.subplots import make_subplots + +import numpy as np +import tikzplotly +import os +from warnings import warn +from tikzplotly._tex import tex_create_document, tex_begin_environment, tex_end_environment, tex_end_all_environment + +def fig_vertical1(): + + data_canada = px.data.gapminder().query("country == 'Canada'") + fig = px.bar(data_canada, x='year', y='pop') + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig1.png")) + + return fig, "Bar chart with Plotly Express" + +def fig_vertical2(): + + long_df = px.data.medals_long() + + fig = px.bar(long_df, x="nation", y="count", color="medal", title="Long-Form Input") + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig2.png")) + + return fig, "Bar charts with Long Format Data" + +def fig_vertical3(): + + wide_df = px.data.medals_wide() + fig = px.bar( + wide_df, + x="nation", + y=["gold", "silver", "bronze"], + title="Wide-Form Input", + color_discrete_map={ + "gold": "gold", + "silver": "silver", + "bronze": "#cd7f32" + } + ) + fig.update_traces(marker_line_width=2, marker_line_color="black") + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig3.png")) + + return fig, "Bar charts with Wide Format Data" + +def fig_vertical5(): + + df = px.data.gapminder().query("country == 'Canada'") + fig = px.bar(df, x='year', y='pop', + hover_data=['lifeExp', 'gdpPercap'], color='lifeExp', + labels={'pop':'population of Canada'}, height=400) + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig5.png")) + + return fig, "Colored Bars" + +def fig_vertical6(): + + df = px.data.gapminder().query("continent == 'Oceania'") + fig = px.bar(df, x='year', y='pop', + hover_data=['lifeExp', 'gdpPercap'], color='country', + labels={'pop':'population of Canada'}, height=400) + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig5bis.png")) + + return fig, "Colored Bars" + +def fig_vertical7(): + + df = px.data.tips() + fig = px.bar(df, x="sex", y="total_bill", color='time') + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig6.png")) + + return fig, "Stacked vs Grouped Bars" + +def fig_vertical8(): + + df = px.data.tips() + fig = px.bar(df, x="sex", y="total_bill", + color='smoker', barmode='group', + height=400) + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig6bis.png")) + + return fig, "Stacked vs Grouped Bars" + +def fig_vertical9(): + + df = px.data.tips() + fig = px.histogram(df, x="sex", y="total_bill", + color='smoker', barmode='group', + height=400) + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig7.png")) + + return fig, "Aggregating into Single Colored Bars" + +def fig_vertical10(): + + df = px.data.tips() + fig = px.histogram(df, x="sex", y="total_bill", + color='smoker', barmode='group', + histfunc='avg', + height=400) + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig7bis.png")) + + return fig, "Aggregating into Single Colored Bars" + +def fig_vertical11(): + + df = px.data.medals_long() + + fig = px.bar(df, x="medal", y="count", color="nation", text_auto=True) + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig8.png")) + + return fig, "Bar Charts with Text" + +def fig_vertical12(): + + df = px.data.medals_long() + + fig = px.bar(df, x="medal", y="count", color="nation", text="nation") + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig8bis.png")) + + return fig, "Bar Charts with Text" + +def fig_vertical13(): + + df = px.data.gapminder().query("continent == 'Europe' and year == 2007 and pop > 2.e6") + fig = px.bar(df, y='pop', x='country', text_auto='.2s', + title="Default: various text sizes, positions and angles") + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig8ter.png")) + + return fig, "Bar Charts with Text" + +def fig_vertical14(): + + df = px.data.gapminder().query("continent == 'Europe' and year == 2007 and pop > 2.e6") + fig = px.bar(df, y='pop', x='country', text_auto='.2s', + title="Controlled text sizes, positions and angles") + fig.update_traces(textfont_size=12, textangle=0, textposition="outside", cliponaxis=False) + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig8quater.png")) + + return fig, "Bar Charts with Text" + +def fig_vertical15(): + + df = px.data.medals_long() + + fig = px.bar(df, x="medal", y="count", color="nation", + pattern_shape="nation", pattern_shape_sequence=[".", "x", "+"]) + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig9.png")) + + return fig, "Pattern fills" + +def fig_vertical16(): + animals=['giraffes', 'orangutans', 'monkeys'] + + fig = go.Figure([go.Bar(x=animals, y=[20, 14, 23])]) + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig10.png")) + + return fig, "Basic Bar Charts with plotly graph objects" + +def fig_vertical17(): + animals=['giraffes', 'orangutans', 'monkeys'] + + fig = go.Figure(data=[ + go.Bar(name='SF Zoo', x=animals, y=[20, 14, 23]), + go.Bar(name='LA Zoo', x=animals, y=[12, 18, 29]) + ]) + # Change the bar mode + fig.update_layout(barmode='group') + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig11.png")) + + return fig, "Grouped Bar Chart" + +def fig_vertical18(): + animals=['giraffes', 'orangutans', 'monkeys'] + + fig = go.Figure(data=[ + go.Bar(name='SF Zoo', x=animals, y=[20, 14, 23]), + go.Bar(name='LA Zoo', x=animals, y=[12, 18, 29]) + ]) + # Change the bar mode + fig.update_layout(barmode='stack') + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig12.png")) + + return fig, "Stacked Bar Chart" + +def fig_vertical19(): + x = [1, 2, 3, 4] + + fig = go.Figure() + fig.add_trace(go.Bar(x=x, y=[1, 4, 9, 16])) + fig.add_trace(go.Bar(x=x, y=[6, -8, -4.5, 8])) + fig.add_trace(go.Bar(x=x, y=[-15, -3, 4.5, -8])) + fig.add_trace(go.Bar(x=x, y=[-1, 3, -3, -4])) + + fig.update_layout(barmode='relative', title_text='Relative Barmode') + + # fig.show() + # fig.write_image(os.path.join(file_directory, "outputs", "test_bars", "fig13.png")) + + return fig, "Bar Chart with Relative Barmode" + +def fig_horizontal1(): + df = px.data.tips() + fig = px.bar(df, x="total_bill", y="day", orientation='h') + return fig, "Horizontal figure" + +def fig_horizontal2(): + fig = go.Figure(go.Bar( + x=[20, 14, 23], + y=['giraffes', 'orangutans', 'monkeys'], + orientation='h')) + return fig, "Basic Horizontal Bar Chart" + + +if __name__ == "__main__": + + print("Tikzploty : ", tikzplotly.__version__) + print("Plotly : ", plotly.__version__) + print("Test histograms") + + + file_directory = os.path.dirname(os.path.abspath(__file__)) + + functions = [ + ("vertical1", fig_vertical1), + ("vertical2", fig_vertical2), + ("vertical3", fig_vertical3), + ("vertical5", fig_vertical5), + ("vertical6", fig_vertical6), + ("vertical7", fig_vertical7), # Stacked bars are not supported yet. + ("vertical8", fig_vertical8), # Stacked bars are not supported yet. + ("vertical9", fig_vertical9), # Aggregated bars are not supported yet. + ("vertical10", fig_vertical10), # Aggregated bars are not supported yet. + ("vertical11", fig_vertical11), # Text template is not supported yet. + ("vertical12", fig_vertical12), # Text template is not supported yet. + ("vertical13", fig_vertical13), # Text template is not supported yet. + ("vertical14", fig_vertical14), # Text template is not supported yet. + ("vertical15", fig_vertical15), # Pattern fills are not supported yet. + ("vertical16", fig_vertical16), + ("vertical17", fig_vertical17), + ("vertical18", fig_vertical18), + ("vertical19", fig_vertical19), + ("horizontal1", fig_horizontal1), + ("horizontal2", fig_horizontal2), + ] + + main_tex_content = tex_create_document(options="twocolumn", compatibility="newest") + main_tex_content += "\\usepackage[left=1cm, right=1cm, top=1cm, bottom=1cm]{geometry}\n" + main_tex_content += "\n" + stack_env = [] + main_tex_content += tex_begin_environment("document", stack_env) + '\n' + + output_path = os.path.join(file_directory, "outputs", "test_bars") + if not os.path.exists(output_path): + os.makedirs(output_path) + + for i, f in functions: + print(f"Figure {i}") + fig, title = f() + data = fig.data + save_path = os.path.join(file_directory, "outputs", "test_bars", "fig{}.tex".format(i)) + tikzplotly.save(save_path, fig) + main_tex_content += tex_begin_environment("figure", stack_env) + main_tex_content += " \\input{fig" + str(i) + ".tex}\n" + main_tex_content += " \\caption{" + title + "}\n" + main_tex_content += tex_end_environment(stack_env) + '\n' + + main_tex_content += "\n" + tex_end_all_environment(stack_env) + + main_tex_path = os.path.join(file_directory, "outputs", "test_bars", "main.tex") + print("Save main tex file : ", main_tex_path) + with open(main_tex_path, "w") as f: + f.write(main_tex_content) diff --git a/src/tests/test_line_charts.py b/src/tests/test_line_charts.py index 6a56507..e71abb2 100644 --- a/src/tests/test_line_charts.py +++ b/src/tests/test_line_charts.py @@ -394,6 +394,29 @@ def fig18(): fig.update_xaxes(minor=dict(ticks="inside", ticklen=6, showgrid=True)) return fig, "Log scale with range and minor ticks" +def fig19(): + df = pd.DataFrame(dict( + x = ["A et B", "B", "C", "D"], + y = [1, 2, 3, 4], + )) + fig = px.line(df, x="x", y="y", title="symbolic x coords") + return fig, "Line Charts with symbolic x coords" + +def fig20(): + df = pd.DataFrame(dict( + x = [1, 2, 3, 4], + y = ["A", "B", "C", "D"], + )) + fig = px.line(df, x="x", y="y", title="symbolic y coords") + return fig, "Line Charts with symbolic y coords" + + +def fig21(x=True, y=False): + fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16]) + if x: fig.data[0].x = None + if y: fig.data[0].y = None + return fig, "empty fig" + if __name__ == "__main__": print("Tikzploty : ", tikzplotly.__version__) @@ -414,12 +437,15 @@ def fig18(): ("9", fig9), ("10", fig10), ("11", fig11), - # ("12", fig12), + ("12", fig12), ("14", fig14), ("15", fig15), ("16", fig16), ("17", fig17), ("18", fig18), + ("19", fig19), + ("20", fig20), + ("21", fig21), ] main_tex_content = tex_create_document(options="twocolumn", compatibility="newest") diff --git a/src/tests/test_markers.py b/src/tests/test_markers.py index 54d5205..b98c9ec 100644 --- a/src/tests/test_markers.py +++ b/src/tests/test_markers.py @@ -227,7 +227,7 @@ def fig3ter(): def fig4(): warn("This example is not exactly the one online, but has been changed as this kind of data is not yet supported.") SymbolValidator = ValidatorCache.get_validator("scatter.marker", "symbol") - raw_symbols = SymbolValidator().values + raw_symbols = SymbolValidator.values namestems = [] namevariants = [] symbols = [] diff --git a/src/tests/test_polar.py b/src/tests/test_polar.py new file mode 100644 index 0000000..b715474 --- /dev/null +++ b/src/tests/test_polar.py @@ -0,0 +1,656 @@ +# From https://plotly.com/python/radar-chart/ +# From https://plotly.com/python/polar-chart/ +import os +import tikzplotly + +from tikzplotly._tex import tex_create_document, tex_begin_environment, tex_end_environment, tex_end_all_environment + +import plotly +import plotly.express as px +import pandas as pd +import plotly.graph_objects as go +import numpy as np + +def fig_radar1(): + df = pd.DataFrame(dict( + r=[1, 5, 2, 2, 3], + theta=['processing cost','mechanical properties','chemical stability', + 'thermal stability', 'device integration'])) + fig = px.line_polar(df, r='r', theta='theta', line_close=True) + + # fig.show() + return fig, "Radar Chart with Plotly Express" + +def fig_radar2(): + df = pd.DataFrame(dict( + r=[1, 5, 2, 2, 3], + theta=['processing cost','mechanical properties','chemical stability', + 'thermal stability', 'device integration'])) + fig = px.line_polar(df, r='r', theta='theta', line_close=True) + fig.update_traces(fill='toself') + + # fig.show() + return fig, "Filled Radar Chart with Plotly Express" + +def fig_radar3(): + fig = go.Figure(data=go.Scatterpolar( + r=[1, 5, 2, 2, 3], + theta=['processing cost','mechanical properties','chemical stability', 'thermal stability', + 'device integration'], + fill='toself' + )) + + fig.update_layout( + polar=dict( + radialaxis=dict( + visible=True + ), + ), + showlegend=False + ) + + # fig.show() + return fig, "Basic Filled Radar Chart with go.Scatterpolar" + +def fig_radar4(): + categories = ['processing cost','mechanical properties','chemical stability', + 'thermal stability', 'device integration'] + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + r=[1, 5, 2, 2, 3], + theta=categories, + fill='toself', + name='Product A' + )) + fig.add_trace(go.Scatterpolar( + r=[4, 3, 2.5, 1, 2], + theta=categories, + fill='toself', + name='Product B' + )) + + fig.update_layout( + polar=dict( + radialaxis=dict( + visible=True, + range=[0, 5] + )), + showlegend=False + ) + + # fig.show() + return fig, "Multiple Trace Radar Chart" + + +def fig_polar1(): + + df = px.data.wind() + fig = px.scatter_polar(df, r="frequency", theta="direction") + + # fig.show() + return fig, "Polar chart with Plotly Express" + +def fig_polar2(): + df = px.data.wind() + fig = px.scatter_polar(df, r="frequency", theta="direction", + color="strength", symbol="strength", size="frequency", + color_discrete_sequence=px.colors.sequential.Plasma_r) + + # fig.show() + return fig, "Polar chart with Plotly Express" + +def fig_polar3(): + df = px.data.wind() + fig = px.line_polar(df, r="frequency", theta="direction", color="strength", line_close=True, + color_discrete_sequence=px.colors.sequential.Plasma_r, + template="plotly_dark",) + + # fig.show() + return fig, "Polar chart with Plotly Express" + +def fig_polar4(): + fig = px.scatter_polar(r=range(0,90,10), theta=range(0,90,10), + range_theta=[0,90], start_angle=0, direction="counterclockwise") + + # fig.show() + return fig, "Range polar chart with Plotly Express" + +def fig_polar5(): + fig = go.Figure(data= + go.Scatterpolar( + r = [0.5,1,2,2.5,3,4], + theta = [35,70,120,155,205,240], + mode = 'markers', + )) + + fig.update_layout(showlegend=False) + + # fig.show() + return fig, "Basic Polar Chart" + +def fig_polar6(): + df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/polar_dataset.csv") + + fig = go.Figure() + fig.add_trace(go.Scatterpolar( + r = df['x1'], + theta = df['y'], + mode = 'lines', + name = 'Figure 8', + line_color = 'peru' + )) + fig.add_trace(go.Scatterpolar( + r = df['x2'], + theta = df['y'], + mode = 'lines', + name = 'Cardioid', + line_color = 'darkviolet' + )) + fig.add_trace(go.Scatterpolar( + r = df['x3'], + theta = df['y'], + mode = 'lines', + name = 'Hypercardioid', + line_color = 'deepskyblue' + )) + + + fig.update_layout( + title = 'Basic Polar Chart', + showlegend = False + ) + + # fig.show() + return fig, "Mic Patterns" + +def fig_polar7(): + fig = go.Figure(go.Barpolar( + r=[3.5, 1.5, 2.5, 4.5, 4.5, 4, 3], + theta=[65, 15, 210, 110, 312.5, 180, 270], + width=[20,15,10,20,15,30,15,], + marker_color=["#E4FF87", '#709BFF', '#709BFF', '#FFAA70', '#FFAA70', '#FFDF70', '#B6FFB4'], + marker_line_color="black", + marker_line_width=2, + opacity=0.8 + )) + + fig.update_layout( + template=None, + polar = dict( + radialaxis = dict(range=[0, 5], showticklabels=False, ticks=''), + angularaxis = dict(showticklabels=False, ticks='') + ) + ) + + # fig.show() + return fig, "Polar Bar Chart" + +def fig_polar8a(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + name = "angular categories", + r = [5, 4, 2, 4, 5], + theta = ["a", "b", "c", "d", "a"], + )) + + fig.update_traces(fill='toself') + + fig.update_layout( + polar = dict( + radialaxis_angle = -45, + angularaxis = dict( + direction = "clockwise", + period = 6) + ), + ) + + # fig.show() + + return fig, "Categorical Polar Chart" + +def fig_polar8b(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + name = "radial categories", + r = ["a", "b", "c", "d", "b", "f", "a"], + theta = [1, 4, 2, 1.5, 1.5, 6, 5], + thetaunit = "radians", + )) + + fig.update_traces(fill='toself') + + fig.update_layout( + polar = dict( + radialaxis = dict( + angle = 180, + tickangle = -180 # so that tick labels are not upside down + ) + ) + ) + + # fig.show() + + return fig, "Categorical Polar Chart" + +def fig_polar8c(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + name = "angular categories (w/ categoryarray)", + r = [5, 4, 2, 4, 5], + theta = ["a", "b", "c", "d", "a"], + )) + + fig.update_traces(fill='toself') + + fig.update_layout( + polar = dict( + sector = [80, 400], + radialaxis_angle = -45, + angularaxis_categoryarray = ["d", "a", "c", "b"] + ), + ) + + # fig.show() + + return fig, "Categorical Polar Chart" + +def fig_polar8d(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + name = "radial categories (w/ category descending)", + r = ["a", "b", "c", "d", "b", "f", "a", "a"], + theta = [45, 90, 180, 200, 300, 15, 20, 45], + )) + + fig.update_traces(fill='toself') + fig.update_layout( + polar = dict( + radialaxis_categoryorder = "category descending", + angularaxis = dict( + thetaunit = "radians", + dtick = 0.3141592653589793 + )) + ) + + # fig.show() + return fig, "Categorical Polar Chart" + +def fig_polar9a(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar()) + fig.update_traces(mode = "lines+markers", + r = [1,2,3,4,5], + theta = [0,90,180,360,0], + line_color = "magenta", + marker = dict( + color = "royalblue", + symbol = "square", + size = 8 + )) + + fig.update_layout( + showlegend = False, + polar = dict( + sector = [150,210], + )) + + # fig.show() + return fig, "Polar Chart Sector" + +def fig_polar9b(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar()) + fig.update_traces(mode = "lines+markers", + r = [1,2,3,4,5], + theta = [0,90,180,360,0], + line_color = "magenta", + marker = dict( + color = "royalblue", + symbol = "square", + size = 8 + )) + + fig.update_layout( + showlegend = False, + ) + + # fig.show() + return fig, "Polar Chart Sector" + +def fig_polar10a(): + + fig = go.Figure() + + r = [1,2,3,4,5] + theta = [0,90,180,360,0] + + fig.add_trace(go.Scatterpolar()) + fig.update_traces(r= r, theta=theta, + mode="lines+markers", line_color='indianred', + marker=dict(color='lightslategray', size=8, symbol='square')) + fig.update_layout( + showlegend = False, + polar = dict( + radialaxis_tickfont_size = 8, + angularaxis = dict( + tickfont_size=8, + rotation=90, # start position of angular axis + direction="counterclockwise" + ) + ) + ) + + # fig.show() + return fig, "Polar Chart Directions" + +def fig_polar10b(): + + fig = go.Figure() + + r = [1,2,3,4,5] + theta = [0,90,180,360,0] + + fig.add_trace(go.Scatterpolar()) + fig.update_traces(r= r, theta=theta, + mode="lines+markers", line_color='indianred', + marker=dict(color='lightslategray', size=8, symbol='square')) + fig.update_layout( + showlegend = False, + polar = dict( + radialaxis_tickfont_size = 8, + angularaxis = dict( + tickfont_size = 8, + rotation = 90, + direction = "clockwise" + ) + ) + ) + + # fig.show() + return fig, "Polar Chart Directions" + +def fig_polar10c(): + + fig = go.Figure() + + r = [1,2,3,4,5] + theta = [0,90,180,360,0] + + fig.add_trace(go.Scatterpolar()) + fig.update_traces(r= r, theta=theta, + mode="lines+markers", line_color='indianred', + marker=dict(color='lightslategray', size=8, symbol='square')) + fig.update_layout( + showlegend = False, + polar = dict( + radialaxis_tickfont_size = 8, + angularaxis = dict( + tickfont_size=8, + rotation=180, # start position of angular axis + direction="counterclockwise" + ) + ) + ) + + # fig.show() + return fig, "Polar Chart Directions" + +def fig_polar10d(): + + fig = go.Figure() + + r = [1,2,3,4,5] + theta = [0,90,180,360,0] + + fig.add_trace(go.Scatterpolar()) + fig.update_traces(r= r, theta=theta, + mode="lines+markers", line_color='indianred', + marker=dict(color='lightslategray', size=8, symbol='square')) + fig.update_layout( + showlegend = False, + polar = dict( + radialaxis_tickfont_size = 8, + angularaxis = dict( + tickfont_size = 8, + rotation = 180, + direction = "clockwise" + ) + ) + ) + + # fig.show() + return fig, "Polar Chart Directions" + +def fig_polar11(): + + df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/hobbs-pearson-trials.csv") + + fig = go.Figure() + + fig.add_trace(go.Scatterpolargl( + r = df.trial_1_r, + theta = df.trial_1_theta, + name = "Trial 1", + marker=dict(size=15, color="mediumseagreen") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_2_r, + theta = df.trial_2_theta, + name = "Trial 2", + marker=dict(size=20, color="darkorange") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_3_r, + theta = df.trial_3_theta, + name = "Trial 3", + marker=dict(size=12, color="mediumpurple") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_4_r, + theta = df.trial_4_theta, + name = "Trial 4", + marker=dict(size=22, color = "magenta") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_5_r, + theta = df.trial_5_theta, + name = "Trial 5", + marker=dict(size=19, color = "limegreen") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_6_r, + theta = df.trial_6_theta, + name = "Trial 6", + marker=dict(size=10, color = "gold") + )) + + # Common parameters for all traces + fig.update_traces(mode="markers", marker=dict(line_color='white', opacity=0.7)) + + fig.update_layout( + title = "Hobbs-Pearson Trials", + font_size = 15, + showlegend = False, + polar = dict( + bgcolor = "rgb(223, 223, 223)", + angularaxis = dict( + linewidth = 3, + showline=True, + linecolor='black' + ), + radialaxis = dict( + side = "counterclockwise", + showline = True, + linewidth = 2, + gridcolor = "white", + gridwidth = 2, + ) + ), + paper_bgcolor = "rgb(223, 223, 223)" + ) + + # print(f"fig = {fig}") + + # fig.show() + return fig, "Webgl Polar Chart" + +def fig_polar12a(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + r = [1, 2, 3], + theta = [50, 100, 200], + marker_symbol = "square" + )) + fig.add_trace(go.Scatterpolar( + r = [1, 2, 3], + theta = [1, 2, 3], + thetaunit = "radians" + )) + + fig.update_layout( + polar = dict( + radialaxis_range = [1, 4], + angularaxis_thetaunit = "radians" + ), + showlegend = False + ) + + # fig.show() + return fig, "Polar Chart Subplots" + +def fig_polar12b(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + r = ["a", "b", "c", "b"], + theta = ["D", "C", "B", "A"], + )) + + fig.update_layout( + showlegend = False + ) + # fig.show() + return fig, "Polar Chart Subplots" + +def fig_polar12c(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + r = [50, 300, 900], + theta = [0, 90, 180], + )) + + fig.update_layout( + polar = dict( + radialaxis = dict(type = "log", tickangle = 45), + sector = [0, 180] + ), + showlegend = False + ) + + # fig.show() + return fig, "Polar Chart Subplots" + +def fig_polar12d(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + mode = "lines", + r = [3, 3, 4, 3], + theta = [0, 45, 90, 270], + fill = "toself", + subplot = "polar4" + )) + + fig.update_layout( + polar = dict( + radialaxis = dict(visible = False, range = [0, 6]) + ), + showlegend = False + ) + + # fig.show() + return fig, "Polar Chart Subplots" + +if __name__ == "__main__": + + print("Tikzploty : ", tikzplotly.__version__) + print("Plotly : ", plotly.__version__) + print("Test polar/radar charts") + + file_directory = os.path.dirname(os.path.abspath(__file__)) + + functions = [ + ("radar1", fig_radar1), + ("radar2", fig_radar2), # Individual marker sizes in a trace are not supported yet + ("radar3", fig_radar3), + ("radar4", fig_radar4), + + ("polar1", fig_polar1), + ("polar2", fig_polar2), + ("polar3", fig_polar3), + ("polar4", fig_polar4), + ("polar5", fig_polar5), + ("polar6", fig_polar6), + ("polar7", fig_polar7), # Polar bar charts are not supported yet. + ("polar8a", fig_polar8a), + ("polar8b", fig_polar8b), + ("polar8c", fig_polar8c), + ("polar8d", fig_polar8d), + ("polar9a", fig_polar9a), + ("polar9b", fig_polar9b), + ("polar10a", fig_polar10a), + ("polar10b", fig_polar10b), + ("polar10c", fig_polar10c), + ("polar10d", fig_polar10d), + ("polar11", fig_polar11), # Webgl polar charts are treated as normal polar charts. + ("polar12a", fig_polar12a), # Radial axis range does not look the same with pgfplots. + ("polar12b", fig_polar12b), + ("polar12c", fig_polar12c), # Radial axis type log is not supported yet. + ("polar12d", fig_polar12d), + ] + + main_tex_content = tex_create_document(options="twocolumn", compatibility="newest") + main_tex_content += "\\usepackage[left=1cm, right=1cm, top=1cm, bottom=1cm]{geometry}\n" + main_tex_content += "\\usetikzlibrary{pgfplots.dateplot}\n" + main_tex_content += "\\usepgfplotslibrary{polar}\n" + main_tex_content += "\n" + stack_env = [] + main_tex_content += tex_begin_environment("document", stack_env) + '\n' + + for i, f in functions: + print(f"Figure {i}") + fig, title = f() + data = fig.data + save_path = os.path.join(file_directory, "outputs", "test_polar", "fig{}.tex".format(i)) + tikzplotly.save(save_path, fig) + main_tex_content += tex_begin_environment("figure", stack_env) + main_tex_content += " \\input{fig" + str(i) + ".tex}\n" + main_tex_content += " \\caption{" + title + "}\n" + main_tex_content += tex_end_environment(stack_env) + '\n' + + main_tex_content += "\n" + tex_end_all_environment(stack_env) + + main_tex_path = os.path.join(file_directory, "outputs", "test_polar", "main.tex") + print("Save main tex file : ", main_tex_path) + with open(main_tex_path, "w") as f: + f.write(main_tex_content) diff --git a/src/tests/test_scatter3d.py b/src/tests/test_scatter3d.py new file mode 100644 index 0000000..2c48a9d --- /dev/null +++ b/src/tests/test_scatter3d.py @@ -0,0 +1,138 @@ +# From https://plotly.com/python/3d-scatter-plots/ +import os +import tikzplotly + +from tikzplotly._tex import tex_create_document, tex_begin_environment, tex_end_environment, tex_end_all_environment + +import plotly +import plotly.express as px +import pandas as pd +import plotly.graph_objects as go +import numpy as np + +def fig1(): + df = px.data.iris() + fig = px.scatter_3d(df, x='sepal_length', y='sepal_width', z='petal_width', color='species') + # fig.show() + return fig, "3D scatter plot with Plotly Express" + +def fig2(): + df = px.data.iris() + fig = px.scatter_3d(df, x='sepal_length', y='sepal_width', z='petal_width', color='petal_length', symbol='species') + # fig.show() + return fig, "3D scatter plot with Plotly Express" + +def fig3(): + df = px.data.iris() + fig = px.scatter_3d(df, x='sepal_length', y='sepal_width', z='petal_width', + color='petal_length', size='petal_length', size_max=18, + symbol='species', opacity=0.7) + + # tight layout + fig.update_layout(margin=dict(l=0, r=0, b=0, t=0)) + # fig.show() + return fig, "Style 3d scatter plot" + +def fig4(): + df = px.data.iris() # replace with your own data source + low, high = 0, 2.5 + mask = (df.petal_width > low) & (df.petal_width < high) + fig = px.scatter_3d(df[mask], + x='sepal_length', y='sepal_width', z='petal_width', + color="species", hover_data=['petal_width']) + # fig.show() + return fig, "Style 3d scatter plot" + +def fig5(): + t = np.linspace(0, 10, 50) + x, y, z = np.cos(t), np.sin(t), t + fig = go.Figure(data=[go.Scatter3d(x=x, y=y, z=z, mode='markers')]) + # fig.show() + return fig, "Basic 3D Scatter Plot with go.Scatter3d" + +def fig6(): + t = np.linspace(0, 20, 100) + x, y, z = np.cos(t), np.sin(t), t + + fig = go.Figure(data=[go.Scatter3d( + x=x, + y=y, + z=z, + mode='markers', + marker=dict( + size=12, + color=z, # set color to an array/list of desired values + colorscale='Viridis', # choose a colorscale + opacity=0.8 + ) + )]) + + # tight layout + fig.update_layout(margin=dict(l=0, r=0, b=0, t=0)) + # fig.show() + return fig, "3D Scatter Plot with Colorscaling and Marker Styling" + +def fig7(): + fig = go.Figure(data=[go.Scatter3d( + x=[1, 2, 3], + y=[4, 5, 6], + z=[7, 8, 9], + mode='markers', + )]) + fig.update_layout( + scene=dict( + xaxis=dict(showgrid=True), + yaxis=dict(showgrid=True), + zaxis=dict(showgrid=True), + camera=dict( + eye=dict(x=1.5, y=1.5, z=0.5) + ) + ) + ) + # fig.show() + return fig, "3D plot with custom view" + + +if __name__ == "__main__": + + print("Tikzploty : ", tikzplotly.__version__) + print("Plotly : ", plotly.__version__) + print("Test scatter 3d charts") + + file_directory = os.path.dirname(os.path.abspath(__file__)) + + functions = [ + ("1", fig1), + ("2", fig2), + ("3", fig3), + ("4", fig4), + ("5", fig5), + ("6", fig6), + ("7", fig7), + ] + + main_tex_content = tex_create_document(options="twocolumn", compatibility="newest") + main_tex_content += "\\usepackage[left=1cm, right=1cm, top=1cm, bottom=1cm]{geometry}\n" + main_tex_content += "\\usetikzlibrary{pgfplots.dateplot}\n" + main_tex_content += "\\usepgfplotslibrary{polar}\n" + main_tex_content += "\n" + stack_env = [] + main_tex_content += tex_begin_environment("document", stack_env) + '\n' + + for i, f in functions: + print(f"Figure {i}") + fig, title = f() + data = fig.data + save_path = os.path.join(file_directory, "outputs", "test_scatter3d", "fig{}.tex".format(i)) + tikzplotly.save(save_path, fig) + main_tex_content += tex_begin_environment("figure", stack_env) + main_tex_content += " \\input{fig" + str(i) + ".tex}\n" + main_tex_content += " \\caption{" + title + "}\n" + main_tex_content += tex_end_environment(stack_env) + '\n' + + main_tex_content += "\n" + tex_end_all_environment(stack_env) + + main_tex_path = os.path.join(file_directory, "outputs", "test_scatter3d", "main.tex") + print("Save main tex file : ", main_tex_path) + with open(main_tex_path, "w") as f: + f.write(main_tex_content) diff --git a/src/tikzplotly/_axis.py b/src/tikzplotly/_axis.py index efa52dc..74fdc55 100644 --- a/src/tikzplotly/_axis.py +++ b/src/tikzplotly/_axis.py @@ -51,9 +51,6 @@ def __init__(self, layout, colors_set, axis_options=None): self.treat_background_layout(colors_set) self.treat_bar_layout() - - - def set_x_label(self, x_label): """Set the x label. @@ -113,7 +110,6 @@ def get_options(self): options_str = option_dict_to_str(self.options, sep="\n") return options_str - def treat_axis_layout(self): """Treat the layout of the axis.""" @@ -158,13 +154,14 @@ def treat_axis_layout(self): self.add_option("xtick", ticks) self.add_option("xticklabels", ticklabels) - if ( - self.layout.xaxis.categoryorder != "trace" - or self.layout.yaxis.categoryorder != "trace" - or self.layout.xaxis.categoryorder != "total descending" - ): + # At this point, only layout.xaxis.categoryarray = "array" is supported + if self.layout.xaxis.categoryorder is not None and self.layout.xaxis.categoryorder not in ["array"]: warn( - "The categoryorder option is not supported (yet 🤞) for the axis environment." + f"The xaxis categoryorder option {self.layout.xaxis.categoryorder} is not supported (yet 🤞) for the axis environment." + ) + if self.layout.yaxis.categoryorder is not None and self.layout.yaxis.categoryorder not in []: + warn( + f"The yaxis categoryorder option {self.layout.yaxis.categoryorder} is not supported (yet 🤞) for the axis environment." ) if self.layout.xaxis.showgrid: @@ -182,7 +179,6 @@ def treat_axis_layout(self): if m.ticklen is not None: self.add_option("subtickwidth", m.ticklen) - def treat_background_layout(self, colors_set): """Treat the background layout of the axis. Parameters diff --git a/src/tikzplotly/_bar.py b/src/tikzplotly/_bar.py new file mode 100644 index 0000000..eb7dd06 --- /dev/null +++ b/src/tikzplotly/_bar.py @@ -0,0 +1,94 @@ +""" +This module handles bar plots. +""" +from warnings import warn +from ._axis import Axis +from ._utils import option_dict_to_str +from ._tex import tex_addplot +from ._color import convert_color +from ._utils import sanitize_text + + +def draw_bar(data_name_macro, x_col_name, y_col_name, trace, axis: Axis, colors_set): + r""" + Draw a bar chart (vertical or horizontal) referencing the data table + created by DataContainer.add_data(...). + + If trace.orientation == 'h', we do xbar (horizontal). + Otherwise, we do ybar (vertical). + + Parameters + ---------- + data_name_macro : str + The LaTeX macro name for the data table (e.g. '\\data0'). + x_col_name : str + The name of the column for x in the data table (e.g. 'data0'). + y_col_name : str + The name of the column for y in the data table (e.g. 'y0'). + trace : plotly.graph_objs._bar.Bar + The bar trace object containing data and style information. + axis : Axis + The axis object to which the bar chart will be added. + colors_set : set + A set to keep track of colors used in the plot (for \\definecolor). + """ + code = "" + plot_options = {} + type_options = {} + + orientation = getattr(trace, "orientation", "v") # default vertical + stack = " stacked" if axis.layout.barmode in ("stack", "relative") else "" + + if orientation == "h": + plot_options["xbar"] = None + axis.add_option("xbar" + stack, None) + type_options["x"] = y_col_name + type_options["y"] = x_col_name + categories = trace.y + else: + plot_options["ybar"] = None + axis.add_option("ybar" + stack, None) + type_options["x"] = x_col_name + type_options["y"] = y_col_name + categories = trace.x + + # Handle symbolic coords + if all(isinstance(value, str) for value in categories): + symbolic = sanitize_text(",".join(categories), keep_space=-1) + if orientation == "h": + axis.add_option("symbolic y coords", "{" + symbolic + "}") + axis.add_option("ytick", "data") + else: + axis.add_option("symbolic x coords", "{" + symbolic + "}") + axis.add_option("xtick", "data") + + # Handle marker style (color, opacity, line) + if trace.marker is not None: + m = trace.marker + if m.color is not None: + c = convert_color(m.color) + colors_set.add(c[:3]) + plot_options["fill"] = c[0] + plot_options["color"] = c[0] + if m.opacity is not None: + plot_options["opacity"] = m.opacity + if m.line is not None: + if m.line.width is not None: + plot_options["line width"] = m.line.width + if m.line.color is not None: + linecol = convert_color(m.line.color) + colors_set.add(linecol[:3]) + plot_options["draw"] = linecol[0] + + if trace.text is not None: + warn("Text display for bar chart is not supported yet (ignored).") + + # Build the final addplot referencing the table + code += tex_addplot( + data_str=data_name_macro, + plot_type="table", + options=option_dict_to_str(plot_options), + type_options=option_dict_to_str(type_options) + ) + + return code diff --git a/src/tikzplotly/_color.py b/src/tikzplotly/_color.py index 3cb8d21..21ed038 100644 --- a/src/tikzplotly/_color.py +++ b/src/tikzplotly/_color.py @@ -4,6 +4,7 @@ """ from warnings import warn import hashlib +import numpy def rgb_str(red, green, blue): """Convert RGB values to a string representation. @@ -43,16 +44,23 @@ def convert_color(color): """ if color is None: return None, None, None, 1 - if color[0] == "#": + if isinstance(color, numpy.ndarray): + warn("Color from data is not supported yet. Returning the default color: blue.") + return "blue", "HTML", "0000ff", 1 + if not isinstance(color, str): + warn(f"Color {color} type '{color.__class__.__name__}' is not supported yet. Returning the default color: blue.") + return "blue", "HTML", "0000ff", 1 + + if color.startswith("#"): return color[1:], "HTML", color[1:], 1 - if color[0:4] == "rgba": + if color.startswith("rgba"): sp = color.split("(")[1].split(",") rgb_color = sp[:-1] rgb_color = convert_color(f"rgb({rgb_color[0]},{rgb_color[1]},{rgb_color[2]})")[:-1] return rgb_color + (float(sp[-1][:-1]),) - if color[0:3] == "rgb": + if color.startswith("rgb"): color = color[4:-1].replace("[", "{").replace("]", "}") return hashlib.sha1(color.encode('UTF-8')).hexdigest()[:10], "RGB", color, 1 @@ -110,7 +118,7 @@ def hex2rgb(hex_color): BISQUE4 = rgb_str(139, 125, 107) BLACK = rgb_str(0, 0, 0) BLANCHEDALMOND = rgb_str(255, 235, 205) -BLUE = rgb_str(0, 0, 255) +BLUE1 = rgb_str(0, 0, 255) BLUE2 = rgb_str(0, 0, 238) BLUE3 = rgb_str(0, 0, 205) BLUE4 = rgb_str(0, 0, 139) @@ -159,9 +167,12 @@ def hex2rgb(hex_color): CORNSILK3 = rgb_str(205, 200, 177) CORNSILK4 = rgb_str(139, 136, 120) CRIMSON = rgb_str(220, 20, 60) +CYAN1 = rgb_str(0, 255, 255) CYAN2 = rgb_str(0, 238, 238) CYAN3 = rgb_str(0, 205, 205) CYAN4 = rgb_str(0, 139, 139) +DARKBLUE = rgb_str(0, 0, 139) +DARKCYAN = rgb_str(0, 139, 139) DARKGOLDENROD = rgb_str(184, 134, 11) DARKGOLDENROD1 = rgb_str(255, 185, 15) DARKGOLDENROD2 = rgb_str(238, 173, 14) @@ -170,6 +181,7 @@ def hex2rgb(hex_color): DARKGRAY = rgb_str(169, 169, 169) DARKGREEN = rgb_str(0, 100, 0) DARKKHAKI = rgb_str(189, 183, 107) +DARKMAGENTA = rgb_str(139, 0, 139) DARKOLIVEGREEN = rgb_str(85, 107, 47) DARKOLIVEGREEN1 = rgb_str(202, 255, 112) DARKOLIVEGREEN2 = rgb_str(188, 238, 104) @@ -185,6 +197,7 @@ def hex2rgb(hex_color): DARKORCHID2 = rgb_str(178, 58, 238) DARKORCHID3 = rgb_str(154, 50, 205) DARKORCHID4 = rgb_str(104, 34, 139) +DARKRED = rgb_str(139, 0, 0) DARKSALMON = rgb_str(233, 150, 122) DARKSEAGREEN = rgb_str(143, 188, 143) DARKSEAGREEN1 = rgb_str(193, 255, 193) @@ -223,6 +236,7 @@ def hex2rgb(hex_color): FLESH = rgb_str(255, 125, 64) FLORALWHITE = rgb_str(255, 250, 240) FORESTGREEN = rgb_str(34, 139, 34) +FUCHSIA = rgb_str(255, 0, 255) GAINSBORO = rgb_str(220, 220, 220) GHOSTWHITE = rgb_str(248, 248, 255) GOLD1 = rgb_str(255, 215, 0) @@ -347,7 +361,6 @@ def hex2rgb(hex_color): HOTPINK2 = rgb_str(238, 106, 167) HOTPINK3 = rgb_str(205, 96, 144) HOTPINK4 = rgb_str(139, 58, 98) -INDIANRED = rgb_str(176, 23, 31) INDIANRED = rgb_str(205, 92, 92) INDIANRED1 = rgb_str(255, 106, 106) INDIANRED2 = rgb_str(238, 99, 99) @@ -389,6 +402,7 @@ def hex2rgb(hex_color): LIGHTGOLDENROD3 = rgb_str(205, 190, 112) LIGHTGOLDENROD4 = rgb_str(139, 129, 76) LIGHTGOLDENRODYELLOW = rgb_str(250, 250, 210) +LIGHTGREEN = rgb_str(144, 238, 144) LIGHTGREY = rgb_str(211, 211, 211) LIGHTPINK = rgb_str(255, 182, 193) LIGHTPINK1 = rgb_str(255, 174, 185) @@ -418,7 +432,7 @@ def hex2rgb(hex_color): LIGHTYELLOW4 = rgb_str(139, 139, 122) LIMEGREEN = rgb_str(50, 205, 50) LINEN = rgb_str(250, 240, 230) -MAGENTA = rgb_str(255, 0, 255) +MAGENTA1 = rgb_str(255, 0, 255) MAGENTA2 = rgb_str(238, 0, 238) MAGENTA3 = rgb_str(205, 0, 205) MAGENTA4 = rgb_str(139, 0, 139) @@ -484,6 +498,7 @@ def hex2rgb(hex_color): PALEGREEN2 = rgb_str(144, 238, 144) PALEGREEN3 = rgb_str(124, 205, 124) PALEGREEN4 = rgb_str(84, 139, 84) +PALETURQUOISE = rgb_str(175, 238, 238) PALETURQUOISE1 = rgb_str(187, 255, 255) PALETURQUOISE2 = rgb_str(174, 238, 238) PALETURQUOISE3 = rgb_str(150, 205, 205) @@ -499,6 +514,7 @@ def hex2rgb(hex_color): PEACHPUFF3 = rgb_str(205, 175, 149) PEACHPUFF4 = rgb_str(139, 119, 101) PEACOCK = rgb_str(51, 161, 201) +PERU = rgb_str(205, 133, 63) PINK = rgb_str(255, 192, 203) PINK1 = rgb_str(255, 181, 197) PINK2 = rgb_str(238, 169, 184) @@ -538,6 +554,7 @@ def hex2rgb(hex_color): SALMON4 = rgb_str(139, 76, 57) SANDYBROWN = rgb_str(244, 164, 96) SAPGREEN = rgb_str(48, 128, 20) +SEAGREEN = rgb_str(46, 139, 87) SEAGREEN1 = rgb_str(84, 255, 159) SEAGREEN2 = rgb_str(78, 238, 148) SEAGREEN3 = rgb_str(67, 205, 128) @@ -636,7 +653,6 @@ def hex2rgb(hex_color): WHEAT4 = rgb_str(139, 126, 102) WHITE = rgb_str(255, 255, 255) WHITESMOKE = rgb_str(245, 245, 245) -WHITESMOKE = rgb_str(245, 245, 245) YELLOW1 = rgb_str(255, 255, 0) YELLOW2 = rgb_str(238, 238, 0) YELLOW3 = rgb_str(205, 205, 0) @@ -649,23 +665,27 @@ def hex2rgb(hex_color): colors["antiquewhite3"] = ANTIQUEWHITE3 colors["antiquewhite4"] = ANTIQUEWHITE4 colors["aqua"] = AQUA +colors["aquamarine"] = AQUAMARINE1 colors["aquamarine1"] = AQUAMARINE1 colors["aquamarine2"] = AQUAMARINE2 colors["aquamarine3"] = AQUAMARINE3 colors["aquamarine4"] = AQUAMARINE4 +colors["azure"] = AZURE1 colors["azure1"] = AZURE1 colors["azure2"] = AZURE2 colors["azure3"] = AZURE3 colors["azure4"] = AZURE4 colors["banana"] = BANANA colors["beige"] = BEIGE +colors["bisque"] = BISQUE1 colors["bisque1"] = BISQUE1 colors["bisque2"] = BISQUE2 colors["bisque3"] = BISQUE3 colors["bisque4"] = BISQUE4 colors["black"] = BLACK colors["blanchedalmond"] = BLANCHEDALMOND -colors["blue"] = BLUE +colors["blue"] = BLUE1 +colors["blue1"] = BLUE1 colors["blue2"] = BLUE2 colors["blue3"] = BLUE3 colors["blue4"] = BLUE4 @@ -691,6 +711,7 @@ def hex2rgb(hex_color): colors["cadmiumorange"] = CADMIUMORANGE colors["cadmiumyellow"] = CADMIUMYELLOW colors["carrot"] = CARROT +colors["chartreuse"] = CHARTREUSE1 colors["chartreuse1"] = CHARTREUSE1 colors["chartreuse2"] = CHARTREUSE2 colors["chartreuse3"] = CHARTREUSE3 @@ -709,14 +730,19 @@ def hex2rgb(hex_color): colors["coral3"] = CORAL3 colors["coral4"] = CORAL4 colors["cornflowerblue"] = CORNFLOWERBLUE +colors["cornsilk"] = CORNSILK1 colors["cornsilk1"] = CORNSILK1 colors["cornsilk2"] = CORNSILK2 colors["cornsilk3"] = CORNSILK3 colors["cornsilk4"] = CORNSILK4 colors["crimson"] = CRIMSON +colors["cyan"] = CYAN1 +colors["cyan1"] = CYAN1 colors["cyan2"] = CYAN2 colors["cyan3"] = CYAN3 colors["cyan4"] = CYAN4 +colors["darkblue"] = DARKBLUE +colors["darkcyan"] = DARKCYAN colors["darkgoldenrod"] = DARKGOLDENROD colors["darkgoldenrod1"] = DARKGOLDENROD1 colors["darkgoldenrod2"] = DARKGOLDENROD2 @@ -725,6 +751,7 @@ def hex2rgb(hex_color): colors["darkgray"] = DARKGRAY colors["darkgreen"] = DARKGREEN colors["darkkhaki"] = DARKKHAKI +colors["darkmagenta"] = DARKMAGENTA colors["darkolivegreen"] = DARKOLIVEGREEN colors["darkolivegreen1"] = DARKOLIVEGREEN1 colors["darkolivegreen2"] = DARKOLIVEGREEN2 @@ -740,6 +767,7 @@ def hex2rgb(hex_color): colors["darkorchid2"] = DARKORCHID2 colors["darkorchid3"] = DARKORCHID3 colors["darkorchid4"] = DARKORCHID4 +colors["darkred"] = DARKRED colors["darksalmon"] = DARKSALMON colors["darkseagreen"] = DARKSEAGREEN colors["darkseagreen1"] = DARKSEAGREEN1 @@ -748,27 +776,30 @@ def hex2rgb(hex_color): colors["darkseagreen4"] = DARKSEAGREEN4 colors["darkslateblue"] = DARKSLATEBLUE colors["darkslategray"] = DARKSLATEGRAY -colors["darkslategrey"] = DARKSLATEGRAY colors["darkslategray1"] = DARKSLATEGRAY1 -colors["darkslategrey1"] = DARKSLATEGRAY colors["darkslategray2"] = DARKSLATEGRAY2 -colors["darkslategrey2"] = DARKSLATEGRAY colors["darkslategray3"] = DARKSLATEGRAY3 -colors["darkslategrey3"] = DARKSLATEGRAY colors["darkslategray4"] = DARKSLATEGRAY4 -colors["darkslategrey4"] = DARKSLATEGRAY +colors["darkslategrey"] = DARKSLATEGRAY +colors["darkslategrey1"] = DARKSLATEGRAY1 +colors["darkslategrey2"] = DARKSLATEGRAY2 +colors["darkslategrey3"] = DARKSLATEGRAY3 +colors["darkslategrey4"] = DARKSLATEGRAY4 colors["darkturquoise"] = DARKTURQUOISE colors["darkviolet"] = DARKVIOLET +colors["deeppink"] = DEEPPINK1 colors["deeppink1"] = DEEPPINK1 colors["deeppink2"] = DEEPPINK2 colors["deeppink3"] = DEEPPINK3 colors["deeppink4"] = DEEPPINK4 +colors["deepskyblue"] = DEEPSKYBLUE1 colors["deepskyblue1"] = DEEPSKYBLUE1 colors["deepskyblue2"] = DEEPSKYBLUE2 colors["deepskyblue3"] = DEEPSKYBLUE3 colors["deepskyblue4"] = DEEPSKYBLUE4 colors["dimgray"] = DIMGRAY colors["dimgray"] = DIMGRAY +colors["dodgerblue"] = DODGERBLUE1 colors["dodgerblue1"] = DODGERBLUE1 colors["dodgerblue2"] = DODGERBLUE2 colors["dodgerblue3"] = DODGERBLUE3 @@ -783,8 +814,10 @@ def hex2rgb(hex_color): colors["flesh"] = FLESH colors["floralwhite"] = FLORALWHITE colors["forestgreen"] = FORESTGREEN +colors["fuchsia"] = FUCHSIA colors["gainsboro"] = GAINSBORO colors["ghostwhite"] = GHOSTWHITE +colors["gold"] = GOLD1 colors["gold1"] = GOLD1 colors["gold2"] = GOLD2 colors["gold3"] = GOLD3 @@ -898,6 +931,7 @@ def hex2rgb(hex_color): colors["green3"] = GREEN3 colors["green4"] = GREEN4 colors["greenyellow"] = GREENYELLOW +colors["honeydew"] = HONEYDEW1 colors["honeydew1"] = HONEYDEW1 colors["honeydew2"] = HONEYDEW2 colors["honeydew3"] = HONEYDEW3 @@ -908,12 +942,12 @@ def hex2rgb(hex_color): colors["hotpink3"] = HOTPINK3 colors["hotpink4"] = HOTPINK4 colors["indianred"] = INDIANRED -colors["indianred"] = INDIANRED colors["indianred1"] = INDIANRED1 colors["indianred2"] = INDIANRED2 colors["indianred3"] = INDIANRED3 colors["indianred4"] = INDIANRED4 colors["indigo"] = INDIGO +colors["ivory"] = IVORY1 colors["ivory1"] = IVORY1 colors["ivory2"] = IVORY2 colors["ivory3"] = IVORY3 @@ -925,11 +959,13 @@ def hex2rgb(hex_color): colors["khaki3"] = KHAKI3 colors["khaki4"] = KHAKI4 colors["lavender"] = LAVENDER +colors["lavenderblush"] = LAVENDERBLUSH1 colors["lavenderblush1"] = LAVENDERBLUSH1 colors["lavenderblush2"] = LAVENDERBLUSH2 colors["lavenderblush3"] = LAVENDERBLUSH3 colors["lavenderblush4"] = LAVENDERBLUSH4 colors["lawngreen"] = LAWNGREEN +colors["lemonchiffon"] = LEMONCHIFFON1 colors["lemonchiffon1"] = LEMONCHIFFON1 colors["lemonchiffon2"] = LEMONCHIFFON2 colors["lemonchiffon3"] = LEMONCHIFFON3 @@ -949,12 +985,14 @@ def hex2rgb(hex_color): colors["lightgoldenrod3"] = LIGHTGOLDENROD3 colors["lightgoldenrod4"] = LIGHTGOLDENROD4 colors["lightgoldenrodyellow"] = LIGHTGOLDENRODYELLOW +colors["lightgreen"] = LIGHTGREEN colors["lightgrey"] = LIGHTGREY colors["lightpink"] = LIGHTPINK colors["lightpink1"] = LIGHTPINK1 colors["lightpink2"] = LIGHTPINK2 colors["lightpink3"] = LIGHTPINK3 colors["lightpink4"] = LIGHTPINK4 +colors["lightsalmon"] = LIGHTSALMON1 colors["lightsalmon1"] = LIGHTSALMON1 colors["lightsalmon2"] = LIGHTSALMON2 colors["lightsalmon3"] = LIGHTSALMON3 @@ -972,13 +1010,15 @@ def hex2rgb(hex_color): colors["lightsteelblue2"] = LIGHTSTEELBLUE2 colors["lightsteelblue3"] = LIGHTSTEELBLUE3 colors["lightsteelblue4"] = LIGHTSTEELBLUE4 +colors["lightyellow"] = LIGHTYELLOW1 colors["lightyellow1"] = LIGHTYELLOW1 colors["lightyellow2"] = LIGHTYELLOW2 colors["lightyellow3"] = LIGHTYELLOW3 colors["lightyellow4"] = LIGHTYELLOW4 colors["limegreen"] = LIMEGREEN colors["linen"] = LINEN -colors["magenta"] = MAGENTA +colors["magenta"] = MAGENTA1 +colors["magenta1"] = MAGENTA1 colors["magenta2"] = MAGENTA2 colors["magenta3"] = MAGENTA3 colors["magenta4"] = MAGENTA4 @@ -1012,6 +1052,7 @@ def hex2rgb(hex_color): colors["mistyrose3"] = MISTYROSE3 colors["mistyrose4"] = MISTYROSE4 colors["moccasin"] = MOCCASIN +colors["navajowhite"] = NAVAJOWHITE1 colors["navajowhite1"] = NAVAJOWHITE1 colors["navajowhite2"] = NAVAJOWHITE2 colors["navajowhite3"] = NAVAJOWHITE3 @@ -1029,6 +1070,7 @@ def hex2rgb(hex_color): colors["orange2"] = ORANGE2 colors["orange3"] = ORANGE3 colors["orange4"] = ORANGE4 +colors["orangered"] = ORANGERED1 colors["orangered1"] = ORANGERED1 colors["orangered2"] = ORANGERED2 colors["orangered3"] = ORANGERED3 @@ -1044,6 +1086,7 @@ def hex2rgb(hex_color): colors["palegreen2"] = PALEGREEN2 colors["palegreen3"] = PALEGREEN3 colors["palegreen4"] = PALEGREEN4 +colors["paleturquoise"] = PALETURQUOISE colors["paleturquoise1"] = PALETURQUOISE1 colors["paleturquoise2"] = PALETURQUOISE2 colors["paleturquoise3"] = PALETURQUOISE3 @@ -1054,11 +1097,13 @@ def hex2rgb(hex_color): colors["palevioletred3"] = PALEVIOLETRED3 colors["palevioletred4"] = PALEVIOLETRED4 colors["papayawhip"] = PAPAYAWHIP +colors["peachpuff"] = PEACHPUFF1 colors["peachpuff1"] = PEACHPUFF1 colors["peachpuff2"] = PEACHPUFF2 colors["peachpuff3"] = PEACHPUFF3 colors["peachpuff4"] = PEACHPUFF4 colors["peacock"] = PEACOCK +colors["peru"] = PERU colors["pink"] = PINK colors["pink1"] = PINK1 colors["pink2"] = PINK2 @@ -1077,6 +1122,7 @@ def hex2rgb(hex_color): colors["purple4"] = PURPLE4 colors["raspberry"] = RASPBERRY colors["rawsienna"] = RAWSIENNA +colors["red"] = RED1 colors["red1"] = RED1 colors["red2"] = RED2 colors["red3"] = RED3 @@ -1098,6 +1144,7 @@ def hex2rgb(hex_color): colors["salmon4"] = SALMON4 colors["sandybrown"] = SANDYBROWN colors["sapgreen"] = SAPGREEN +colors["seagreen"] = SEAGREEN colors["seagreen1"] = SEAGREEN1 colors["seagreen2"] = SEAGREEN2 colors["seagreen3"] = SEAGREEN3 @@ -1148,6 +1195,7 @@ def hex2rgb(hex_color): colors["slategray2"] = SLATEGRAY2 colors["slategray3"] = SLATEGRAY3 colors["slategray4"] = SLATEGRAY4 +colors["snow"] = SNOW1 colors["snow1"] = SNOW1 colors["snow2"] = SNOW2 colors["snow3"] = SNOW3 @@ -1172,6 +1220,7 @@ def hex2rgb(hex_color): colors["thistle2"] = THISTLE2 colors["thistle3"] = THISTLE3 colors["thistle4"] = THISTLE4 +colors["tomato"] = TOMATO1 colors["tomato1"] = TOMATO1 colors["tomato2"] = TOMATO2 colors["tomato3"] = TOMATO3 @@ -1196,7 +1245,7 @@ def hex2rgb(hex_color): colors["wheat4"] = WHEAT4 colors["white"] = WHITE colors["whitesmoke"] = WHITESMOKE -colors["whitesmoke"] = WHITESMOKE +colors["yellow"] = YELLOW1 colors["yellow1"] = YELLOW1 colors["yellow2"] = YELLOW2 colors["yellow3"] = YELLOW3 diff --git a/src/tikzplotly/_data.py b/src/tikzplotly/_data.py index 767a025..33a77e6 100644 --- a/src/tikzplotly/_data.py +++ b/src/tikzplotly/_data.py @@ -2,7 +2,7 @@ This module contains the code to handle data types in TikZ using Plotly data. """ from warnings import warn -from ._utils import replace_all_months +from ._utils import sanitize_text def data_type(data): """Return the type of data, for special handling. @@ -17,20 +17,37 @@ def data_type(data): Type of data, can be : - None : no special handling - 'date' : data is a date - - 'month' : data is a month + - 'string' : a symbolic data """ if isinstance(data, str): if len(data.split('-')) == 3: warn("Assuming this is a date, add \"\\usetikzlibrary{pgfplots.dateplot}\" to your tex preamble.") return 'date' + if data.lower() in ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december']: warn(f"Assuming data {data} is a month. This feature is experimental.") return 'month' - warn(f"Data type of {data} is not supported yet.") - return None return None +def treat_data(data_str): + """Treat data for correct TeX display + + Parameters + ---------- + data_str + string of data to be treated + + Returns + ------- + Sanitized TeX string + """ + data_str = sanitize_text(str(data_str), keep_space=-1) + if data_str.find(' ') !=- 1: # Add curly braces if space in string + if not data_str.startswith("{") and not data_str.startswith("}"): + data_str = "{" + data_str + "}" + return data_str + return data_str def post_treat_data(data_str): """Post-treat the data string to replace all months with their corresponding number. @@ -42,5 +59,5 @@ def post_treat_data(data_str): ------- string of post-treated data """ - data_str = replace_all_months(data_str) + # data_str = replace_all_months(data_str) return data_str.replace("None", "nan") diff --git a/src/tikzplotly/_dataContainer.py b/src/tikzplotly/_dataContainer.py index b6cf111..9ccd493 100644 --- a/src/tikzplotly/_dataContainer.py +++ b/src/tikzplotly/_dataContainer.py @@ -1,8 +1,46 @@ """ Contain the code to handle data in TikZ plots. """ +import hashlib +import numpy as np from ._utils import replace_all_digits, sanitize_text -from ._data import post_treat_data +from ._data import treat_data, post_treat_data + +def hexid_to_alpha(num): + """ + Converts a hexadecimal string or integer to an alphabetic representation using the letters A-P. + Each hexadecimal digit (0-15) is mapped to a corresponding uppercase letter (A-P). + + Parameters + ---------- + num : int or str + The hexadecimal number to convert. Can be an integer or a string containing hexadecimal digits. + + Returns + ------- + Alphabetic representation of the hexadecimal input, where each digit is replaced by a letter from A to P. + + Examples + -------- + >>> hexid_to_alpha(255) + 'PP' + >>> hexid_to_alpha('1a3') + 'ABD' + """ + hexstr = str(num) + table = "ABCDEFGHIJKLMNOP" + return ''.join(table[int(c, 16)] for c in hexstr if c in "0123456789abcdef") + +def index_to_letters(idx): + """Convert an integer to a string like Excel columns: A, B, ..., Z, AA, AB, ...""" + letters = "" + while True: + idx, rem = divmod(idx, 26) + letters = chr(65 + rem) + letters # 65 = ord('A') + if idx == 0: + break + idx -= 1 + return letters class Data: """Class to handle data in TikZ plots. @@ -43,6 +81,46 @@ def add_y_data(self, y, y_label=None): self.y_data.append(y) return self.y_label[-1] +class Data3D: + """Handle 3D data in Tikz plots + """ + def __init__(self, x, y, z, name): + """Initialize the Data3D object + + Parameters + ---------- + x + x_values of the data + y + y_values of the data + z + z_values of the data + name + name of the data + """ + self.x = np.array(x) + self.y = np.array(y) + self.z = np.array(z) + if name: + self.name = sanitize_text(name, keep_space=0) + else: + hash_digest = self.get_hash() + self.name = f"data{hexid_to_alpha(hash_digest)}" + self.z_name = "z" + + def get_hash(self, tolerance=1e-6): + """ + Generates the unique hash corresponding to the data, up to tolerance + """ + def normalize_float(value): + return np.round(value / tolerance) * tolerance + x_norm = normalize_float(self.x) + y_norm = normalize_float(self.y) + z_norm = normalize_float(self.z) + hash_input = f"{x_norm}{y_norm}{z_norm}" + return hashlib.md5(hash_input.encode()).hexdigest() + + class DataContainer: """Container for data used in TikZ plots. """ @@ -50,7 +128,7 @@ class DataContainer: def __init__(self): self.data = [] - def add_data(self, x, y, y_label=None): + def add_data(self, x, y, name=None, y_label=None): """Add data to the container. Parameters @@ -61,6 +139,8 @@ def add_data(self, x, y, y_label=None): y values of the data y_label, optional name of the y data, by default None + name, optional + name of the data, by default None Returns ------- @@ -72,17 +152,41 @@ def add_data(self, x, y, y_label=None): are_equals = data.x == x if isinstance(are_equals, bool): if are_equals: - y_label = data.add_y_data(y, y_label) - return data.macro_name, y_label - elif are_equals.all(): - if (data.x == x).all(): - y_label = data.add_y_data(y, y_label) - return data.macro_name, y_label - data_to_add = Data(f"data{len(self.data)}", x) - y_label = data_to_add.add_y_data(y, y_label) + y_label_val = data.add_y_data(y, y_label or name) + return data.macro_name, treat_data(y_label_val) + elif hasattr(are_equals, "all") and are_equals.all(): + y_label_val = data.add_y_data(y, y_label or name) + return data.macro_name, treat_data(y_label_val) + data_to_add = Data(f"data{index_to_letters(len(self.data))}", x) + y_label_val = data_to_add.add_y_data(y, y_label or name) self.data.append(data_to_add) - return data_to_add.macro_name, sanitize_text(y_label) + return data_to_add.macro_name, treat_data(y_label_val) + + def add_data3d(self, x, y, z, name=None): + """Add data to the container. + + Parameters + ---------- + x + x values of the data + y + y values of the data + z + z values of the data + name, optional + name of the data, by default None + Returns + ------- + tuple (macro_name, z_name), where macro_name is the name of the data in LaTeX and z_name the name of the z data in LaTeX + """ + for data in self.data: + if hasattr(data, "x") and hasattr(data, "y") and hasattr(data, "z"): + if np.array_equal(data.x, x) and np.array_equal(data.y, y) and np.array_equal(data.z, z): + return data.name, data.z_name + data_obj = Data3D(x, y, z, name) + self.data.append(data_obj) + return data_obj.name, data_obj.z_name def export_data(self): """Generate LaTeX code to export the data from DataContainer. @@ -94,11 +198,29 @@ def export_data(self): export_string = "" for data in self.data: - export_string += "\\pgfplotstableread{" - export_string += f"{sanitize_text(data.name)} {' '.join([sanitize_text(label) for label in data.y_label])}\n" - for i, x_val in enumerate(data.x): - export_string += f"{x_val} {' '.join([str(y[i]) for y in data.y_data])}\n" + # 3D + if hasattr(data, "z"): + export_string += "\\pgfplotstableread{\n" + export_string += "x y z\n" + for x, y, z in zip(data.x, data.y, data.z): + export_string += f"{treat_data(x)} {treat_data(y)} {treat_data(z)}\n" + export_string += f"}}{{\\{data.name}}}\n" - export_string += "}" + sanitize_text(data.macro_name) + "\n" + # 2D + else: + export_string += "\\pgfplotstableread{\n" + header = "x" + if hasattr(data, "y_label") and data.y_label: + for label in data.y_label: + header += f" {treat_data(label)}" + else: + header += " y" + export_string += header + "\n" + for i, x in enumerate(data.x): + row = [treat_data(x)] + for y_col in data.y_data: + row.append(treat_data(y_col[i])) + export_string += " ".join(row) + "\n" + export_string += f"}}\\{data.name}\n" return post_treat_data(export_string) diff --git a/src/tikzplotly/_heatmap.py b/src/tikzplotly/_heatmap.py index dd6064f..afaf6bd 100755 --- a/src/tikzplotly/_heatmap.py +++ b/src/tikzplotly/_heatmap.py @@ -3,6 +3,7 @@ """ from warnings import warn import io +import os from copy import deepcopy import numpy as np from PIL import Image @@ -63,7 +64,6 @@ def resize_image(img, nb_row, nb_col): return resized_image - def draw_heatmap(data, fig, img_name, axis: Axis): """Draw a heatmap, and return the tikz code. @@ -92,7 +92,7 @@ def draw_heatmap(data, fig, img_name, axis: Axis): fig_copy.update_layout(coloraxis_showscale=False, coloraxis_colorbar=None, xaxis_visible=False, yaxis_visible=False) try: fig_copy.update_traces(showscale=False) - except ValueError as e: + except ValueError as _: pass if data.texttemplate is not None: @@ -103,6 +103,8 @@ def draw_heatmap(data, fig, img_name, axis: Axis): img_bytes = fig_copy.to_image(format="png") # The image created by plotly keeps places around the heatmap cropped_image = crop_image(Image.open(io.BytesIO(img_bytes))) # so we crop all the white around the figure resized_image = resize_image(cropped_image, *figure_data.shape) # and we resize it so each square is a 1px x 1px square + + os.makedirs(os.path.dirname(img_name), exist_ok=True) # Make sure the directory exists resized_image.save(img_name) diff --git a/src/tikzplotly/_polar.py b/src/tikzplotly/_polar.py new file mode 100644 index 0000000..a293a9a --- /dev/null +++ b/src/tikzplotly/_polar.py @@ -0,0 +1,216 @@ +""" +Provides functionality to convert Plotly 3D polar plots into TikZ/PGFPlots code for LaTeX documents. +""" +from warnings import warn +import numpy as np +from ._axis import Axis +from ._utils import option_dict_to_str +from ._tex import tex_addplot +from ._color import convert_color +from ._dataContainer import DataContainer + +def get_polar_coord(trace, axis: Axis, data_container: DataContainer): + """Get polar coordinates from the trace + + Parameters + ---------- + trace + polar trace from Plotly figure + axis + axis object previously created + data_container + Data table, created before + + Returns + ------- + Tuple (data_name_macro, theta_col_name, r_col_name): + - data_name_macro: name of the data in LaTeX + - theta_col_name: name of the theta column + - r_col_name: name of the r column + """ + polar_layout = getattr(axis.layout, 'polar') + if polar_layout: + # Angular Axis + angularaxis = getattr(polar_layout, 'angularaxis') + if angularaxis: + # Rotation + rotation = getattr(angularaxis, 'rotation') + if rotation is None: + rotation = 0 + else: + axis.add_option("rotate", rotation) + axis.add_option("xticklabel style", f"{{anchor=\\tick+{rotation}+180}}") + axis.add_option("yticklabel style", f"{{anchor=\\tick-{rotation}-90}}") + + # Direction + direction = getattr(angularaxis, "direction", "counterclockwise") + if direction == "clockwise": + axis.add_option("y dir", "reverse") + axis.add_option("xticklabel style", f"{{anchor={rotation}-\\tick+180}}") + + # Period + period = getattr(angularaxis, "period") + + # Category + angular_categoryorder = getattr(angularaxis, 'categoryorder', 'trace') + angular_categoryarray = getattr(angularaxis, 'categoryarray', None) + + # Radial Axis + radialaxis = getattr(polar_layout, 'radialaxis') + if radialaxis: + # Type + radial_axis_type = getattr(radialaxis, 'type', None) + if radial_axis_type is not None and radial_axis_type not in ['-', 'linear', 'category']: + warn(f"Polar: Radial axis type {radial_axis_type} is not supported yet.") + + # Category + radial_categoryorder = getattr(radialaxis, 'categoryorder', 'trace') + radial_categoryarray = getattr(radialaxis, 'categoryarray', None) + + # Range + sector = getattr(radialaxis, 'range') + if sector and len(sector) > 1: + axis.add_option("ymin", sector[0]) + axis.add_option("ymax", sector[1]) + + # Sector + sector = getattr(polar_layout, 'sector') + if sector and len(sector) > 1: + axis.add_option("xmin", sector[0]) + axis.add_option("xmax", sector[1]) + + theta = [t if t is not None else '' for t in trace.theta] + r = [val if val is not None else 'nan' for val in trace.r] + + thetaunit = getattr(trace, "thetaunit", "degrees") + + # Angular Axis + if all(isinstance(t, str) for t in theta): + if angular_categoryarray is not None: + symbolic_theta = list(angular_categoryarray) + else: + symbolic_theta = list(dict.fromkeys(theta)) + + if angular_categoryorder is not None: + if angular_categoryorder == "category ascending": + symbolic_theta = sorted(set(symbolic_theta)) + elif angular_categoryorder == "category descending": + symbolic_theta = sorted(set(symbolic_theta), reverse=True) + else: + warn(f"Polar: Angular category order {angular_categoryorder} is not supported yet.") + + n_theta = len(symbolic_theta) + if period is not None: + n_theta = max(period, n_theta) + + numeric_theta = [symbolic_theta.index(t) * (360 / n_theta) for t in theta] + + axis.environment = "polaraxis" + axis.add_option("xtick", f"{{{','.join(str( i * (360 / n_theta)) for i in range(n_theta))}}}") + axis.add_option("xticklabels", "{" + ",".join(symbolic_theta) + "}") + else: + symbolic_theta = None + if thetaunit == "radians": + numeric_theta = [t * (180 / 3.141592653589793) for t in theta] + else: + numeric_theta = theta + + # Radial Axis + if all(isinstance(v, str) for v in r): + if radial_categoryarray is not None: + symbolic_r = list(radial_categoryarray) + else: + symbolic_r = list(dict.fromkeys(r)) + if radial_categoryorder is not None: + if radial_categoryorder == "category ascending": + symbolic_r = sorted(set(symbolic_r)) + elif radial_categoryorder == "category descending": + symbolic_r = sorted(set(symbolic_r), reverse=True) + else: + warn(f"Polar: Radial category order {radial_categoryorder} is not supported yet.") + + axis.add_option("symbolic y coords", "{" + ",".join(symbolic_r) + "}") + axis.add_option("ytick", "data") + + data_name_macro, r_col_name = data_container.add_data(numeric_theta, r, trace.name) + theta_col_name = data_container.data[-1].name + + return data_name_macro, theta_col_name, r_col_name + +def draw_scatterpolar(data_name_macro, theta_col_name, r_col_name, trace, axis: Axis, colors_set): + """ + Draw a scatterpolar plot using pgfplots polaraxis environment. + + Parameters + ---------- + data_name_macro : str + The LaTeX macro for the data table (e.g. '\\data0'). + theta_col_name : str + Name of the column for theta values (angles). + r_col_name : str + The name of the column for radial values in the data table. + trace : plotly.graph_objs._scatterpolar.Scatterpolar + Plotly Scatterpolar trace + axis : Axis + Axis object (to add axis-level options) + colors_set : set + Set of colors defined + + Returns + ------- + str + LaTeX/pgfplots code for scatterpolar plot + """ + + plot_options = {} + + mode = trace.mode if trace.mode else "lines" + + if "markers" not in mode: + plot_options["no markers"] = None + elif "lines" not in mode: + plot_options["only marks"] = None + + # Marker style + if trace.marker is not None: + marker = trace.marker + if marker.color is not None: + col = convert_color(marker.color) + plot_options["color"] = col[0] + mark_opts = {"solid": None, "fill": col[0]} + colors_set.add(col[:3]) + plot_options["mark options"] = "{" + option_dict_to_str(mark_opts) + "}" + if marker.size is not None: + if isinstance(marker.size, np.ndarray): + warn("Polar: Individual marker sizes in a trace are not supported yet.") + else: + plot_options["mark size"] = marker.size/4 + + # Line style + if trace.line is not None: + line = trace.line + if line.color is not None: + color = convert_color(line.color) + colors_set.add(color[:3]) + plot_options["color"] = color[0] + if line.width is not None: + plot_options["line width"] = line.width + + # Fill + if trace.fill is not None: + if trace.fill == 'toself': + plot_options["fill"] = ".!50" + plot_options["opacity"] = 0.6 + + # Axis options for polar plot + axis.environment = "polaraxis" + + # Construct TikZ addplot + code = tex_addplot( + data_str=data_name_macro, + plot_type="table", + options=option_dict_to_str(plot_options), + type_options=f"x={theta_col_name}, y={r_col_name}" + ) + + return code diff --git a/src/tikzplotly/_save.py b/src/tikzplotly/_save.py index 9c5d195..a4e4390 100755 --- a/src/tikzplotly/_save.py +++ b/src/tikzplotly/_save.py @@ -7,16 +7,21 @@ from pathlib import Path from warnings import warn import re +import numpy as np from .__about__ import __version__ from ._tex import tex_add_legendentry, tex_comment, tex_begin_environment, tex_add_color, tex_end_all_environment from ._scatter import draw_scatter2d +from ._scatter3d import draw_scatter3d from ._heatmap import draw_heatmap from ._histogram import draw_histogram +from ._bar import draw_bar +from ._polar import get_polar_coord, draw_scatterpolar from ._axis import Axis from ._color import convert_color from ._annotations import str_from_annotation from ._dataContainer import DataContainer -from ._utils import sanitize_tex_text +from ._utils import sanitize_tex_text, sanitize_text + def get_tikz_code( fig, @@ -70,6 +75,19 @@ def get_tikz_code( trace.y = list(range(len(trace.x))) data_name_macro, y_name = data_container.add_data(trace.x, trace.y, trace.name) + + # If x is textual => symbolic x coords + if all(isinstance(v, str) for v in trace.x): + sanitized_trace_x = [sanitize_text(x, keep_space=-1) for x in trace.x] + axis.add_option("symbolic x coords", "{" + ",".join(sanitized_trace_x) + "}") + axis.add_option("xtick", "data") + + # If y is textual => symbolic y coords + if all(isinstance(v, str) for v in trace.y): + sanitized_trace_y = [sanitize_text(y, keep_space=-1) for y in trace.y] + axis.add_option("symbolic y coords", "{" + ",".join(sanitized_trace_y) + "}") + axis.add_option("ytick", "data") + data_str.append( draw_scatter2d(data_name_macro, trace, y_name, axis, colors_set) ) if trace.name and trace['showlegend'] is not False: data_str.append( tex_add_legendentry(sanitize_tex_text(trace.name)) ) @@ -92,6 +110,79 @@ def get_tikz_code( if trace.name and trace['showlegend'] is not False: data_str.append( tex_add_legendentry(sanitize_tex_text(trace.name)) ) + elif trace.type == "bar": + orientation = getattr(trace, "orientation", "v") + cat_list = trace.y if orientation == "h" else trace.x + val_list = trace.x if orientation == "h" else trace.y + + data_name_macro, val_col_name = data_container.add_data(cat_list, val_list, trace.name) + x_col_name = "x" + + bar_code = draw_bar(data_name_macro, x_col_name, val_col_name, trace, axis, colors_set) + data_str.append(bar_code) + + if trace.name and trace['showlegend'] is not False: + data_str.append(tex_add_legendentry(sanitize_tex_text(trace.name))) + + elif trace.type in ('scatterpolar', 'scatterpolargl'): + data_name_macro, theta_col_name, r_col_name = get_polar_coord(trace, axis, data_container) + theta_col_name = "x" + + polar_code = draw_scatterpolar(data_name_macro, theta_col_name, r_col_name, trace, axis, colors_set) + data_str.append(polar_code) + + if trace.name and trace['showlegend'] is not False: + data_str.append(tex_add_legendentry(sanitize_tex_text(trace.name))) + + elif trace.type == "scatter3d": + # Handle the case where x, y, or z is empty + if trace.x is None or trace.y is None or trace.z is None: + warn("Adding empty 3D trace.") + data_str.append("\\addplot3 coordinates {};\n") + continue + + # View + if hasattr(figure_layout.scene, "camera") and hasattr(figure_layout.scene.camera, "eye"): + eye = figure_layout.scene.camera.eye + if eye is not None and eye.x is not None and eye.y is not None and eye.z is not None: + norm = np.sqrt(eye.x**2 + eye.y**2 + eye.z**2) + azimuth = np.degrees(np.arctan2(eye.y, eye.x)) + elevation = np.degrees(np.arcsin(eye.z / norm)) + axis.add_option("view", f"{{{azimuth:.1f}}}{{{elevation:.1f}}}") + + # Labels + if hasattr(figure_layout.scene.xaxis, "title") and getattr(figure_layout.scene.xaxis.title, "text", None): + axis.add_option("xlabel", f"{{{sanitize_tex_text(figure_layout.scene.xaxis.title.text)}}}") + if hasattr(figure_layout.scene.yaxis, "title") and getattr(figure_layout.scene.yaxis.title, "text", None): + axis.add_option("ylabel", f"{{{sanitize_tex_text(figure_layout.scene.yaxis.title.text)}}}") + if hasattr(figure_layout.scene.zaxis, "title") and getattr(figure_layout.scene.zaxis.title, "text", None): + axis.add_option("zlabel", f"{{{sanitize_tex_text(figure_layout.scene.zaxis.title.text)}}}") + + # Grid + if hasattr(figure_layout.scene.xaxis, "showgrid"): + if figure_layout.scene.xaxis.showgrid is False: + axis.add_option("xmajorgrids", "false") + if hasattr(figure_layout.scene.yaxis, "showgrid"): + if figure_layout.scene.yaxis.showgrid is False: + axis.add_option("ymajorgrids", "false") + if hasattr(figure_layout.scene.zaxis, "showgrid"): + if figure_layout.scene.zaxis.showgrid is False: + axis.add_option("zmajorgrids", "false") + + # Title + if hasattr(figure_layout.scene, "title") and getattr(figure_layout.scene.title, "text", None): + axis.add_option("title", f"{{{sanitize_tex_text(figure_layout.scene.title.text)}}}") + + data_name_macro, z_name = data_container.add_data3d(trace.x, trace.y, trace.z, trace.name) + data_str.append(draw_scatter3d(data_name_macro, trace, colors_set)) + + if trace.name and trace['showlegend'] is not False: + data_str.append(tex_add_legendentry(sanitize_tex_text(trace.name))) + if getattr(trace, "line", None) and getattr(trace.line, "color", None) is not None: + colors_set.add(convert_color(trace.line.color)[:3]) + if getattr(trace, "fillcolor", None) is not None: + colors_set.add(convert_color(trace.fillcolor)[:3]) + else: warn(f"Trace type {trace.type} is not supported yet.") diff --git a/src/tikzplotly/_scatter.py b/src/tikzplotly/_scatter.py index 6e22bd9..a064a8a 100644 --- a/src/tikzplotly/_scatter.py +++ b/src/tikzplotly/_scatter.py @@ -10,7 +10,7 @@ from ._dash import DASH_PATTERN from ._axis import Axis from ._data import data_type -from ._utils import px_to_pt, option_dict_to_str, sanitize_text +from ._utils import px_to_pt, option_dict_to_str def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set): """Get code for a scatter trace. @@ -37,9 +37,12 @@ def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set): mode = scatter.mode marker = scatter.marker - if data_type(scatter.x[0]) == "date": + type_of_data = data_type(scatter.x[0]) + + if type_of_data == "date": axis.add_option("date coordinates in", "x") - if data_type(scatter.x[0]) == "month": + + if type_of_data == "month": scatter_x_str = "{" + ", ".join(list(scatter.x)) + "}" axis.add_option("xticklabels", scatter_x_str) @@ -60,7 +63,6 @@ def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set): else: options_dict["only marks"] = None - mark_options = "" if scatter.marker.size is not None: options_dict["mark size"] = px_to_pt(marker.size) @@ -79,9 +81,9 @@ def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set): if (angle:=scatter.marker.angle) is not None: mark_option_dict["rotate"] = angle - if (opacity:=scatter.opacity) is not None: + if (opacity := scatter.opacity) is not None: options_dict["opacity"] = np.round(opacity, 2) - if (opacity:=scatter.marker.opacity) is not None: + if (opacity := scatter.marker.opacity) is not None: mark_option_dict["opacity"] = np.round(opacity, 2) if mark_option_dict: @@ -126,7 +128,7 @@ def draw_scatter2d(data_name, scatter, y_name, axis: Axis, color_set): options_dict["forget plot"] = None options = option_dict_to_str(options_dict) - code += tex_addplot(data_name, plot_type="table", options=options, type_options=f"y={sanitize_text(y_name)}") + code += tex_addplot(data_name, plot_type="table", options=options, type_options=f"y={y_name}") if scatter.text is not None: for x_data, y_data, text_data in zip(scatter.x, scatter.y, scatter.text): diff --git a/src/tikzplotly/_scatter3d.py b/src/tikzplotly/_scatter3d.py new file mode 100644 index 0000000..9ac833e --- /dev/null +++ b/src/tikzplotly/_scatter3d.py @@ -0,0 +1,104 @@ +""" +Provides functionality to convert Plotly 3D scatter traces into TikZ/PGFPlots code for LaTeX documents. +""" +from warnings import warn +import numpy as np +from ._color import convert_color +from ._marker import marker_symbol_to_tex +from ._utils import px_to_pt, option_dict_to_str + +def draw_scatter3d(data_name, scatter, color_set): + """ + Get code for a scatter3d trace. + + Parameters + ---------- + data_name + name of the data imported in LaTeX + scatter + scatter trace from Plotly figure + color_set + set of colors used in the figure + """ + code = "" + + mode = scatter.mode or "markers+lines" + marker = scatter.marker + + options_dict = {} + mark_option_dict = {} + + # Markers only + if mode == "markers": + if marker.symbol is not None: + symbol, symbol_options = marker_symbol_to_tex(marker.symbol) + options_dict["mark"] = symbol + options_dict["only marks"] = None + if symbol_options is not None: + mark_option_dict[symbol_options[0]] = symbol_options[1] + else: + options_dict["only marks"] = None + + if marker.size is not None: + size = marker.size + if isinstance(size, (list, tuple)) or (hasattr(size, "shape") and hasattr(size, "__len__")): + try: + size = float(np.mean(size)) + except (TypeError, ValueError): + size = float(size[0]) + options_dict["mark size"] = px_to_pt(size) + + if (c := marker.color) is not None: + color_set.add(convert_color(c)[:3]) + mark_option_dict["solid"] = None + mark_option_dict["fill"] = convert_color(c)[0] + + if (line := marker.line) is not None: + if line.color is not None: + color_set.add(convert_color(line.color)[:3]) + mark_option_dict["draw"] = convert_color(line.color)[0] + if line.width is not None: + mark_option_dict["line width"] = px_to_pt(line.width) + + if (opacity := scatter.opacity) is not None: + options_dict["opacity"] = opacity + if (opacity := marker.opacity) is not None: + mark_option_dict["opacity"] = opacity + + if mark_option_dict: + mark_options = option_dict_to_str(mark_option_dict) + options_dict["mark options"] = f"{{{mark_options}}}" + + elif mode == "lines": + options_dict["mark"] = "none" + + elif "lines" in mode and "markers" in mode: + if marker.symbol is not None: + symbol, symbol_options = marker_symbol_to_tex(marker.symbol) + options_dict["mark"] = symbol + if symbol_options is not None: + mark_option_dict[symbol_options[0]] = symbol_options[1] + + else: + warn(f"Scatter3d : Mode {mode} is not supported yet.") + + if scatter.line is not None: + if scatter.line.width is not None: + options_dict["line width"] = px_to_pt(scatter.line.width) + if scatter.line.color is not None: + options_dict["color"] = convert_color(scatter.line.color)[0] + color_set.add(convert_color(scatter.line.color)[:3]) + + if scatter.showlegend is False: + options_dict["forget plot"] = None + + options = option_dict_to_str(options_dict) + if scatter.name: + code += f"\n% {scatter.name}\n" + + code += "\\addplot3+ " + if options is not None: + code += f"[{options}] " + code += f"table[x=x, y=y, z=z] {{\\{data_name}}};\n" + + return code diff --git a/src/tikzplotly/_tex.py b/src/tikzplotly/_tex.py index 5c39ec1..8225291 100644 --- a/src/tikzplotly/_tex.py +++ b/src/tikzplotly/_tex.py @@ -162,7 +162,6 @@ def tex_add_legendentry(legend, options=None): return f"\\addlegendentry[{options}]{{{legend}}}\n" return f"\\addlegendentry{{{legend}}}\n" - def tex_create_document(document_class="article", options=None, compatibility="newest"): """Create a LaTeX document. @@ -212,9 +211,6 @@ def tex_create_document(document_class="article", options=None, compatibility="n # code += f"];\n" # return code - - - def tex_text(text): """Convert a string to LaTeX, escaping the special characters %, _, &, #, $, {, }, ~. diff --git a/src/tikzplotly/_utils.py b/src/tikzplotly/_utils.py index 4e072f4..29bdca4 100644 --- a/src/tikzplotly/_utils.py +++ b/src/tikzplotly/_utils.py @@ -52,7 +52,7 @@ def replace_all_months(text): """ return pattern_months.sub(lambda m: rep_months[re.escape(m.group(0))], text) -def sanitize_text(text: str, keep_space: bool = False) -> str: +def sanitize_text(text: str, keep_space: int = 0) -> str: """ Sanitize the input text by removing or replacing unwanted characters. @@ -60,9 +60,10 @@ def sanitize_text(text: str, keep_space: bool = False) -> str: ---------- text : str The input text to be sanitized. - keep_space : bool, optional - If True, spaces will be preserved in the sanitized text. - If False, spaces will be replaced with underscores. Defaults to False. + keep_space : int, optional + If 1, spaces will be preserved in the sanitized text. + If 0, spaces will be replaced with underscores. Defaults to 0. + If -1, spaces will be deleted from the text Returns ------- @@ -71,7 +72,7 @@ def sanitize_text(text: str, keep_space: bool = False) -> str: """ return ''.join(sanitize_char(ch, keep_space) for ch in text) -def sanitize_char(ch: str, keep_space: bool = False) -> str: +def sanitize_char(ch: str, keep_space: int = 0) -> str: """ Sanitize a character by escaping special characters or converting to hex if non-ASCII/non-printable. @@ -79,23 +80,35 @@ def sanitize_char(ch: str, keep_space: bool = False) -> str: ---------- ch : str The character to sanitize. - keep_space : bool, optional - If True, spaces will be kept as is. Defaults to False. + keep_space : int, optional + If 1, spaces will be preserved in the sanitized text. + If 0, spaces will be replaced with underscores. Defaults to 0. + If -1, spaces will be deleted from the text Returns ------- str The sanitized character. """ + if ch == "@": + return "at" if ch == " ": - return " " if keep_space else "_" - if ch in "[]{}=": + if keep_space == 1: + return " " + if keep_space == 0: + return "_" + return "" + if ch in "[]{}= ": return f"x{ord(ch):x}" - if ord(ch) > 127 or not ch.isprintable(): + # if not ascii, return hex + if ord(ch) > 127: + return f"x{ord(ch):x}" + # if not printable, return hex + if not ch.isprintable(): return f"x{ord(ch):x}" return ch -def sanitize_tex_text(text: str) -> str: +def sanitize_tex_text(text: str): """ Sanitize a string for LaTeX, escaping special characters and ensuring proper formatting. @@ -109,9 +122,10 @@ def sanitize_tex_text(text: str) -> str: str The sanitized text, with special characters escaped and formatted for LaTeX. """ - sanitized = ''.join(sanitize_tex_char(ch) for ch in text) - if '[' in sanitized or ']' in sanitized: - return f"{{{sanitized}}}" + sanitized = "".join(map(sanitize_tex_char, text)) + special_chars = "[]," + if any(c in sanitized for c in special_chars): + return "{" + sanitized + "}" return sanitized def sanitize_tex_char(ch: str) -> str: @@ -152,7 +166,6 @@ def px_to_pt(px): return int(pt) return pt - def option_dict_to_str(options_dict, sep=" "): """Convert a dictionary of options to a string of options for TikZ. diff --git a/tests/empty_plot.tex b/tests/empty_plot.tex new file mode 100644 index 0000000..25634b8 --- /dev/null +++ b/tests/empty_plot.tex @@ -0,0 +1,4 @@ +\begin{tikzpicture} +\begin{axis} +\end{axis} +\end{tikzpicture} diff --git a/tests/test_bars.py b/tests/test_bars.py new file mode 100644 index 0000000..f2c5889 --- /dev/null +++ b/tests/test_bars.py @@ -0,0 +1,57 @@ +import plotly.express as px +import plotly.graph_objects as go +import numpy as np +import os +from .helpers import assert_equality +import pathlib +import pytest + +this_dir = pathlib.Path(__file__).resolve().parent +test_name = "test_bars" + + +def plot_vertical1(): + data_canada = px.data.gapminder().query("country == 'Canada'") + fig = px.bar(data_canada, x='year', y='pop') + return fig + +def plot_vertical2(): + wide_df = px.data.medals_wide() + fig = px.bar( + wide_df, + x="nation", + y=["gold", "silver", "bronze"], + title="Wide-Form Input", + color_discrete_map={ + "gold": "gold", + "silver": "silver", + "bronze": "#cd7f32" + } + ) + fig.update_traces(marker_line_width=2, marker_line_color="black") + return fig + +def plot_horizontal1(): + fig = go.Figure(go.Bar( + x=[20, 14, 23], + y=['giraffes', 'orangutans', 'monkeys'], + orientation='h')) + return fig + +def plot_horizontal2(): + df = px.data.tips() + fig = px.bar(df, x="total_bill", y="day", orientation='h') + return fig + + +def test_vertical1(): + assert_equality(plot_vertical1(), os.path.join(this_dir, test_name, test_name + "_vertical1_reference.tex")) + +def test_vertical2(): + assert_equality(plot_vertical2(), os.path.join(this_dir, test_name, test_name + "_vertical2_reference.tex")) + +def test_horizontal1(): + assert_equality(plot_horizontal1(), os.path.join(this_dir, test_name, test_name + "_horizontal1_reference.tex")) + +def test_horizontal2(): + assert_equality(plot_horizontal2(), os.path.join(this_dir, test_name, test_name + "_horizontal2_reference.tex")) diff --git a/tests/test_bars/test_bars_horizontal1_reference.tex b/tests/test_bars/test_bars_horizontal1_reference.tex new file mode 100644 index 0000000..0984220 --- /dev/null +++ b/tests/test_bars/test_bars_horizontal1_reference.tex @@ -0,0 +1,16 @@ +\pgfplotstableread{ +x y0 +giraffes 20 +orangutans 14 +monkeys 23 +}\dataA + +\begin{tikzpicture} +\begin{axis}[ +xbar, +symbolic y coords={giraffes,orangutans,monkeys}, +ytick=data +] +\addplot+ [xbar] table[x=y0, y=x] {\dataA}; +\end{axis} +\end{tikzpicture} diff --git a/tests/test_bars/test_bars_horizontal2_reference.tex b/tests/test_bars/test_bars_horizontal2_reference.tex new file mode 100644 index 0000000..edb84e5 --- /dev/null +++ b/tests/test_bars/test_bars_horizontal2_reference.tex @@ -0,0 +1,262 @@ +\pgfplotstableread{ +x y0 +Sun 16.99 +Sun 10.34 +Sun 21.01 +Sun 23.68 +Sun 24.59 +Sun 25.29 +Sun 8.77 +Sun 26.88 +Sun 15.04 +Sun 14.78 +Sun 10.27 +Sun 35.26 +Sun 15.42 +Sun 18.43 +Sun 14.83 +Sun 21.58 +Sun 10.33 +Sun 16.29 +Sun 16.97 +Sat 20.65 +Sat 17.92 +Sat 20.29 +Sat 15.77 +Sat 39.42 +Sat 19.82 +Sat 17.81 +Sat 13.37 +Sat 12.69 +Sat 21.7 +Sat 19.65 +Sat 9.55 +Sat 18.35 +Sat 15.06 +Sat 20.69 +Sat 17.78 +Sat 24.06 +Sat 16.31 +Sat 16.93 +Sat 18.69 +Sat 31.27 +Sat 16.04 +Sun 17.46 +Sun 13.94 +Sun 9.68 +Sun 30.4 +Sun 18.29 +Sun 22.23 +Sun 32.4 +Sun 28.55 +Sun 18.04 +Sun 12.54 +Sun 10.29 +Sun 34.81 +Sun 9.94 +Sun 25.56 +Sun 19.49 +Sat 38.01 +Sat 26.41 +Sat 11.24 +Sat 48.27 +Sat 20.29 +Sat 13.81 +Sat 11.02 +Sat 18.29 +Sat 17.59 +Sat 20.08 +Sat 16.45 +Sat 3.07 +Sat 20.23 +Sat 15.01 +Sat 12.02 +Sat 17.07 +Sat 26.86 +Sat 25.28 +Sat 14.73 +Sat 10.51 +Sat 17.92 +Thur 27.2 +Thur 22.76 +Thur 17.29 +Thur 19.44 +Thur 16.66 +Thur 10.07 +Thur 32.68 +Thur 15.98 +Thur 34.83 +Thur 13.03 +Thur 18.28 +Thur 24.71 +Thur 21.16 +Fri 28.97 +Fri 22.49 +Fri 5.75 +Fri 16.32 +Fri 22.75 +Fri 40.17 +Fri 27.28 +Fri 12.03 +Fri 21.01 +Fri 12.46 +Fri 11.35 +Fri 15.38 +Sat 44.3 +Sat 22.42 +Sat 20.92 +Sat 15.36 +Sat 20.49 +Sat 25.21 +Sat 18.24 +Sat 14.31 +Sat 14.0 +Sat 7.25 +Sun 38.07 +Sun 23.95 +Sun 25.71 +Sun 17.31 +Sun 29.93 +Thur 10.65 +Thur 12.43 +Thur 24.08 +Thur 11.69 +Thur 13.42 +Thur 14.26 +Thur 15.95 +Thur 12.48 +Thur 29.8 +Thur 8.52 +Thur 14.52 +Thur 11.38 +Thur 22.82 +Thur 19.08 +Thur 20.27 +Thur 11.17 +Thur 12.26 +Thur 18.26 +Thur 8.51 +Thur 10.33 +Thur 14.15 +Thur 16.0 +Thur 13.16 +Thur 17.47 +Thur 34.3 +Thur 41.19 +Thur 27.05 +Thur 16.43 +Thur 8.35 +Thur 18.64 +Thur 11.87 +Thur 9.78 +Thur 7.51 +Sun 14.07 +Sun 13.13 +Sun 17.26 +Sun 24.55 +Sun 19.77 +Sun 29.85 +Sun 48.17 +Sun 25.0 +Sun 13.39 +Sun 16.49 +Sun 21.5 +Sun 12.66 +Sun 16.21 +Sun 13.81 +Sun 17.51 +Sun 24.52 +Sun 20.76 +Sun 31.71 +Sat 10.59 +Sat 10.63 +Sat 50.81 +Sat 15.81 +Sun 7.25 +Sun 31.85 +Sun 16.82 +Sun 32.9 +Sun 17.89 +Sun 14.48 +Sun 9.6 +Sun 34.63 +Sun 34.65 +Sun 23.33 +Sun 45.35 +Sun 23.17 +Sun 40.55 +Sun 20.69 +Sun 20.9 +Sun 30.46 +Sun 18.15 +Sun 23.1 +Sun 15.69 +Thur 19.81 +Thur 28.44 +Thur 15.48 +Thur 16.58 +Thur 7.56 +Thur 10.34 +Thur 43.11 +Thur 13.0 +Thur 13.51 +Thur 18.71 +Thur 12.74 +Thur 13.0 +Thur 16.4 +Thur 20.53 +Thur 16.47 +Sat 26.59 +Sat 38.73 +Sat 24.27 +Sat 12.76 +Sat 30.06 +Sat 25.89 +Sat 48.33 +Sat 13.27 +Sat 28.17 +Sat 12.9 +Sat 28.15 +Sat 11.59 +Sat 7.74 +Sat 30.14 +Fri 12.16 +Fri 13.42 +Fri 8.58 +Fri 15.98 +Fri 13.42 +Fri 16.27 +Fri 10.09 +Sat 20.45 +Sat 13.28 +Sat 22.12 +Sat 24.01 +Sat 15.69 +Sat 11.61 +Sat 10.77 +Sat 15.53 +Sat 10.07 +Sat 12.6 +Sat 32.83 +Sat 35.83 +Sat 29.03 +Sat 27.18 +Sat 22.67 +Sat 17.82 +Thur 18.78 +}\dataA + +\begin{tikzpicture} + +\definecolor{636efa}{HTML}{636efa} + +\begin{axis}[ +xbar stacked, +symbolic y coords={Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Fri,Fri,Fri,Fri,Fri,Fri,Fri,Fri,Fri,Fri,Fri,Fri,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sun,Sun,Sun,Sun,Sun,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sat,Sat,Sat,Sat,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Sun,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Thur,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Fri,Fri,Fri,Fri,Fri,Fri,Fri,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Sat,Thur}, +ytick=data, +xlabel=total\_bill, +ylabel=day +] +\addplot+ [xbar, fill=636efa, color=636efa] table[x=y0, y=x] {\dataA}; +\end{axis} +\end{tikzpicture} diff --git a/tests/test_bars/test_bars_vertical1_reference.tex b/tests/test_bars/test_bars_vertical1_reference.tex new file mode 100644 index 0000000..81db6b8 --- /dev/null +++ b/tests/test_bars/test_bars_vertical1_reference.tex @@ -0,0 +1,28 @@ +\pgfplotstableread{ +x y0 +1952 14785584 +1957 17010154 +1962 18985849 +1967 20819767 +1972 22284500 +1977 23796400 +1982 25201900 +1987 26549700 +1992 28523502 +1997 30305843 +2002 31902268 +2007 33390141 +}\dataA + +\begin{tikzpicture} + +\definecolor{636efa}{HTML}{636efa} + +\begin{axis}[ +ybar stacked, +xlabel=year, +ylabel=pop +] +\addplot+ [ybar, fill=636efa, color=636efa] table[x=x, y=y0] {\dataA}; +\end{axis} +\end{tikzpicture} diff --git a/tests/test_bars/test_bars_vertical2_reference.tex b/tests/test_bars/test_bars_vertical2_reference.tex new file mode 100644 index 0000000..b63b189 --- /dev/null +++ b/tests/test_bars/test_bars_vertical2_reference.tex @@ -0,0 +1,29 @@ +\pgfplotstableread{ +x gold silver bronze +SouthKorea 24 13 11 +China 10 15 8 +Canada 9 12 12 +}\dataA + +\begin{tikzpicture} + +\definecolor{cd7f32}{HTML}{cd7f32} +\definecolor{gold}{RGB}{255, 215, 0} +\definecolor{silver}{RGB}{192, 192, 192} + +\begin{axis}[ +ybar stacked, +symbolic x coords={SouthKorea,China,Canada}, +xtick=data, +title=Wide-Form Input, +xlabel=nation, +ylabel=value +] +\addplot+ [ybar, fill=gold, color=gold, line width=2, draw=black] table[x=x, y=gold] {\dataA}; +\addlegendentry{gold} +\addplot+ [ybar, fill=silver, color=silver, line width=2, draw=black] table[x=x, y=silver] {\dataA}; +\addlegendentry{silver} +\addplot+ [ybar, fill=cd7f32, color=cd7f32, line width=2, draw=black] table[x=x, y=bronze] {\dataA}; +\addlegendentry{bronze} +\end{axis} +\end{tikzpicture} diff --git a/tests/test_markers/test_markers_1_reference.tex b/tests/test_markers/test_markers_1_reference.tex index 1bd63e4..0569891 100644 --- a/tests/test_markers/test_markers_1_reference.tex +++ b/tests/test_markers/test_markers_1_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 setosa +\pgfplotstableread{ +x setosa 3.5 5.1 3.0 4.9 3.2 4.7 @@ -49,8 +50,9 @@ 3.2 4.6 3.7 5.3 3.3 5.0 -}\dataZ -\pgfplotstableread{data1 versicolor +}\dataA +\pgfplotstableread{ +x versicolor 3.2 7.0 3.2 6.4 3.1 6.9 @@ -101,8 +103,9 @@ 2.9 6.2 2.5 5.1 2.8 5.7 -}\dataO -\pgfplotstableread{data2 virginica +}\dataB +\pgfplotstableread{ +x virginica 3.3 6.3 2.7 5.8 3.0 7.1 @@ -153,7 +156,7 @@ 3.0 6.5 3.4 6.2 3.0 5.9 -}\dataT +}\dataC \begin{tikzpicture} @@ -166,11 +169,11 @@ xlabel=sepal\_width, ylabel=sepal\_length ] -\addplot+ [mark=*, only marks, mark size=9, mark options={solid, fill=636efa, draw=darkslategrey, line width=1.5}] table[y=setosa] {\dataZ}; +\addplot+ [mark=*, only marks, mark size=9, mark options={solid, fill=636efa, draw=darkslategrey, line width=1.5}] table[y=setosa] {\dataA}; \addlegendentry{setosa} -\addplot+ [mark=*, only marks, mark size=9, mark options={solid, fill=EF553B, draw=darkslategrey, line width=1.5}] table[y=versicolor] {\dataO}; +\addplot+ [mark=*, only marks, mark size=9, mark options={solid, fill=EF553B, draw=darkslategrey, line width=1.5}] table[y=versicolor] {\dataB}; \addlegendentry{versicolor} -\addplot+ [mark=*, only marks, mark size=9, mark options={solid, fill=00cc96, draw=darkslategrey, line width=1.5}] table[y=virginica] {\dataT}; +\addplot+ [mark=*, only marks, mark size=9, mark options={solid, fill=00cc96, draw=darkslategrey, line width=1.5}] table[y=virginica] {\dataC}; \addlegendentry{virginica} \end{axis} \end{tikzpicture} diff --git a/tests/test_markers/test_markers_2_reference.tex b/tests/test_markers/test_markers_2_reference.tex index fa2e092..60e4e4e 100644 --- a/tests/test_markers/test_markers_2_reference.tex +++ b/tests/test_markers/test_markers_2_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 4.251066014107722 3.2624466286607725 5.160973480326474 3.6819292088540663 3.0003431244520344 3.943129848342151 @@ -499,11 +500,12 @@ 5.53298984569714 5.006389817768609 5.760619542916981 3.9779016219269576 3.6837008698539506 5.323431798045239 -}\dataZ -\pgfplotstableread{data1 y0 +}\dataA +\pgfplotstableread{ +x y0 2 4.25 2 4.75 -}\dataO +}\dataB \begin{tikzpicture} @@ -511,7 +513,7 @@ \definecolor{mediumpurple}{RGB}{147, 112, 219} \begin{axis} -\addplot+ [only marks, mark size=15, mark options={solid, fill=lightskyblue, draw=mediumpurple, line width=1.5, opacity=0.5}, forget plot] table[y=y0] {\dataZ}; -\addplot+ [only marks, mark size=60, mark options={solid, fill=lightskyblue, draw=mediumpurple, line width=6, opacity=0.5}, forget plot] table[y=y0] {\dataO}; +\addplot+ [only marks, mark size=15, mark options={solid, fill=lightskyblue, draw=mediumpurple, line width=1.5, opacity=0.5}, forget plot] table[y=y0] {\dataA}; +\addplot+ [only marks, mark size=60, mark options={solid, fill=lightskyblue, draw=mediumpurple, line width=6, opacity=0.5}, forget plot] table[y=y0] {\dataB}; \end{axis} \end{tikzpicture} diff --git a/tests/test_markers/test_markers_3_reference.tex b/tests/test_markers/test_markers_3_reference.tex index 6ea2340..9e869e9 100644 --- a/tests/test_markers/test_markers_3_reference.tex +++ b/tests/test_markers/test_markers_3_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 setosa +\pgfplotstableread{ +x setosa 3.5 5.1 3.0 4.9 3.2 4.7 @@ -49,8 +50,9 @@ 3.2 4.6 3.7 5.3 3.3 5.0 -}\dataZ -\pgfplotstableread{data1 versicolor +}\dataA +\pgfplotstableread{ +x versicolor 3.2 7.0 3.2 6.4 3.1 6.9 @@ -101,8 +103,9 @@ 2.9 6.2 2.5 5.1 2.8 5.7 -}\dataO -\pgfplotstableread{data2 virginica +}\dataB +\pgfplotstableread{ +x virginica 3.3 6.3 2.7 5.8 3.0 7.1 @@ -153,7 +156,7 @@ 3.0 6.5 3.4 6.2 3.0 5.9 -}\dataT +}\dataC \begin{tikzpicture} @@ -166,11 +169,11 @@ xlabel=sepal\_width, ylabel=sepal\_length ] -\addplot+ [mark=diamond*, only marks, mark size=6, mark options={solid, fill=636efa, draw=darkslategrey, line width=1.5}] table[y=setosa] {\dataZ}; +\addplot+ [mark=diamond*, only marks, mark size=6, mark options={solid, fill=636efa, draw=darkslategrey, line width=1.5}] table[y=setosa] {\dataA}; \addlegendentry{setosa} -\addplot+ [mark=diamond*, only marks, mark size=6, mark options={solid, fill=EF553B, draw=darkslategrey, line width=1.5}] table[y=versicolor] {\dataO}; +\addplot+ [mark=diamond*, only marks, mark size=6, mark options={solid, fill=EF553B, draw=darkslategrey, line width=1.5}] table[y=versicolor] {\dataB}; \addlegendentry{versicolor} -\addplot+ [mark=diamond*, only marks, mark size=6, mark options={solid, fill=00cc96, draw=darkslategrey, line width=1.5}] table[y=virginica] {\dataT}; +\addplot+ [mark=diamond*, only marks, mark size=6, mark options={solid, fill=00cc96, draw=darkslategrey, line width=1.5}] table[y=virginica] {\dataC}; \addlegendentry{virginica} \end{axis} \end{tikzpicture} diff --git a/tests/test_markers/test_markers_angle_reference.tex b/tests/test_markers/test_markers_angle_reference.tex index 3fec2f1..b06aee8 100644 --- a/tests/test_markers/test_markers_angle_reference.tex +++ b/tests/test_markers/test_markers_angle_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 setosa +\pgfplotstableread{ +x setosa 3.5 5.1 3.0 4.9 3.2 4.7 @@ -49,8 +50,9 @@ 3.2 4.6 3.7 5.3 3.3 5.0 -}\dataZ -\pgfplotstableread{data1 versicolor +}\dataA +\pgfplotstableread{ +x versicolor 3.2 7.0 3.2 6.4 3.1 6.9 @@ -101,8 +103,9 @@ 2.9 6.2 2.5 5.1 2.8 5.7 -}\dataO -\pgfplotstableread{data2 virginica +}\dataB +\pgfplotstableread{ +x virginica 3.3 6.3 2.7 5.8 3.0 7.1 @@ -153,7 +156,7 @@ 3.0 6.5 3.4 6.2 3.0 5.9 -}\dataT +}\dataC \begin{tikzpicture} @@ -166,11 +169,11 @@ xlabel=sepal\_width, ylabel=sepal\_length ] -\addplot+ [mark=triangle*, only marks, mark size=9, mark options={xscale=0.5, solid, fill=636efa, draw=darkslategrey, line width=1.5, rotate=45}] table[y=setosa] {\dataZ}; +\addplot+ [mark=triangle*, only marks, mark size=9, mark options={xscale=0.5, solid, fill=636efa, draw=darkslategrey, line width=1.5, rotate=45}] table[y=setosa] {\dataA}; \addlegendentry{setosa} -\addplot+ [mark=triangle*, only marks, mark size=9, mark options={xscale=0.5, solid, fill=EF553B, draw=darkslategrey, line width=1.5, rotate=45}] table[y=versicolor] {\dataO}; +\addplot+ [mark=triangle*, only marks, mark size=9, mark options={xscale=0.5, solid, fill=EF553B, draw=darkslategrey, line width=1.5, rotate=45}] table[y=versicolor] {\dataB}; \addlegendentry{versicolor} -\addplot+ [mark=triangle*, only marks, mark size=9, mark options={xscale=0.5, solid, fill=00cc96, draw=darkslategrey, line width=1.5, rotate=45}] table[y=virginica] {\dataT}; +\addplot+ [mark=triangle*, only marks, mark size=9, mark options={xscale=0.5, solid, fill=00cc96, draw=darkslategrey, line width=1.5, rotate=45}] table[y=virginica] {\dataC}; \addlegendentry{virginica} \end{axis} \end{tikzpicture} diff --git a/tests/test_polar.py b/tests/test_polar.py new file mode 100644 index 0000000..847a32a --- /dev/null +++ b/tests/test_polar.py @@ -0,0 +1,278 @@ +""" +Test of polar plots https://plotly.com/python/radar-chart/ and https://plotly.com/python/polar-chart/ +""" +import os, pathlib +import plotly.express as px +import plotly.graph_objects as go +import pandas as pd +from .helpers import assert_equality + +this_dir = pathlib.Path(__file__).resolve().parent +test_name = "test_polar" + +def plot_radar_1(): + df = pd.DataFrame(dict( + r=[1, 5, 2, 2, 3], + theta=['processing cost','mechanical properties','chemical stability', + 'thermal stability', 'device integration'])) + fig = px.line_polar(df, r='r', theta='theta', line_close=True) + return fig + +def plot_radar_2(): + df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/polar_dataset.csv") + + fig = go.Figure() + fig.add_trace(go.Scatterpolar( + r = df['x1'], + theta = df['y'], + mode = 'lines', + name = 'Figure 8', + line_color = 'peru' + )) + fig.add_trace(go.Scatterpolar( + r = df['x2'], + theta = df['y'], + mode = 'lines', + name = 'Cardioid', + line_color = 'darkviolet', + line_width=2 + )) + fig.add_trace(go.Scatterpolar( + r = df['x3'], + theta = df['y'], + mode = 'lines', + name = 'Hypercardioid', + line_color = 'deepskyblue' + )) + fig.update_layout( + title = 'Basic Polar Chart', + showlegend = False + ) + return fig + +def fig_polar_categorial_angular(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + name = "angular categories", + r = [5, 4, 2, 4, 5], + theta = ["a", "b", "c", "d", "a"], + )) + + fig.update_traces(fill='toself') + + fig.update_layout( + polar = dict( + radialaxis_angle = -45, + angularaxis = dict( + direction = "clockwise", + period = 6) + ), + ) + return fig + +def fig_polar_categorial_radial(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + name = "radial categories", + r = ["a", "b", "c", "d", "b", "f", "a"], + theta = [1, 4, 2, 1.5, 1.5, 6, 5], + thetaunit = "radians", + )) + + fig.update_traces(fill='toself') + + fig.update_layout( + polar = dict( + radialaxis = dict( + angle = 180, + tickangle = -180 # so that tick labels are not upside down + ) + ) + ) + return fig + +def fig_polar_categorial_angularcategories(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + name = "angular categories (w/ categoryarray)", + r = [5, 4, 2, 4, 5], + theta = ["a", "b", "c", "d", "a"], + )) + + fig.update_traces(fill='toself') + + fig.update_layout( + polar = dict( + sector = [80, 400], + radialaxis_angle = -45, + angularaxis_categoryarray = ["d", "a", "c", "b"] + ), + ) + return fig + +def fig_polar_categorial_radialcategories(): + + fig = go.Figure() + + fig.add_trace(go.Scatterpolar( + name = "radial categories (w/ category descending)", + r = ["a", "b", "c", "d", "b", "f", "a", "a"], + theta = [45, 90, 180, 200, 300, 15, 20, 45], + )) + + fig.update_traces(fill='toself') + fig.update_layout( + polar = dict( + radialaxis_categoryorder = "category descending", + angularaxis = dict( + thetaunit = "radians", + dtick = 0.3141592653589793 + )) + ) + return fig + +def fig_polar_range_1(): + fig = px.scatter_polar(r=range(0,90,10), theta=range(0,90,10), + range_theta=[0,90], start_angle=0, direction="counterclockwise") + return fig + +def fig_polar_range_2(): + fig = go.Figure() + fig.add_trace(go.Scatterpolar( + mode = "lines", + r = [3, 3, 4, 3], + theta = [0, 45, 90, 270], + fill = "toself", + subplot = "polar4", + )) + fig.update_layout( + polar = dict( + radialaxis = dict(visible = False, range = [0, 6]) + ), + showlegend = False + ) + return fig + +def fig_polar_1(): + df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/hobbs-pearson-trials.csv") + + fig = go.Figure() + fig.add_trace(go.Scatterpolargl( + r = df.trial_1_r, + theta = df.trial_1_theta, + name = "Trial 1", + marker=dict(size=15, color="mediumseagreen") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_2_r, + theta = df.trial_2_theta, + name = "Trial 2", + marker=dict(size=20, color="darkorange") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_3_r, + theta = df.trial_3_theta, + name = "Trial 3", + marker=dict(size=12, color="mediumpurple") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_4_r, + theta = df.trial_4_theta, + name = "Trial 4", + marker=dict(size=22, color = "magenta") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_5_r, + theta = df.trial_5_theta, + name = "Trial 5", + marker=dict(size=19, color = "limegreen") + )) + fig.add_trace(go.Scatterpolargl( + r = df.trial_6_r, + theta = df.trial_6_theta, + name = "Trial 6", + marker=dict(size=10, color = "gold") + )) + + # Common parameters for all traces + fig.update_traces(mode="markers", marker=dict(line_color='white', opacity=0.7)) + + fig.update_layout( + title = "Hobbs-Pearson Trials", + font_size = 15, + showlegend = False, + polar = dict( + bgcolor = "rgb(223, 223, 223)", + angularaxis = dict( + linewidth = 3, + showline=True, + linecolor='black' + ), + radialaxis = dict( + side = "counterclockwise", + showline = True, + linewidth = 2, + gridcolor = "white", + gridwidth = 2, + ) + ), + paper_bgcolor = "rgb(223, 223, 223)" + ) + return fig + +def fig_polar_matplotlib(): # not supported yet + fig = go.Figure(go.Barpolar( + r=[3.5, 1.5, 2.5, 4.5, 4.5, 4, 3], + theta=[65, 15, 210, 110, 312.5, 180, 270], + width=[20,15,10,20,15,30,15,], + marker_color=["#E4FF87", '#709BFF', '#709BFF', '#FFAA70', '#FFAA70', '#FFDF70', '#B6FFB4'], + marker_line_color="black", + marker_line_width=2, + opacity=0.8 + )) + + fig.update_layout( + template=None, + polar = dict( + radialaxis = dict(range=[0, 5], showticklabels=False, ticks=''), + angularaxis = dict(showticklabels=False, ticks='') + ) + ) + return fig + + +def test_radar_1(): + assert_equality(plot_radar_1(), os.path.join(this_dir, test_name, test_name + "_radar_1_reference.tex")) + +def test_radar_2(): + assert_equality(plot_radar_2(), os.path.join(this_dir, test_name, test_name + "_radar_2_reference.tex")) + +def test_polar_categorial_angular(): + assert_equality(fig_polar_categorial_angular(), os.path.join(this_dir, test_name, test_name + "_categorical_angular_reference.tex")) + +def test_polar_categorial_radial(): + assert_equality(fig_polar_categorial_radial(), os.path.join(this_dir, test_name, test_name + "_categorical_radial_reference.tex")) + +def test_polar_categorial_angularcategories(): + assert_equality(fig_polar_categorial_angularcategories(), os.path.join(this_dir, test_name, test_name + "_categorical_angularcategories_reference.tex")) + +def test_polar_categorial_radialcategories(): + assert_equality(fig_polar_categorial_radialcategories(), os.path.join(this_dir, test_name, test_name + "_categorical_radialcategories_reference.tex")) + +def test_polar_range_1(): + assert_equality(fig_polar_range_1(), os.path.join(this_dir, test_name, test_name + "_radar_range_1_reference.tex")) + +def test_polar_range_2(): + assert_equality(fig_polar_range_2(), os.path.join(this_dir, test_name, test_name + "_radar_range_2_reference.tex")) + +def test_polar_1(): + assert_equality(fig_polar_1(), os.path.join(this_dir, test_name, test_name + "_1_reference.tex")) + +def test_polar_matplotlib(): + assert_equality(fig_polar_matplotlib(), os.path.join(this_dir, "empty_plot.tex")) diff --git a/tests/test_polar/test_polar_1_reference.tex b/tests/test_polar/test_polar_1_reference.tex new file mode 100644 index 0000000..526841e --- /dev/null +++ b/tests/test_polar/test_polar_1_reference.tex @@ -0,0 +1,399 @@ +\pgfplotstableread{ +x Trial1 +-30.35294436 6.804985785 +-25.61145985 3.389596011 +-12.42522745 5.381472111 +13.96138052 8.059540219 +-4.950932841 5.318229228 +-25.69227419 2.985099936 +12.46876416 1.966587002 +-4.913764107 6.769265408 +-10.96738029 4.073401899 +30.81419405 6.504371825 +2.474959431 7.556369819 +17.97554375 4.047456094 +0.771130593 7.386662496 +6.137488486 5.413624737 +-14.45196357 7.470716531 +28.18453411 7.982110217 +12.53868007 4.73781408 +-8.983230337 4.206453043 +5.231285165 5.478604805 +-64.48900254 4.824520281 +11.35748668 5.59960061 +3.454074792 6.866795217 +13.92434661 3.085671366 +-25.36400205 7.771810943 +-16.81800639 3.687794435 +-10.26005103 5.360356685 +-13.21213413 5.140446739 +2.579338865 6.045445681 +8.717574966 6.83392094 +-10.67549872 3.620769463 +-2.926366013 3.989430583 +25.19588075 5.3118245 +40.59032932 4.60821348 +-9.12143363 6.640584716 +-24.29736238 3.055188854 +-3.176944506 7.492564164 +10.85049842 5.485078178 +-31.33205975 3.897794997 +4.849567462 5.976245114 +15.04827695 5.447061561 +3.295104699 5.377034117 +-6.197091873 4.690805788 +-8.778574136 4.711640491 +29.54917412 3.629919329 +-5.137448793 5.957668076 +23.02686049 5.357121284 +-6.634816578 3.849235283 +2.755014992 6.250507136 +21.73325011 7.122243357 +-24.81699496 3.399404234 +-7.830547063 3.510556672 +28.32579621 4.100997604 +12.30097747 4.0963821 +-21.56315724 6.233583075 +-19.33551628 3.939488527 +26.14644317 3.925445077 +-1.706071203 6.118132501 +16.0717237 3.940450346 +2.053266303 7.583015573 +-5.097911612 3.513202145 +}\dataA +\pgfplotstableread{ +x Trial2 +14.80662578 3.488043923 +79.00634037 2.918478576 +49.02206554 4.20182736 +49.69908314 8.227324607 +54.13749108 4.776690427 +86.41932102 3.041912303 +96.95239194 4.789947719 +41.46348826 5.66388078 +67.13769169 3.858262393 +68.06103944 8.260212881 +42.68193032 6.868624486 +76.39865661 5.7401976 +42.19479347 6.594979282 +59.57788897 5.692703778 +27.5108668 5.337916574 +60.75344483 9.283604185 +68.3708328 5.764590893 +65.74802815 4.028864552 +58.53300837 5.662344748 +-176.7441065 0.422837231 +61.17401858 6.201266464 +47.45150859 6.439265381 +84.42665319 5.096758513 +12.47934655 4.632081909 +72.48080276 3.421846136 +50.57883176 4.369404703 +51.56022824 4.028334419 +52.43785618 5.805767198 +51.58682799 6.848189921 +73.87294478 3.809295513 +70.21705693 4.385268184 +70.71429915 6.983326846 +82.23439443 7.396273186 +38.93539045 5.215125003 +84.70936667 3.086148779 +38.16582844 6.335394491 +61.70405365 6.090414714 +70.19695629 2.448056007 +54.45429259 5.94278402 +64.33489497 6.373129886 +58.27389315 5.454205341 +60.49982239 4.393337617 +59.15523254 4.20594468 +83.86561847 6.155542288 +47.8734099 5.119087171 +69.28260157 6.869860831 +71.18991043 4.104599861 +51.04839646 5.954348126 +59.42758242 8.092332877 +78.59873696 2.961769705 +75.75586452 3.974012188 +79.97048372 6.373384129 +73.89378025 5.415409143 +31.73341113 3.87689092 +68.08475118 3.261446947 +80.41107998 6.14580853 +48.92425071 5.502451987 +76.65025576 5.571553295 +42.18286436 6.853049261 +76.03333589 4.140355075 +}\dataB +\pgfplotstableread{ +x Trial3 +151.2942552 1.855870835 +147.188025 5.286962062 +125.2821571 3.886013392 +87.06729797 6.282863313 +119.6278984 4.453414848 +147.7408241 5.688008051 +139.5645981 7.330864283 +101.3914971 3.825660595 +134.5601843 4.989604177 +104.0244447 7.89743147 +89.39314294 4.656693113 +123.1940314 6.667153696 +91.47434052 4.431006287 +113.3323736 5.346113253 +96.14992557 2.479945696 +93.28073452 8.113477349 +118.2155652 6.081311682 +132.3229374 4.968216896 +112.9411864 5.244453921 +-179.7462331 5.422207884 +110.3035136 5.792774616 +97.75083617 4.787580592 +131.6080893 6.784318637 +115.4969192 1.108936909 +140.5811822 5.138911105 +123.3966621 4.042929657 +128.342009 4.02289203 +107.6088104 4.828428791 +97.90468979 5.417378374 +137.128448 5.378635211 +130.4312449 5.421097175 +112.2270845 7.120561979 +118.6302022 8.34930854 +106.0582256 3.410485588 +146.9081097 5.628378471 +90.27734956 3.914936976 +111.5052824 5.763940262 +151.0897425 4.764374107 +107.7213942 5.076236268 +111.300855 6.165558183 +114.6802779 5.105576516 +126.5693795 4.761036377 +128.2189522 4.596249541 +125.3548572 7.504188411 +112.4180683 4.107031418 +111.7973557 6.920422299 +133.4180523 5.34912895 +105.1841168 4.798065719 +97.23103612 7.023251532 +146.6680368 5.283680965 +136.2393152 5.569071152 +121.7918442 7.383794908 +123.911328 6.26923321 +129.862245 2.656529645 +141.3439509 4.843984339 +123.2709677 7.247992362 +108.4588217 4.372959394 +124.4123771 6.570981081 +89.02711074 4.602479244 +134.8767011 5.670052051 +}\dataC +\pgfplotstableread{ +x Trial4 +-140.2033276 5.372470924 +-168.0842454 7.096355572 +-166.2851413 4.883823903 +138.2488668 2.920135441 +-174.4243864 4.723963046 +-169.9604828 7.423693951 +176.9918227 8.090946075 +-169.9014162 3.306844591 +-172.6415816 6.050828483 +142.9516688 5.530232074 +172.4157464 2.472306953 +168.5193592 6.275670537 +177.8220537 2.615896174 +172.8551903 4.653539945 +-146.0145217 3.335440014 +128.177293 4.795883605 +169.1670728 5.472711346 +-173.5885738 5.881930491 +173.7269927 4.571587072 +-151.2061048 9.03986117 +166.2604772 4.6429076 +172.5075661 3.172767736 +173.9491839 7.044248139 +-131.8068409 4.466336514 +-170.6352738 6.55733029 +-168.5770855 4.820849437 +-166.7655034 5.131915515 +176.0704873 3.970012237 +162.2975015 3.406323813 +-174.0557463 6.476722964 +-178.0609299 6.019218509 +156.4712689 5.664501535 +155.2391421 7.158758523 +-163.0005264 3.600712662 +-170.1167133 7.324127169 +-170.6392725 2.552946156 +167.3831437 4.72713386 +-163.0988171 6.971755207 +172.880737 4.076578361 +163.3860077 4.946223407 +176.182542 4.642155449 +-174.5796802 5.360574864 +-172.3358449 5.391719067 +165.3380257 7.072524305 +-172.5256643 4.10111157 +157.5428777 5.485732621 +-175.8815111 6.192535286 +175.427644 3.768711392 +142.0696747 4.29031139 +-168.340734 7.06019537 +-175.8058311 6.539691844 +163.0637454 6.679744406 +171.720975 6.060825359 +-151.4039046 4.786574041 +-168.2713691 6.41668653 +165.0453279 6.703281333 +-177.3153367 3.88884781 +170.0424129 6.308591081 +173.5991966 2.437044771 +-177.2506567 6.508186348 +}\dataD +\pgfplotstableread{ +x Trial5 +-101.8337858 7.937557871 +-127.4783916 7.302746492 +-112.244285 5.929302221 +-82.32591087 2.407178713 +-114.6888556 5.270921887 +-130.5378634 7.400596128 +-145.010265 6.810820338 +-98.74884501 4.967759034 +-124.4417488 6.19022937 +-152.4541193 2.158518658 +-89.29423655 4.004125894 +-139.8324517 4.776617322 +-91.54359518 4.232250452 +-119.442163 4.307654873 +-92.45583853 6.200275173 +-129.6599243 0.727513849 +-131.0512351 4.378006804 +-123.8529175 6.004964939 +-118.086739 4.341931703 +-121.9792171 10.23798294 +-121.91503 3.802158889 +-99.36184758 3.96928117 +-141.467702 5.758980142 +-93.56626319 7.674179069 +-126.3369014 6.699953533 +-112.8349442 5.734310388 +-114.3864799 6.044275915 +-109.7960723 4.312943066 +-102.7432647 3.377545282 +-128.2467289 6.367666727 +-127.7920926 5.737244182 +-142.4736297 3.396351472 +-161.5872942 4.216467481 +-99.94061078 5.464885017 +-130.1631173 7.311135578 +-90.22881201 4.745400769 +-122.6504912 3.916468532 +-123.2677506 7.60297299 +-111.9973088 4.125204829 +-127.5283168 3.67679495 +-117.9312953 4.551235789 +-120.3916342 5.606960532 +-119.3868715 5.794844257 +-149.6746955 5.030528156 +-107.8505175 5.109586241 +-138.9899313 3.405440208 +-127.5954702 6.026306125 +-107.3208354 4.221109264 +-117.5738074 1.909782937 +-127.481661 7.254669394 +-129.9120332 6.268875872 +-148.4952117 4.562580567 +-135.3316414 4.918057965 +-104.4216593 6.836560963 +-123.8754402 6.786486549 +-146.8168266 4.751014334 +-107.0584854 4.719926348 +-138.9025649 4.927805215 +-88.89688252 4.059190587 +-130.7544674 6.128338984 +}\dataE +\pgfplotstableread{ +x Trial6 +-66.53583633 8.469180528 +-84.51442268 5.821997567 +-63.3397417 6.140918328 +-24.14681274 5.831724285 +-59.70124532 5.546754472 +-88.06537268 5.627487709 +-98.44420454 3.948328976 +-49.15839682 6.490184615 +-73.63622331 5.320618245 +-17.92387468 3.243593041 +-38.41239945 6.444085332 +-66.34036238 3.363778101 +-40.88883874 6.463116811 +-52.46063321 4.730944926 +-52.61046256 7.796578411 +-7.039351051 4.57012783 +-57.23545869 3.926206816 +-71.6422035 5.25434814 +-52.34539617 4.838411107 +-92.78303867 8.694523999 +-47.18716306 4.399531818 +-41.96920846 5.856483905 +-82.14422825 3.621577039 +-59.4391656 8.894912373 +-79.19482259 5.494542836 +-62.29990854 5.968980891 +-65.53790404 6.047899574 +-48.90605545 5.384671397 +-37.74831104 5.381220018 +-78.05333346 5.111574623 +-71.87311766 4.770561105 +-41.89109283 3.098330883 +-53.11545549 1.665083172 +-52.9976281 6.740258533 +-87.08436102 5.594494929 +-43.61190484 6.879630826 +-48.79799841 4.382792466 +-82.56680316 6.410843616 +-47.909963 5.154204318 +-46.57048559 4.015158519 +-54.50048322 4.939148868 +-65.90072713 5.298297314 +-66.87331746 5.490417177 +-75.48080725 2.623751259 +-54.77769387 5.953588662 +-42.59833459 3.301479372 +-74.50816627 4.954889001 +-47.11021844 5.50005367 +-22.35687318 4.45051235 +-84.19298675 5.786624513 +-78.50528476 4.906834424 +-65.03637179 2.629969473 +-66.51373368 3.769703608 +-63.52677656 7.396735716 +-77.80907855 5.764481902 +-68.51017974 2.794585196 +-51.29686931 5.78203327 +-68.33991303 3.485351918 +-38.63173307 6.500653599 +-77.85184859 4.74864071 +}\dataF + +\begin{tikzpicture} + +\definecolor{darkorange}{RGB}{255, 140, 0} +\definecolor{gold}{RGB}{255, 215, 0} +\definecolor{limegreen}{RGB}{50, 205, 50} +\definecolor{magenta}{RGB}{255, 0, 255} +\definecolor{mediumpurple}{RGB}{147, 112, 219} +\definecolor{mediumseagreen}{RGB}{60, 179, 113} + +\begin{polaraxis}[ +title=Hobbs-Pearson Trials +] +\addplot+ [only marks, color=mediumseagreen, mark options={solid, fill=mediumseagreen}, mark size=3.75] table[x=x, y=Trial1] {\dataA}; +\addplot+ [only marks, color=darkorange, mark options={solid, fill=darkorange}, mark size=5.0] table[x=x, y=Trial2] {\dataB}; +\addplot+ [only marks, color=mediumpurple, mark options={solid, fill=mediumpurple}, mark size=3.0] table[x=x, y=Trial3] {\dataC}; +\addplot+ [only marks, color=magenta, mark options={solid, fill=magenta}, mark size=5.5] table[x=x, y=Trial4] {\dataD}; +\addplot+ [only marks, color=limegreen, mark options={solid, fill=limegreen}, mark size=4.75] table[x=x, y=Trial5] {\dataE}; +\addplot+ [only marks, color=gold, mark options={solid, fill=gold}, mark size=2.5] table[x=x, y=Trial6] {\dataF}; +\end{polaraxis} +\end{tikzpicture} diff --git a/tests/test_polar/test_polar_categorical_angular_reference.tex b/tests/test_polar/test_polar_categorical_angular_reference.tex new file mode 100644 index 0000000..4bbcedb --- /dev/null +++ b/tests/test_polar/test_polar_categorical_angular_reference.tex @@ -0,0 +1,20 @@ +\pgfplotstableread{ +x angularcategories +0.0 5 +60.0 4 +120.0 2 +180.0 4 +0.0 5 +}\dataA + +\begin{tikzpicture} +\begin{polaraxis}[ +y dir=reverse, +xticklabel style={anchor=0-\tick+180}, +xtick={0.0,60.0,120.0,180.0,240.0,300.0}, +xticklabels={a,b,c,d} +] +\addplot+ [no markers, fill=.!50, opacity=0.6] table[x=x, y=angularcategories] {\dataA}; +\addlegendentry{angular categories} +\end{polaraxis} +\end{tikzpicture} diff --git a/tests/test_polar/test_polar_categorical_angularcategories_reference.tex b/tests/test_polar/test_polar_categorical_angularcategories_reference.tex new file mode 100644 index 0000000..61e242a --- /dev/null +++ b/tests/test_polar/test_polar_categorical_angularcategories_reference.tex @@ -0,0 +1,20 @@ +\pgfplotstableread{ +x angularcategories(w/categoryarray) +90.0 5 +270.0 4 +180.0 2 +0.0 4 +90.0 5 +}\dataA + +\begin{tikzpicture} +\begin{polaraxis}[ +xmin=80, +xmax=400, +xtick={0.0,90.0,180.0,270.0}, +xticklabels={d,a,c,b} +] +\addplot+ [no markers, fill=.!50, opacity=0.6] table[x=x, y=angularcategories(w/categoryarray)] {\dataA}; +\addlegendentry{angular categories (w/ categoryarray)} +\end{polaraxis} +\end{tikzpicture} diff --git a/tests/test_polar/test_polar_categorical_radial_reference.tex b/tests/test_polar/test_polar_categorical_radial_reference.tex new file mode 100644 index 0000000..5186fec --- /dev/null +++ b/tests/test_polar/test_polar_categorical_radial_reference.tex @@ -0,0 +1,20 @@ +\pgfplotstableread{ +x radialcategories +57.29577951308232 a +229.1831180523293 b +114.59155902616465 c +85.94366926962348 d +85.94366926962348 b +343.77467707849394 f +286.4788975654116 a +}\dataA + +\begin{tikzpicture} +\begin{polaraxis}[ +symbolic y coords={a,b,c,d,f}, +ytick=data +] +\addplot+ [no markers, fill=.!50, opacity=0.6] table[x=x, y=radialcategories] {\dataA}; +\addlegendentry{radial categories} +\end{polaraxis} +\end{tikzpicture} diff --git a/tests/test_polar/test_polar_categorical_radialcategories_reference.tex b/tests/test_polar/test_polar_categorical_radialcategories_reference.tex new file mode 100644 index 0000000..330d7b4 --- /dev/null +++ b/tests/test_polar/test_polar_categorical_radialcategories_reference.tex @@ -0,0 +1,21 @@ +\pgfplotstableread{ +x radialcategories(w/categorydescending) +45 a +90 b +180 c +200 d +300 b +15 f +20 a +45 a +}\dataA + +\begin{tikzpicture} +\begin{polaraxis}[ +symbolic y coords={f,d,c,b,a}, +ytick=data +] +\addplot+ [no markers, fill=.!50, opacity=0.6] table[x=x, y=radialcategories(w/categorydescending)] {\dataA}; +\addlegendentry{radial categories (w/ category descending)} +\end{polaraxis} +\end{tikzpicture} diff --git a/tests/test_polar/test_polar_radar_1_reference.tex b/tests/test_polar/test_polar_radar_1_reference.tex new file mode 100644 index 0000000..21e76bf --- /dev/null +++ b/tests/test_polar/test_polar_radar_1_reference.tex @@ -0,0 +1,25 @@ +\pgfplotstableread{ +x y0 +0.0 1 +72.0 5 +144.0 2 +216.0 2 +288.0 3 +0.0 1 +}\dataA + +\begin{tikzpicture} + +\definecolor{636efa}{HTML}{636efa} + +\begin{polaraxis}[ +rotate=90, +xticklabel style={anchor=90-\tick+180}, +yticklabel style={anchor=\tick-90-90}, +y dir=reverse, +xtick={0.0,72.0,144.0,216.0,288.0}, +xticklabels={processing cost,mechanical properties,chemical stability,thermal stability,device integration} +] +\addplot+ [no markers, color=636efa] table[x=x, y=y0] {\dataA}; +\end{polaraxis} +\end{tikzpicture} diff --git a/tests/test_polar/test_polar_radar_2_reference.tex b/tests/test_polar/test_polar_radar_2_reference.tex new file mode 100644 index 0000000..6ef6087 --- /dev/null +++ b/tests/test_polar/test_polar_radar_2_reference.tex @@ -0,0 +1,79 @@ +\pgfplotstableread{ +x Figure8 Cardioid Hypercardioid +0 1.0 1.0 1.0 +6 0.995 0.997 0.996 +12 0.978 0.989 0.984 +18 0.951 0.976 0.963 +24 0.914 0.957 0.935 +30 0.866 0.933 0.9 +36 0.809 0.905 0.857 +42 0.743 0.872 0.807 +48 0.669 0.835 0.752 +54 0.588 0.794 0.691 +60 0.5 0.75 0.625 +66 0.407 0.703 0.555 +72 0.309 0.655 0.482 +78 0.208 0.604 0.406 +84 0.105 0.552 0.328 +90 0.105 0.5 0.25 +96 0.208 0.448 0.172 +102 0.309 0.396 0.094 +108 0.407 0.345 0.018 +114 0.5 0.297 0.055 +120 0.588 0.25 0.125 +126 0.669 0.206 0.191 +132 0.743 0.165 0.252 +138 0.809 0.128 0.307 +144 0.866 0.095 0.357 +150 0.914 0.067 0.4 +156 0.951 0.043 0.435 +162 0.978 0.024 0.463 +168 0.995 0.011 0.484 +174 1.0 0.003 0.496 +180 0.995 0.0 0.5 +186 0.978 0.003 0.496 +192 0.951 0.011 0.484 +198 0.914 0.024 0.463 +204 0.866 0.043 0.435 +210 0.809 0.067 0.4 +216 0.743 0.095 0.357 +222 0.669 0.128 0.307 +228 0.588 0.165 0.252 +234 0.5 0.206 0.191 +240 0.407 0.25 0.125 +246 0.309 0.297 0.055 +252 0.208 0.345 0.018 +258 0.105 0.396 0.094 +264 0.0 0.448 0.172 +270 0.105 0.5 0.25 +276 0.208 0.552 0.328 +282 0.309 0.604 0.406 +288 0.407 0.655 0.482 +294 0.5 0.703 0.555 +300 0.588 0.75 0.625 +306 0.669 0.794 0.691 +312 0.743 0.835 0.752 +318 0.809 0.872 0.807 +324 0.866 0.905 0.857 +330 0.914 0.933 0.9 +336 0.951 0.957 0.935 +342 0.978 0.976 0.963 +348 0.995 0.989 0.984 +354 1.0 0.997 0.996 +360 1.0 1.0 1.0 +}\dataA + +\begin{tikzpicture} + +\definecolor{darkviolet}{RGB}{148, 0, 211} +\definecolor{deepskyblue}{RGB}{0, 191, 255} +\definecolor{peru}{RGB}{205, 133, 63} + +\begin{polaraxis}[ +title=Basic Polar Chart +] +\addplot+ [no markers, color=peru] table[x=x, y=Figure8] {\dataA}; +\addplot+ [no markers, color=darkviolet, line width=2] table[x=x, y=Cardioid] {\dataA}; +\addplot+ [no markers, color=deepskyblue] table[x=x, y=Hypercardioid] {\dataA}; +\end{polaraxis} +\end{tikzpicture} diff --git a/tests/test_polar/test_polar_radar_range_1_reference.tex b/tests/test_polar/test_polar_radar_range_1_reference.tex new file mode 100644 index 0000000..19c5667 --- /dev/null +++ b/tests/test_polar/test_polar_radar_range_1_reference.tex @@ -0,0 +1,27 @@ +\pgfplotstableread{ +x y0 +0 0 +10 10 +20 20 +30 30 +40 40 +50 50 +60 60 +70 70 +80 80 +}\dataA + +\begin{tikzpicture} + +\definecolor{636efa}{HTML}{636efa} + +\begin{polaraxis}[ +rotate=0, +xticklabel style={anchor=\tick+0+180}, +yticklabel style={anchor=\tick-0-90}, +xmin=0, +xmax=90 +] +\addplot+ [only marks, color=636efa, mark options={solid, fill=636efa}] table[x=x, y=y0] {\dataA}; +\end{polaraxis} +\end{tikzpicture} diff --git a/tests/test_polar/test_polar_radar_range_2_reference.tex b/tests/test_polar/test_polar_radar_range_2_reference.tex new file mode 100644 index 0000000..52eee34 --- /dev/null +++ b/tests/test_polar/test_polar_radar_range_2_reference.tex @@ -0,0 +1,16 @@ +\pgfplotstableread{ +x y0 +0 3 +45 3 +90 4 +270 3 +}\dataA + +\begin{tikzpicture} +\begin{polaraxis}[ +ymin=0, +ymax=6 +] +\addplot+ [no markers, fill=.!50, opacity=0.6] table[x=x, y=y0] {\dataA}; +\end{polaraxis} +\end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_10_reference.tex b/tests/test_scatter/test_scatter_10_reference.tex index 5f928aa..f3cc525 100644 --- a/tests/test_scatter/test_scatter_10_reference.tex +++ b/tests/test_scatter/test_scatter_10_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 Australia New_Zealand +\pgfplotstableread{ +x Australia NewZealand 1952 69.12 69.39 1957 70.33 70.26 1962 70.93 71.24 @@ -11,7 +12,7 @@ 1997 78.83 77.55 2002 80.37 79.11 2007 81.235 80.204 -}\dataZ +}\dataA \begin{tikzpicture} @@ -24,9 +25,9 @@ xlabel=year, ylabel=lifeExp ] -\addplot+ [mark=*, solid, color=636efa] table[y=Australia] {\dataZ}; +\addplot+ [mark=*, solid, color=636efa] table[y=Australia] {\dataA}; \addlegendentry{Australia} -\addplot+ [mark=*, solid, color=EF553B] table[y=New_Zealand] {\dataZ}; +\addplot+ [mark=*, solid, color=EF553B] table[y=NewZealand] {\dataA}; \addlegendentry{New Zealand} \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_1_reference.tex b/tests/test_scatter/test_scatter_1_reference.tex index 28af129..0e26cca 100644 --- a/tests/test_scatter/test_scatter_1_reference.tex +++ b/tests/test_scatter/test_scatter_1_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 Australia New_Zealand +\pgfplotstableread{ +x Australia NewZealand 1952 69.12 69.39 1957 70.33 70.26 1962 70.93 71.24 @@ -11,7 +12,7 @@ 1997 78.83 77.55 2002 80.37 79.11 2007 81.235 80.204 -}\dataZ +}\dataA \begin{tikzpicture} @@ -22,9 +23,9 @@ xlabel=year, ylabel=lifeExp ] -\addplot+ [mark=*, solid, color=636efa] table[y=Australia] {\dataZ}; +\addplot+ [mark=*, solid, color=636efa] table[y=Australia] {\dataA}; \addlegendentry{Australia} -\addplot+ [mark=*, solid, color=EF553B] table[y=New_Zealand] {\dataZ}; +\addplot+ [mark=*, solid, color=EF553B] table[y=NewZealand] {\dataA}; \addlegendentry{New Zealand} \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_2_reference.tex b/tests/test_scatter/test_scatter_2_reference.tex index a430911..cdf37c2 100644 --- a/tests/test_scatter/test_scatter_2_reference.tex +++ b/tests/test_scatter/test_scatter_2_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 Botswana +\pgfplotstableread{ +x Botswana 47.622 851.2411407 49.618 918.2325349 51.52 983.6539764 @@ -11,8 +12,9 @@ 52.556 8647.142313 46.63399999999999 11003.60508 50.728 12569.85177 -}\dataZ -\pgfplotstableread{data1 Canada +}\dataA +\pgfplotstableread{ +x Canada 68.75 11367.16112 69.96 12489.95006 71.3 13462.48555 @@ -25,7 +27,7 @@ 78.61 28954.92589 79.77 33328.96507 80.653 36319.23501 -}\dataO +}\dataB \begin{tikzpicture} @@ -36,7 +38,7 @@ xlabel=lifeExp, ylabel=gdpPercap ] -\addplot+ [mark=*, solid, color=636efa] table[y=Botswana] {\dataZ}; +\addplot+ [mark=*, solid, color=636efa] table[y=Botswana] {\dataA}; \node at (axis cs:47.622,851.2411407) {1952}; \node at (axis cs:49.618,918.2325349) {1957}; \node at (axis cs:51.52,983.6539764) {1962}; @@ -50,7 +52,7 @@ \node at (axis cs:46.63399999999999,11003.60508) {2002}; \node at (axis cs:50.728,12569.85177) {2007}; \addlegendentry{Botswana} -\addplot+ [mark=*, solid, color=EF553B] table[y=Canada] {\dataO}; +\addplot+ [mark=*, solid, color=EF553B] table[y=Canada] {\dataB}; \node at (axis cs:68.75,11367.16112) {1952}; \node at (axis cs:69.96,12489.95006) {1957}; \node at (axis cs:71.3,13462.48555) {1962}; diff --git a/tests/test_scatter/test_scatter_3_reference.tex b/tests/test_scatter/test_scatter_3_reference.tex index b3e1e53..c0603e2 100644 --- a/tests/test_scatter/test_scatter_3_reference.tex +++ b/tests/test_scatter/test_scatter_3_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 0 0 1 1 2 4 @@ -9,10 +10,10 @@ 7 49 8 64 9 81 -}\dataZ +}\dataA \begin{tikzpicture} \begin{axis} -\addplot+ table[y=y0] {\dataZ}; +\addplot+ table[y=y0] {\dataA}; \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_4_reference.tex b/tests/test_scatter/test_scatter_4_reference.tex index cd89e0e..525c285 100644 --- a/tests/test_scatter/test_scatter_4_reference.tex +++ b/tests/test_scatter/test_scatter_4_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 Television Newspaper Internet Radio +\pgfplotstableread{ +x Television Newspaper Internet Radio 2001 74 45 13 18 2002 82 42 14 21 2003 80 50 20 18 @@ -11,11 +12,12 @@ 2010 66 31 41 16 2011 66 31 43 19 2012 69 28 50 23 -}\dataZ -\pgfplotstableread{data1 y0 y1 y2 y3 +}\dataA +\pgfplotstableread{ +x y0 y1 y2 y3 2001 74 45 13 18 2012 69 28 50 23 -}\dataO +}\dataB \begin{tikzpicture} @@ -32,14 +34,14 @@ axis background/.style={fill=white}, clip=false ] -\addplot+ [mark=none, line width=1.5, color=6fb95895bc] table[y=Television] {\dataZ}; -\addplot+ [only marks, mark size=3, mark options={solid, fill=6fb95895bc}] table[y=y0] {\dataO}; -\addplot+ [mark=none, line width=1.5, color=9b5dacb44d] table[y=Newspaper] {\dataZ}; -\addplot+ [only marks, mark size=3, mark options={solid, fill=9b5dacb44d}] table[y=y1] {\dataO}; -\addplot+ [mark=none, line width=3, color=8b7c4ec1c1] table[y=Internet] {\dataZ}; -\addplot+ [only marks, mark size=4.5, mark options={solid, fill=8b7c4ec1c1}] table[y=y2] {\dataO}; -\addplot+ [mark=none, line width=1.5, color=9f6fd82da0] table[y=Radio] {\dataZ}; -\addplot+ [only marks, mark size=3, mark options={solid, fill=9f6fd82da0}] table[y=y3] {\dataO}; +\addplot+ [mark=none, line width=1.5, color=6fb95895bc] table[y=Television] {\dataA}; +\addplot+ [only marks, mark size=3, mark options={solid, fill=6fb95895bc}] table[y=y0] {\dataB}; +\addplot+ [mark=none, line width=1.5, color=9b5dacb44d] table[y=Newspaper] {\dataA}; +\addplot+ [only marks, mark size=3, mark options={solid, fill=9b5dacb44d}] table[y=y1] {\dataB}; +\addplot+ [mark=none, line width=3, color=8b7c4ec1c1] table[y=Internet] {\dataA}; +\addplot+ [only marks, mark size=4.5, mark options={solid, fill=8b7c4ec1c1}] table[y=y2] {\dataB}; +\addplot+ [mark=none, line width=1.5, color=9f6fd82da0] table[y=Radio] {\dataA}; +\addplot+ [only marks, mark size=3, mark options={solid, fill=9f6fd82da0}] table[y=y3] {\dataB}; \node[anchor= east] at (axis cs:\pgfkeysvalueof{/pgfplots/xmin} + 0.05*\pgfkeysvalueof{/pgfplots/xmax}-0.05*\pgfkeysvalueof{/pgfplots/xmin}, 74) {Television 74\%}; \node[anchor= west] at (axis cs:\pgfkeysvalueof{/pgfplots/xmin} + 0.95*\pgfkeysvalueof{/pgfplots/xmax}-0.95*\pgfkeysvalueof{/pgfplots/xmin}, 69) {69\%}; \node[anchor= east] at (axis cs:\pgfkeysvalueof{/pgfplots/xmin} + 0.05*\pgfkeysvalueof{/pgfplots/xmax}-0.05*\pgfkeysvalueof{/pgfplots/xmin}, 45) {Newspaper 45\%}; diff --git a/tests/test_scatter/test_scatter_5_reference.tex b/tests/test_scatter/test_scatter_5_reference.tex index b90e837..d905af4 100644 --- a/tests/test_scatter/test_scatter_5_reference.tex +++ b/tests/test_scatter/test_scatter_5_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 2018-01-01 1.0 2018-01-08 1.018172278347936 2018-01-15 1.032007866452698 @@ -104,17 +105,19 @@ 2019-12-16 1.22441776261611 2019-12-23 1.2265044859331442 2019-12-30 1.213013658002661 -}\dataZ +}\dataA \begin{tikzpicture} \definecolor{636efa}{HTML}{636efa} \begin{axis}[ +symbolic x coords={2018-01-01,2018-01-08,2018-01-15,2018-01-22,2018-01-29,2018-02-05,2018-02-12,2018-02-19,2018-02-26,2018-03-05,2018-03-12,2018-03-19,2018-03-26,2018-04-02,2018-04-09,2018-04-16,2018-04-23,2018-04-30,2018-05-07,2018-05-14,2018-05-21,2018-05-28,2018-06-04,2018-06-11,2018-06-18,2018-06-25,2018-07-02,2018-07-09,2018-07-16,2018-07-23,2018-07-30,2018-08-06,2018-08-13,2018-08-20,2018-08-27,2018-09-03,2018-09-10,2018-09-17,2018-09-24,2018-10-01,2018-10-08,2018-10-15,2018-10-22,2018-10-29,2018-11-05,2018-11-12,2018-11-19,2018-11-26,2018-12-03,2018-12-10,2018-12-17,2018-12-24,2018-12-31,2019-01-07,2019-01-14,2019-01-21,2019-01-28,2019-02-04,2019-02-11,2019-02-18,2019-02-25,2019-03-04,2019-03-11,2019-03-18,2019-03-25,2019-04-01,2019-04-08,2019-04-15,2019-04-22,2019-04-29,2019-05-06,2019-05-13,2019-05-20,2019-05-27,2019-06-03,2019-06-10,2019-06-17,2019-06-24,2019-07-01,2019-07-08,2019-07-15,2019-07-22,2019-07-29,2019-08-05,2019-08-12,2019-08-19,2019-08-26,2019-09-02,2019-09-09,2019-09-16,2019-09-23,2019-09-30,2019-10-07,2019-10-14,2019-10-21,2019-10-28,2019-11-04,2019-11-11,2019-11-18,2019-11-25,2019-12-02,2019-12-09,2019-12-16,2019-12-23,2019-12-30}, +xtick=data, date coordinates in=x, xlabel=date, ylabel=GOOG ] -\addplot+ [mark=none, solid, color=636efa, forget plot] table[y=y0] {\dataZ}; +\addplot+ [mark=none, solid, color=636efa, forget plot] table[y=y0] {\dataA}; \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_6_False_True_reference.tex b/tests/test_scatter/test_scatter_6_False_True_reference.tex index 17ec700..5f454d5 100644 --- a/tests/test_scatter/test_scatter_6_False_True_reference.tex +++ b/tests/test_scatter/test_scatter_6_False_True_reference.tex @@ -1,10 +1,11 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 0 0 1 1 2 2 3 3 4 4 -}\dataZ +}\dataA \begin{tikzpicture} @@ -14,6 +15,6 @@ xlabel=x, ylabel=y ] -\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataZ}; +\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataA}; \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_6_True_False_reference.tex b/tests/test_scatter/test_scatter_6_True_False_reference.tex index 275c1bb..78f926d 100644 --- a/tests/test_scatter/test_scatter_6_True_False_reference.tex +++ b/tests/test_scatter/test_scatter_6_True_False_reference.tex @@ -1,10 +1,11 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 0 0 1 1 2 4 3 9 4 16 -}\dataZ +}\dataA \begin{tikzpicture} @@ -14,6 +15,6 @@ xlabel=x, ylabel=y ] -\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataZ}; +\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataA}; \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_7_reference.tex b/tests/test_scatter/test_scatter_7_reference.tex index 5e5656b..2baf1e0 100644 --- a/tests/test_scatter/test_scatter_7_reference.tex +++ b/tests/test_scatter/test_scatter_7_reference.tex @@ -1,17 +1,18 @@ -\pgfplotstableread{data0 High_2014 Low_2014 High_2007 Low_2007 High_2000 Low_2000 -1 28.8 12.7 36.5 23.6 32.5 13.8 -2 28.5 14.3 26.6 14.0 37.6 22.3 -3 37.0 18.6 43.6 27.0 49.9 32.5 -4 56.8 35.5 52.3 36.8 53.0 37.2 -5 69.7 49.9 71.5 47.6 69.1 49.9 -6 79.7 58.0 81.4 57.7 75.4 56.1 -7 78.5 60.0 80.5 58.9 76.5 57.7 -8 77.8 58.6 82.2 61.2 76.6 58.3 -9 74.1 51.7 76.0 53.3 70.7 51.2 -10 62.6 45.2 67.3 48.5 60.6 42.8 -11 45.3 32.2 46.1 31.0 45.1 31.6 -12 39.9 29.1 35.0 23.6 29.3 15.9 -}\dataZ +\pgfplotstableread{ +x High2014 Low2014 High2007 Low2007 High2000 Low2000 +January 28.8 12.7 36.5 23.6 32.5 13.8 +February 28.5 14.3 26.6 14.0 37.6 22.3 +March 37.0 18.6 43.6 27.0 49.9 32.5 +April 56.8 35.5 52.3 36.8 53.0 37.2 +May 69.7 49.9 71.5 47.6 69.1 49.9 +June 79.7 58.0 81.4 57.7 75.4 56.1 +July 78.5 60.0 80.5 58.9 76.5 57.7 +August 77.8 58.6 82.2 61.2 76.6 58.3 +September 74.1 51.7 76.0 53.3 70.7 51.2 +October 62.6 45.2 67.3 48.5 60.6 42.8 +November 45.3 32.2 46.1 31.0 45.1 31.6 +December 39.9 29.1 35.0 23.6 29.3 15.9 +}\dataA \begin{tikzpicture} @@ -19,22 +20,24 @@ \definecolor{royalblue}{RGB}{65, 105, 225} \begin{axis}[ +symbolic x coords={January,February,March,April,May,June,July,August,September,October,November,December}, +xtick=data, xticklabels={January, February, March, April, May, June, July, August, September, October, November, December}, title=Average High and Low Temperatures in New York, xlabel=Month, ylabel=Temperature (degrees F) ] -\addplot+ [line width=1.125, color=firebrick] table[y=High_2014] {\dataZ}; +\addplot+ [line width=1.125, color=firebrick] table[y=High2014] {\dataA}; \addlegendentry{High 2014} -\addplot+ [line width=1.125, color=royalblue] table[y=Low_2014] {\dataZ}; +\addplot+ [line width=1.125, color=royalblue] table[y=Low2014] {\dataA}; \addlegendentry{Low 2014} -\addplot+ [line width=1.125, dashed, color=firebrick] table[y=High_2007] {\dataZ}; +\addplot+ [line width=1.125, dashed, color=firebrick] table[y=High2007] {\dataA}; \addlegendentry{High 2007} -\addplot+ [line width=1.125, dashed, color=royalblue] table[y=Low_2007] {\dataZ}; +\addplot+ [line width=1.125, dashed, color=royalblue] table[y=Low2007] {\dataA}; \addlegendentry{Low 2007} -\addplot+ [line width=1.125, dotted, color=firebrick] table[y=High_2000] {\dataZ}; +\addplot+ [line width=1.125, dotted, color=firebrick] table[y=High2000] {\dataA}; \addlegendentry{High 2000} -\addplot+ [line width=1.125, dotted, color=royalblue] table[y=Low_2000] {\dataZ}; +\addplot+ [line width=1.125, dotted, color=royalblue] table[y=Low2000] {\dataA}; \addlegendentry{Low 2000} \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_8_reference.tex b/tests/test_scatter/test_scatter_8_reference.tex index 981db8b..053d770 100644 --- a/tests/test_scatter/test_scatter_8_reference.tex +++ b/tests/test_scatter/test_scatter_8_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 974.5803384 43.828 5937.029525999998 76.423 6223.367465 72.301 @@ -141,7 +142,7 @@ 2280.769906 62.698 1271.211593 42.38399999999999 469.70929810000007 43.487 -}\dataZ +}\dataA \begin{tikzpicture} @@ -161,6 +162,6 @@ xlabel=gdpPercap, ylabel=lifeExp ] -\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataZ}; +\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataA}; \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_9_reference.tex b/tests/test_scatter/test_scatter_9_reference.tex index 0c412ab..481e671 100644 --- a/tests/test_scatter/test_scatter_9_reference.tex +++ b/tests/test_scatter/test_scatter_9_reference.tex @@ -1,4 +1,5 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 5.836039190663969 0.40841700265768377 1.4920592434019648 1.4724129208622037 2.661095776728801 0.6000122918441767 @@ -49,7 +50,7 @@ 2.176004410404423 5.964769984228198 0.19910999912356603 1.1353172107281377 0.8083660586147164 1.4947954331172004 -}\dataZ +}\dataA \begin{tikzpicture} @@ -61,6 +62,6 @@ xmode=log, ymode=log ] -\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataZ}; +\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataA}; \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_transparent_color_reference.tex b/tests/test_scatter/test_scatter_transparent_color_reference.tex index 3e81744..84ddc6d 100644 --- a/tests/test_scatter/test_scatter_transparent_color_reference.tex +++ b/tests/test_scatter/test_scatter_transparent_color_reference.tex @@ -1,10 +1,11 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 0 0 1 1 2 4 3 9 4 16 -}\dataZ +}\dataA \begin{tikzpicture} @@ -14,6 +15,6 @@ xlabel=x, ylabel=y ] -\addplot+ [mark=*, only marks, mark options={solid, fill=636efa, opacity=0.5}, forget plot] table[y=y0] {\dataZ}; +\addplot+ [mark=*, only marks, mark options={solid, fill=636efa, opacity=0.5}, forget plot] table[y=y0] {\dataA}; \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter/test_scatter_transparent_color_rgba_reference.tex b/tests/test_scatter/test_scatter_transparent_color_rgba_reference.tex index 3e81744..84ddc6d 100644 --- a/tests/test_scatter/test_scatter_transparent_color_rgba_reference.tex +++ b/tests/test_scatter/test_scatter_transparent_color_rgba_reference.tex @@ -1,10 +1,11 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 0 0 1 1 2 4 3 9 4 16 -}\dataZ +}\dataA \begin{tikzpicture} @@ -14,6 +15,6 @@ xlabel=x, ylabel=y ] -\addplot+ [mark=*, only marks, mark options={solid, fill=636efa, opacity=0.5}, forget plot] table[y=y0] {\dataZ}; +\addplot+ [mark=*, only marks, mark options={solid, fill=636efa, opacity=0.5}, forget plot] table[y=y0] {\dataA}; \end{axis} \end{tikzpicture} diff --git a/tests/test_scatter3d.py b/tests/test_scatter3d.py new file mode 100644 index 0000000..55f4349 --- /dev/null +++ b/tests/test_scatter3d.py @@ -0,0 +1,100 @@ +""" +Test of 3D scatter plots https://plotly.com/python/3d-scatter-plots/ +""" +import os, pathlib +import plotly.express as px +import plotly.graph_objects as go +import numpy as np +import pytest +from .helpers import assert_equality + +this_dir = pathlib.Path(__file__).resolve().parent +test_name = "test_scatter3d" + +def plot_scatter_3d_1(): + df = px.data.iris() + fig = px.scatter_3d(df, x='sepal_length', y='sepal_width', z='petal_width', color='species') + return fig + +def plot_scatter_3d_2(mode): + t = np.linspace(0, 20, 100) + x, y, z = np.cos(t), np.sin(t), t + + fig = go.Figure(data=[go.Scatter3d( + x=x, + y=y, + z=z, + mode=mode, + marker=dict( + size=12, + color=z, # set color to an array/list of desired values + colorscale='Viridis', # choose a colorscale + opacity=0.8, + symbol="diamond" + ), + )]) + fig.update_layout(margin=dict(l=0, r=0, b=0, t=0)) + return fig + +def plot_scatter_3d_3(): + t = np.linspace(0, 20, 100) + x, y, z = np.cos(t), np.sin(t), t + + fig = go.Figure(data=[go.Scatter3d( + x=x, + y=y, + z=z, + mode='lines', + line=dict( + color='darkblue', + width=4 + ), + showlegend=False + )]) + fig.update_layout(margin=dict(l=0, r=0, b=0, t=0)) + return fig + +def plot_scatter_3d_view(): + fig = go.Figure(data=[go.Scatter3d( + x=[1, 2, 3], + y=[4, 5, 6], + z=[7, 8, 9], + mode='markers', + marker=dict(size=6, color='red') + )]) + fig.update_layout( + scene=dict( + camera=dict( + eye=dict(x=1.5, y=1.5, z=0.5) + ), + xaxis=dict(showgrid=False), + yaxis=dict(showgrid=False), + zaxis=dict(showgrid=False) + ), + margin=dict(l=0, r=0, b=0, t=0) + ) + return fig + + +def plot_scatter_3d_empty(): + return go.Figure(data=[go.Scatter3d( + x=None, + y=None, + z=None, + )]) + +def test_scatter_3d_1(): + assert_equality(plot_scatter_3d_1(), os.path.join(this_dir, test_name, test_name + "_1_reference.tex")) + +@pytest.mark.parametrize("mode", ["markers", "markers+lines", "lines"]) +def test_scatter_3d_2(mode): + assert_equality(plot_scatter_3d_2(mode), os.path.join(this_dir, test_name, test_name + f"_2_{mode}_reference.tex")) + +def test_scatter_3d_3(): + assert_equality(plot_scatter_3d_3(), os.path.join(this_dir, test_name, test_name + "_3_reference.tex")) + +def test_scatter_3d_view(): + assert_equality(plot_scatter_3d_view(), os.path.join(this_dir, test_name, test_name + "_view_reference.tex")) + +def test_scatter_3d_empty(): + assert_equality(plot_scatter_3d_empty(), os.path.join(this_dir, test_name, test_name + "_empty_reference.tex")) diff --git a/tests/test_scatter3d/test_scatter3d_1_reference.tex b/tests/test_scatter3d/test_scatter3d_1_reference.tex new file mode 100644 index 0000000..b10e77c --- /dev/null +++ b/tests/test_scatter3d/test_scatter3d_1_reference.tex @@ -0,0 +1,185 @@ +\pgfplotstableread{ +x y z +5.1 3.5 0.2 +4.9 3.0 0.2 +4.7 3.2 0.2 +4.6 3.1 0.2 +5.0 3.6 0.2 +5.4 3.9 0.4 +4.6 3.4 0.3 +5.0 3.4 0.2 +4.4 2.9 0.2 +4.9 3.1 0.1 +5.4 3.7 0.2 +4.8 3.4 0.2 +4.8 3.0 0.1 +4.3 3.0 0.1 +5.8 4.0 0.2 +5.7 4.4 0.4 +5.4 3.9 0.4 +5.1 3.5 0.3 +5.7 3.8 0.3 +5.1 3.8 0.3 +5.4 3.4 0.2 +5.1 3.7 0.4 +4.6 3.6 0.2 +5.1 3.3 0.5 +4.8 3.4 0.2 +5.0 3.0 0.2 +5.0 3.4 0.4 +5.2 3.5 0.2 +5.2 3.4 0.2 +4.7 3.2 0.2 +4.8 3.1 0.2 +5.4 3.4 0.4 +5.2 4.1 0.1 +5.5 4.2 0.2 +4.9 3.1 0.1 +5.0 3.2 0.2 +5.5 3.5 0.2 +4.9 3.1 0.1 +4.4 3.0 0.2 +5.1 3.4 0.2 +5.0 3.5 0.3 +4.5 2.3 0.3 +4.4 3.2 0.2 +5.0 3.5 0.6 +5.1 3.8 0.4 +4.8 3.0 0.3 +5.1 3.8 0.2 +4.6 3.2 0.2 +5.3 3.7 0.2 +5.0 3.3 0.2 +}{\setosa} +\pgfplotstableread{ +x y z +7.0 3.2 1.4 +6.4 3.2 1.5 +6.9 3.1 1.5 +5.5 2.3 1.3 +6.5 2.8 1.5 +5.7 2.8 1.3 +6.3 3.3 1.6 +4.9 2.4 1.0 +6.6 2.9 1.3 +5.2 2.7 1.4 +5.0 2.0 1.0 +5.9 3.0 1.5 +6.0 2.2 1.0 +6.1 2.9 1.4 +5.6 2.9 1.3 +6.7 3.1 1.4 +5.6 3.0 1.5 +5.8 2.7 1.0 +6.2 2.2 1.5 +5.6 2.5 1.1 +5.9 3.2 1.8 +6.1 2.8 1.3 +6.3 2.5 1.5 +6.1 2.8 1.2 +6.4 2.9 1.3 +6.6 3.0 1.4 +6.8 2.8 1.4 +6.7 3.0 1.7 +6.0 2.9 1.5 +5.7 2.6 1.0 +5.5 2.4 1.1 +5.5 2.4 1.0 +5.8 2.7 1.2 +6.0 2.7 1.6 +5.4 3.0 1.5 +6.0 3.4 1.6 +6.7 3.1 1.5 +6.3 2.3 1.3 +5.6 3.0 1.3 +5.5 2.5 1.3 +5.5 2.6 1.2 +6.1 3.0 1.4 +5.8 2.6 1.2 +5.0 2.3 1.0 +5.6 2.7 1.3 +5.7 3.0 1.2 +5.7 2.9 1.3 +6.2 2.9 1.3 +5.1 2.5 1.1 +5.7 2.8 1.3 +}{\versicolor} +\pgfplotstableread{ +x y z +6.3 3.3 2.5 +5.8 2.7 1.9 +7.1 3.0 2.1 +6.3 2.9 1.8 +6.5 3.0 2.2 +7.6 3.0 2.1 +4.9 2.5 1.7 +7.3 2.9 1.8 +6.7 2.5 1.8 +7.2 3.6 2.5 +6.5 3.2 2.0 +6.4 2.7 1.9 +6.8 3.0 2.1 +5.7 2.5 2.0 +5.8 2.8 2.4 +6.4 3.2 2.3 +6.5 3.0 1.8 +7.7 3.8 2.2 +7.7 2.6 2.3 +6.0 2.2 1.5 +6.9 3.2 2.3 +5.6 2.8 2.0 +7.7 2.8 2.0 +6.3 2.7 1.8 +6.7 3.3 2.1 +7.2 3.2 1.8 +6.2 2.8 1.8 +6.1 3.0 1.8 +6.4 2.8 2.1 +7.2 3.0 1.6 +7.4 2.8 1.9 +7.9 3.8 2.0 +6.4 2.8 2.2 +6.3 2.8 1.5 +6.1 2.6 1.4 +7.7 3.0 2.3 +6.3 3.4 2.4 +6.4 3.1 1.8 +6.0 3.0 1.8 +6.9 3.1 2.1 +6.7 3.1 2.4 +6.9 3.1 2.3 +5.8 2.7 1.9 +6.8 3.2 2.3 +6.7 3.3 2.5 +6.7 3.0 2.3 +6.3 2.5 1.9 +6.5 3.0 2.0 +6.2 3.4 2.3 +5.9 3.0 1.8 +}{\virginica} + +\begin{tikzpicture} + +\definecolor{00cc96}{HTML}{00cc96} +\definecolor{636efa}{HTML}{636efa} +\definecolor{EF553B}{HTML}{EF553B} + +\begin{axis}[ +xlabel={sepal\_length}, +ylabel={sepal\_width}, +zlabel={petal\_width} +] + +% setosa +\addplot3+ [mark=*, only marks, mark options={solid, fill=636efa}] table[x=x, y=y, z=z] {\setosa}; +\addlegendentry{setosa} + +% versicolor +\addplot3+ [mark=*, only marks, mark options={solid, fill=EF553B}] table[x=x, y=y, z=z] {\versicolor}; +\addlegendentry{versicolor} + +% virginica +\addplot3+ [mark=*, only marks, mark options={solid, fill=00cc96}] table[x=x, y=y, z=z] {\virginica}; +\addlegendentry{virginica} +\end{axis} +\end{tikzpicture} diff --git a/tests/test_scatter3d/test_scatter3d_2_lines_reference.tex b/tests/test_scatter3d/test_scatter3d_2_lines_reference.tex new file mode 100644 index 0000000..e2e5bb1 --- /dev/null +++ b/tests/test_scatter3d/test_scatter3d_2_lines_reference.tex @@ -0,0 +1,109 @@ +\pgfplotstableread{ +x y z +1.0 0.0 0.0 +0.9796632259996998 0.2006488565226854 0.20202020202020202 +0.9194800727522776 0.3931366121483298 0.40404040404040403 +0.82189840263017 0.5696341069089657 0.6060606060606061 +0.6908872083770674 0.7229625614794605 0.8080808080808081 +0.5317751800910392 0.8468855636029834 1.0101010101010102 +0.3510339684920502 0.9363627251042848 1.2121212121212122 +0.15601495992575853 0.9877546923600838 1.4141414141414141 +-0.04534973060188524 0.9989711717233568 1.6161616161616161 +-0.24486988668507892 0.9695559491823237 1.8181818181818181 +-0.43443031567828566 0.9007054462029555 2.0202020202020203 +-0.6063209223738354 0.7952200570230491 2.2222222222222223 +-0.7535503059294446 0.6573902466827755 2.4242424242424243 +-0.8701301249459654 0.4928220425889235 2.6262626262626263 +-0.9513186645587279 0.30820901749007684 2.8282828282828283 +-0.993813698804694 0.11106003812412972 3.0303030303030303 +-0.9958868038686729 -0.09060614703340773 3.2323232323232323 +-0.9574536592123347 -0.28858705872043244 3.4343434343434343 +-0.8800774771896732 -0.47483011082223947 3.6363636363636362 +-0.7669054216542901 -0.6417601376193878 3.8383838383838382 +-0.6225406016393301 -0.7825875026542022 4.040404040404041 +-0.45285484658127084 -0.8915842573351402 4.242424242424242 +-0.2647498781834829 -0.9643171169287782 4.444444444444445 +-0.06587659290724678 -0.9978277779792126 4.646464646464646 +0.13567612713271912 -0.9907532430056771 4.848484848484849 +0.33171041770321597 -0.9433812584459996 5.05050505050505 +0.5142528686769626 -0.8576386109880517 5.252525252525253 +0.6758788309121296 -0.7370127583189133 5.454545454545454 +0.810014403075603 -0.586409981847235 5.656565656565657 +0.9112038155344026 -0.4119558308308628 5.858585858585858 +0.9753313358637337 -0.22074597455506334 6.0606060606060606 +0.9997886702873213 -0.020557596287260064 6.262626262626262 +0.983581052239521 0.18046693235991093 6.4646464646464645 +0.9273677030509753 0.37415123057121996 6.666666666666667 +0.8334350190781794 0.5526174707464059 6.8686868686868685 +0.7056035758515253 0.7086067976992182 7.070707070707071 +0.5490727317130796 0.8357745720522589 7.2727272727272725 +0.3702091514654802 0.9289484292312513 7.474747474747475 +0.17628785152548898 0.9843386578838236 7.6767676767676765 +-0.02480370080544784 0.9996923408861117 7.878787878787879 +-0.22488639862108173 0.9743849894755358 8.080808080808081 +-0.41582216870771727 0.9094459434244625 8.282828282828282 +-0.5898449758557073 0.8075165041395626 8.484848484848484 +-0.7398766950653171 0.6727425035622647 8.686868686868687 +-0.859815004003662 0.510605678474283 8.88888888888889 +-0.9447815861050266 0.32770070881349983 9.09090909090909 +-0.9913205490138658 0.13146698864295842 9.292929292929292 +-0.9975389879884077 -0.07011396040064677 9.494949494949495 +-0.9631839770525324 -0.26884312591038406 9.696969696969697 +-0.8896528563926016 -0.45663748763377376 9.8989898989899 +-0.779936397574316 -0.6258587825850161 10.1010101010101 +-0.638497158251875 -0.769624180301191 10.303030303030303 +-0.4710879741150293 -0.8820862319774624 10.505050505050505 +-0.2845179706505102 -0.9586707069567294 10.707070707070708 +-0.08637561184970585 -0.9962626429198221 10.909090909090908 +0.11527994954575044 -0.9933330424549106 11.11111111111111 +0.3122466663798508 -0.9500010628071266 11.313131313131313 +0.4965132034409228 -0.8680291693306353 11.515151515151516 +0.6605847868889071 -0.7507514497694541 11.717171717171716 +0.7977880432989004 -0.6029380050795535 11.919191919191919 +0.9025424294354707 -0.43060093249866344 12.121212121212121 +0.9705872127458185 -0.2407497922206855 12.323232323232324 +0.9991547704697801 -0.04110650371268662 12.525252525252524 +0.9870831586770104 0.1602087321472088 12.727272727272727 +0.9348633726492067 0.3550077104499993 12.929292929292929 +0.8446193763599521 0.5353672656012185 13.131313131313131 +0.7200217133240836 0.6939515345770562 13.333333333333334 +0.5661382125698547 0.8243103325011825 13.535353535353535 +0.38922786205169047 0.9211415045489321 13.737373737373737 +0.19648623340319554 0.9805065833960652 13.93939393939394 +-0.004247187491081489 0.9999909806585335 14.141414141414142 +-0.20480786020107072 0.9788021967690197 14.343434343434343 +-0.3970382705782732 0.9178020547461276 14.545454545454545 +-0.5731197257990347 0.8194716467944692 14.747474747474747 +-0.7258903683424182 0.6878104194817846 14.94949494949495 +-0.8491364741458517 0.5281735020569958 15.15151515151515 +-0.9378451868090543 0.3470538943436452 15.353535353535353 +-0.9884084082494465 0.15181837339991294 15.555555555555555 +-0.9987695528527076 -0.04959213944167377 15.757575757575758 +-0.9685071961064762 -0.24898556401922536 15.959595959595958 +-0.8988522154304799 -0.43825186230718777 16.161616161616163 +-0.7926377260247273 -0.609692902437243 16.363636363636363 +-0.6541838480224215 -0.7563355690343919 16.565656565656564 +-0.48912199187635547 -0.8722153845598611 16.767676767676768 +-0.30416580891556017 -0.9526191057745708 16.96969696969697 +-0.106838123325693 -0.9942764280642703 17.171717171717173 +0.09483504780155239 -0.9954930003312314 17.373737373737374 +0.29265094105990214 -0.9562193402649591 17.575757575757574 +0.47856368221963436 -0.8780528469633162 17.77777777777778 +0.645011540479259 -0.7641728290436485 17.97979797979798 +0.7852244908862596 -0.6192111908811196 18.18181818181818 +0.8934995752719529 -0.4490640366237758 18.383838383838384 +0.9654328617943044 -0.26065185471747443 18.585858585858585 +0.9980985684711091 -0.06163803708687286 18.78787878787879 +0.9901680651138731 0.13988281820384094 18.98989898989899 +0.9419639134315667 0.3357141429738816 19.19191919191919 +0.8554467473014667 0.5178907824351968 19.393939393939394 +0.7341355268330447 0.6790029662980626 19.595959595959595 +0.5829644097750302 0.8124976904186563 19.7979797979798 +0.40808206181339196 0.9129452507276277 20.0 +}{\dataDFHNIDGLEFPCLNOOILBDMAJGJEBAMDGP} + +\begin{tikzpicture} +\begin{axis} +\addplot3+ [mark=none] table[x=x, y=y, z=z] {\dataDFHNIDGLEFPCLNOOILBDMAJGJEBAMDGP}; +\end{axis} +\end{tikzpicture} diff --git a/tests/test_scatter3d/test_scatter3d_2_markers+lines_reference.tex b/tests/test_scatter3d/test_scatter3d_2_markers+lines_reference.tex new file mode 100644 index 0000000..019173b --- /dev/null +++ b/tests/test_scatter3d/test_scatter3d_2_markers+lines_reference.tex @@ -0,0 +1,109 @@ +\pgfplotstableread{ +x y z +1.0 0.0 0.0 +0.9796632259996998 0.2006488565226854 0.20202020202020202 +0.9194800727522776 0.3931366121483298 0.40404040404040403 +0.82189840263017 0.5696341069089657 0.6060606060606061 +0.6908872083770674 0.7229625614794605 0.8080808080808081 +0.5317751800910392 0.8468855636029834 1.0101010101010102 +0.3510339684920502 0.9363627251042848 1.2121212121212122 +0.15601495992575853 0.9877546923600838 1.4141414141414141 +-0.04534973060188524 0.9989711717233568 1.6161616161616161 +-0.24486988668507892 0.9695559491823237 1.8181818181818181 +-0.43443031567828566 0.9007054462029555 2.0202020202020203 +-0.6063209223738354 0.7952200570230491 2.2222222222222223 +-0.7535503059294446 0.6573902466827755 2.4242424242424243 +-0.8701301249459654 0.4928220425889235 2.6262626262626263 +-0.9513186645587279 0.30820901749007684 2.8282828282828283 +-0.993813698804694 0.11106003812412972 3.0303030303030303 +-0.9958868038686729 -0.09060614703340773 3.2323232323232323 +-0.9574536592123347 -0.28858705872043244 3.4343434343434343 +-0.8800774771896732 -0.47483011082223947 3.6363636363636362 +-0.7669054216542901 -0.6417601376193878 3.8383838383838382 +-0.6225406016393301 -0.7825875026542022 4.040404040404041 +-0.45285484658127084 -0.8915842573351402 4.242424242424242 +-0.2647498781834829 -0.9643171169287782 4.444444444444445 +-0.06587659290724678 -0.9978277779792126 4.646464646464646 +0.13567612713271912 -0.9907532430056771 4.848484848484849 +0.33171041770321597 -0.9433812584459996 5.05050505050505 +0.5142528686769626 -0.8576386109880517 5.252525252525253 +0.6758788309121296 -0.7370127583189133 5.454545454545454 +0.810014403075603 -0.586409981847235 5.656565656565657 +0.9112038155344026 -0.4119558308308628 5.858585858585858 +0.9753313358637337 -0.22074597455506334 6.0606060606060606 +0.9997886702873213 -0.020557596287260064 6.262626262626262 +0.983581052239521 0.18046693235991093 6.4646464646464645 +0.9273677030509753 0.37415123057121996 6.666666666666667 +0.8334350190781794 0.5526174707464059 6.8686868686868685 +0.7056035758515253 0.7086067976992182 7.070707070707071 +0.5490727317130796 0.8357745720522589 7.2727272727272725 +0.3702091514654802 0.9289484292312513 7.474747474747475 +0.17628785152548898 0.9843386578838236 7.6767676767676765 +-0.02480370080544784 0.9996923408861117 7.878787878787879 +-0.22488639862108173 0.9743849894755358 8.080808080808081 +-0.41582216870771727 0.9094459434244625 8.282828282828282 +-0.5898449758557073 0.8075165041395626 8.484848484848484 +-0.7398766950653171 0.6727425035622647 8.686868686868687 +-0.859815004003662 0.510605678474283 8.88888888888889 +-0.9447815861050266 0.32770070881349983 9.09090909090909 +-0.9913205490138658 0.13146698864295842 9.292929292929292 +-0.9975389879884077 -0.07011396040064677 9.494949494949495 +-0.9631839770525324 -0.26884312591038406 9.696969696969697 +-0.8896528563926016 -0.45663748763377376 9.8989898989899 +-0.779936397574316 -0.6258587825850161 10.1010101010101 +-0.638497158251875 -0.769624180301191 10.303030303030303 +-0.4710879741150293 -0.8820862319774624 10.505050505050505 +-0.2845179706505102 -0.9586707069567294 10.707070707070708 +-0.08637561184970585 -0.9962626429198221 10.909090909090908 +0.11527994954575044 -0.9933330424549106 11.11111111111111 +0.3122466663798508 -0.9500010628071266 11.313131313131313 +0.4965132034409228 -0.8680291693306353 11.515151515151516 +0.6605847868889071 -0.7507514497694541 11.717171717171716 +0.7977880432989004 -0.6029380050795535 11.919191919191919 +0.9025424294354707 -0.43060093249866344 12.121212121212121 +0.9705872127458185 -0.2407497922206855 12.323232323232324 +0.9991547704697801 -0.04110650371268662 12.525252525252524 +0.9870831586770104 0.1602087321472088 12.727272727272727 +0.9348633726492067 0.3550077104499993 12.929292929292929 +0.8446193763599521 0.5353672656012185 13.131313131313131 +0.7200217133240836 0.6939515345770562 13.333333333333334 +0.5661382125698547 0.8243103325011825 13.535353535353535 +0.38922786205169047 0.9211415045489321 13.737373737373737 +0.19648623340319554 0.9805065833960652 13.93939393939394 +-0.004247187491081489 0.9999909806585335 14.141414141414142 +-0.20480786020107072 0.9788021967690197 14.343434343434343 +-0.3970382705782732 0.9178020547461276 14.545454545454545 +-0.5731197257990347 0.8194716467944692 14.747474747474747 +-0.7258903683424182 0.6878104194817846 14.94949494949495 +-0.8491364741458517 0.5281735020569958 15.15151515151515 +-0.9378451868090543 0.3470538943436452 15.353535353535353 +-0.9884084082494465 0.15181837339991294 15.555555555555555 +-0.9987695528527076 -0.04959213944167377 15.757575757575758 +-0.9685071961064762 -0.24898556401922536 15.959595959595958 +-0.8988522154304799 -0.43825186230718777 16.161616161616163 +-0.7926377260247273 -0.609692902437243 16.363636363636363 +-0.6541838480224215 -0.7563355690343919 16.565656565656564 +-0.48912199187635547 -0.8722153845598611 16.767676767676768 +-0.30416580891556017 -0.9526191057745708 16.96969696969697 +-0.106838123325693 -0.9942764280642703 17.171717171717173 +0.09483504780155239 -0.9954930003312314 17.373737373737374 +0.29265094105990214 -0.9562193402649591 17.575757575757574 +0.47856368221963436 -0.8780528469633162 17.77777777777778 +0.645011540479259 -0.7641728290436485 17.97979797979798 +0.7852244908862596 -0.6192111908811196 18.18181818181818 +0.8934995752719529 -0.4490640366237758 18.383838383838384 +0.9654328617943044 -0.26065185471747443 18.585858585858585 +0.9980985684711091 -0.06163803708687286 18.78787878787879 +0.9901680651138731 0.13988281820384094 18.98989898989899 +0.9419639134315667 0.3357141429738816 19.19191919191919 +0.8554467473014667 0.5178907824351968 19.393939393939394 +0.7341355268330447 0.6790029662980626 19.595959595959595 +0.5829644097750302 0.8124976904186563 19.7979797979798 +0.40808206181339196 0.9129452507276277 20.0 +}{\dataDFHNIDGLEFPCLNOOILBDMAJGJEBAMDGP} + +\begin{tikzpicture} +\begin{axis} +\addplot3+ [mark=diamond*] table[x=x, y=y, z=z] {\dataDFHNIDGLEFPCLNOOILBDMAJGJEBAMDGP}; +\end{axis} +\end{tikzpicture} diff --git a/tests/test_scatter3d/test_scatter3d_2_markers_reference.tex b/tests/test_scatter3d/test_scatter3d_2_markers_reference.tex new file mode 100644 index 0000000..44b1c57 --- /dev/null +++ b/tests/test_scatter3d/test_scatter3d_2_markers_reference.tex @@ -0,0 +1,112 @@ +\pgfplotstableread{ +x y z +1.0 0.0 0.0 +0.9796632259996998 0.2006488565226854 0.20202020202020202 +0.9194800727522776 0.3931366121483298 0.40404040404040403 +0.82189840263017 0.5696341069089657 0.6060606060606061 +0.6908872083770674 0.7229625614794605 0.8080808080808081 +0.5317751800910392 0.8468855636029834 1.0101010101010102 +0.3510339684920502 0.9363627251042848 1.2121212121212122 +0.15601495992575853 0.9877546923600838 1.4141414141414141 +-0.04534973060188524 0.9989711717233568 1.6161616161616161 +-0.24486988668507892 0.9695559491823237 1.8181818181818181 +-0.43443031567828566 0.9007054462029555 2.0202020202020203 +-0.6063209223738354 0.7952200570230491 2.2222222222222223 +-0.7535503059294446 0.6573902466827755 2.4242424242424243 +-0.8701301249459654 0.4928220425889235 2.6262626262626263 +-0.9513186645587279 0.30820901749007684 2.8282828282828283 +-0.993813698804694 0.11106003812412972 3.0303030303030303 +-0.9958868038686729 -0.09060614703340773 3.2323232323232323 +-0.9574536592123347 -0.28858705872043244 3.4343434343434343 +-0.8800774771896732 -0.47483011082223947 3.6363636363636362 +-0.7669054216542901 -0.6417601376193878 3.8383838383838382 +-0.6225406016393301 -0.7825875026542022 4.040404040404041 +-0.45285484658127084 -0.8915842573351402 4.242424242424242 +-0.2647498781834829 -0.9643171169287782 4.444444444444445 +-0.06587659290724678 -0.9978277779792126 4.646464646464646 +0.13567612713271912 -0.9907532430056771 4.848484848484849 +0.33171041770321597 -0.9433812584459996 5.05050505050505 +0.5142528686769626 -0.8576386109880517 5.252525252525253 +0.6758788309121296 -0.7370127583189133 5.454545454545454 +0.810014403075603 -0.586409981847235 5.656565656565657 +0.9112038155344026 -0.4119558308308628 5.858585858585858 +0.9753313358637337 -0.22074597455506334 6.0606060606060606 +0.9997886702873213 -0.020557596287260064 6.262626262626262 +0.983581052239521 0.18046693235991093 6.4646464646464645 +0.9273677030509753 0.37415123057121996 6.666666666666667 +0.8334350190781794 0.5526174707464059 6.8686868686868685 +0.7056035758515253 0.7086067976992182 7.070707070707071 +0.5490727317130796 0.8357745720522589 7.2727272727272725 +0.3702091514654802 0.9289484292312513 7.474747474747475 +0.17628785152548898 0.9843386578838236 7.6767676767676765 +-0.02480370080544784 0.9996923408861117 7.878787878787879 +-0.22488639862108173 0.9743849894755358 8.080808080808081 +-0.41582216870771727 0.9094459434244625 8.282828282828282 +-0.5898449758557073 0.8075165041395626 8.484848484848484 +-0.7398766950653171 0.6727425035622647 8.686868686868687 +-0.859815004003662 0.510605678474283 8.88888888888889 +-0.9447815861050266 0.32770070881349983 9.09090909090909 +-0.9913205490138658 0.13146698864295842 9.292929292929292 +-0.9975389879884077 -0.07011396040064677 9.494949494949495 +-0.9631839770525324 -0.26884312591038406 9.696969696969697 +-0.8896528563926016 -0.45663748763377376 9.8989898989899 +-0.779936397574316 -0.6258587825850161 10.1010101010101 +-0.638497158251875 -0.769624180301191 10.303030303030303 +-0.4710879741150293 -0.8820862319774624 10.505050505050505 +-0.2845179706505102 -0.9586707069567294 10.707070707070708 +-0.08637561184970585 -0.9962626429198221 10.909090909090908 +0.11527994954575044 -0.9933330424549106 11.11111111111111 +0.3122466663798508 -0.9500010628071266 11.313131313131313 +0.4965132034409228 -0.8680291693306353 11.515151515151516 +0.6605847868889071 -0.7507514497694541 11.717171717171716 +0.7977880432989004 -0.6029380050795535 11.919191919191919 +0.9025424294354707 -0.43060093249866344 12.121212121212121 +0.9705872127458185 -0.2407497922206855 12.323232323232324 +0.9991547704697801 -0.04110650371268662 12.525252525252524 +0.9870831586770104 0.1602087321472088 12.727272727272727 +0.9348633726492067 0.3550077104499993 12.929292929292929 +0.8446193763599521 0.5353672656012185 13.131313131313131 +0.7200217133240836 0.6939515345770562 13.333333333333334 +0.5661382125698547 0.8243103325011825 13.535353535353535 +0.38922786205169047 0.9211415045489321 13.737373737373737 +0.19648623340319554 0.9805065833960652 13.93939393939394 +-0.004247187491081489 0.9999909806585335 14.141414141414142 +-0.20480786020107072 0.9788021967690197 14.343434343434343 +-0.3970382705782732 0.9178020547461276 14.545454545454545 +-0.5731197257990347 0.8194716467944692 14.747474747474747 +-0.7258903683424182 0.6878104194817846 14.94949494949495 +-0.8491364741458517 0.5281735020569958 15.15151515151515 +-0.9378451868090543 0.3470538943436452 15.353535353535353 +-0.9884084082494465 0.15181837339991294 15.555555555555555 +-0.9987695528527076 -0.04959213944167377 15.757575757575758 +-0.9685071961064762 -0.24898556401922536 15.959595959595958 +-0.8988522154304799 -0.43825186230718777 16.161616161616163 +-0.7926377260247273 -0.609692902437243 16.363636363636363 +-0.6541838480224215 -0.7563355690343919 16.565656565656564 +-0.48912199187635547 -0.8722153845598611 16.767676767676768 +-0.30416580891556017 -0.9526191057745708 16.96969696969697 +-0.106838123325693 -0.9942764280642703 17.171717171717173 +0.09483504780155239 -0.9954930003312314 17.373737373737374 +0.29265094105990214 -0.9562193402649591 17.575757575757574 +0.47856368221963436 -0.8780528469633162 17.77777777777778 +0.645011540479259 -0.7641728290436485 17.97979797979798 +0.7852244908862596 -0.6192111908811196 18.18181818181818 +0.8934995752719529 -0.4490640366237758 18.383838383838384 +0.9654328617943044 -0.26065185471747443 18.585858585858585 +0.9980985684711091 -0.06163803708687286 18.78787878787879 +0.9901680651138731 0.13988281820384094 18.98989898989899 +0.9419639134315667 0.3357141429738816 19.19191919191919 +0.8554467473014667 0.5178907824351968 19.393939393939394 +0.7341355268330447 0.6790029662980626 19.595959595959595 +0.5829644097750302 0.8124976904186563 19.7979797979798 +0.40808206181339196 0.9129452507276277 20.0 +}{\dataDFHNIDGLEFPCLNOOILBDMAJGJEBAMDGP} + +\begin{tikzpicture} + +\definecolor{blue}{HTML}{0000ff} + +\begin{axis} +\addplot3+ [mark=diamond*, only marks, mark size=9, mark options={solid, fill=blue, opacity=0.8}] table[x=x, y=y, z=z] {\dataDFHNIDGLEFPCLNOOILBDMAJGJEBAMDGP}; +\end{axis} +\end{tikzpicture} diff --git a/tests/test_scatter3d/test_scatter3d_3_reference.tex b/tests/test_scatter3d/test_scatter3d_3_reference.tex new file mode 100644 index 0000000..c80baa6 --- /dev/null +++ b/tests/test_scatter3d/test_scatter3d_3_reference.tex @@ -0,0 +1,112 @@ +\pgfplotstableread{ +x y z +1.0 0.0 0.0 +0.9796632259996998 0.2006488565226854 0.20202020202020202 +0.9194800727522776 0.3931366121483298 0.40404040404040403 +0.82189840263017 0.5696341069089657 0.6060606060606061 +0.6908872083770674 0.7229625614794605 0.8080808080808081 +0.5317751800910392 0.8468855636029834 1.0101010101010102 +0.3510339684920502 0.9363627251042848 1.2121212121212122 +0.15601495992575853 0.9877546923600838 1.4141414141414141 +-0.04534973060188524 0.9989711717233568 1.6161616161616161 +-0.24486988668507892 0.9695559491823237 1.8181818181818181 +-0.43443031567828566 0.9007054462029555 2.0202020202020203 +-0.6063209223738354 0.7952200570230491 2.2222222222222223 +-0.7535503059294446 0.6573902466827755 2.4242424242424243 +-0.8701301249459654 0.4928220425889235 2.6262626262626263 +-0.9513186645587279 0.30820901749007684 2.8282828282828283 +-0.993813698804694 0.11106003812412972 3.0303030303030303 +-0.9958868038686729 -0.09060614703340773 3.2323232323232323 +-0.9574536592123347 -0.28858705872043244 3.4343434343434343 +-0.8800774771896732 -0.47483011082223947 3.6363636363636362 +-0.7669054216542901 -0.6417601376193878 3.8383838383838382 +-0.6225406016393301 -0.7825875026542022 4.040404040404041 +-0.45285484658127084 -0.8915842573351402 4.242424242424242 +-0.2647498781834829 -0.9643171169287782 4.444444444444445 +-0.06587659290724678 -0.9978277779792126 4.646464646464646 +0.13567612713271912 -0.9907532430056771 4.848484848484849 +0.33171041770321597 -0.9433812584459996 5.05050505050505 +0.5142528686769626 -0.8576386109880517 5.252525252525253 +0.6758788309121296 -0.7370127583189133 5.454545454545454 +0.810014403075603 -0.586409981847235 5.656565656565657 +0.9112038155344026 -0.4119558308308628 5.858585858585858 +0.9753313358637337 -0.22074597455506334 6.0606060606060606 +0.9997886702873213 -0.020557596287260064 6.262626262626262 +0.983581052239521 0.18046693235991093 6.4646464646464645 +0.9273677030509753 0.37415123057121996 6.666666666666667 +0.8334350190781794 0.5526174707464059 6.8686868686868685 +0.7056035758515253 0.7086067976992182 7.070707070707071 +0.5490727317130796 0.8357745720522589 7.2727272727272725 +0.3702091514654802 0.9289484292312513 7.474747474747475 +0.17628785152548898 0.9843386578838236 7.6767676767676765 +-0.02480370080544784 0.9996923408861117 7.878787878787879 +-0.22488639862108173 0.9743849894755358 8.080808080808081 +-0.41582216870771727 0.9094459434244625 8.282828282828282 +-0.5898449758557073 0.8075165041395626 8.484848484848484 +-0.7398766950653171 0.6727425035622647 8.686868686868687 +-0.859815004003662 0.510605678474283 8.88888888888889 +-0.9447815861050266 0.32770070881349983 9.09090909090909 +-0.9913205490138658 0.13146698864295842 9.292929292929292 +-0.9975389879884077 -0.07011396040064677 9.494949494949495 +-0.9631839770525324 -0.26884312591038406 9.696969696969697 +-0.8896528563926016 -0.45663748763377376 9.8989898989899 +-0.779936397574316 -0.6258587825850161 10.1010101010101 +-0.638497158251875 -0.769624180301191 10.303030303030303 +-0.4710879741150293 -0.8820862319774624 10.505050505050505 +-0.2845179706505102 -0.9586707069567294 10.707070707070708 +-0.08637561184970585 -0.9962626429198221 10.909090909090908 +0.11527994954575044 -0.9933330424549106 11.11111111111111 +0.3122466663798508 -0.9500010628071266 11.313131313131313 +0.4965132034409228 -0.8680291693306353 11.515151515151516 +0.6605847868889071 -0.7507514497694541 11.717171717171716 +0.7977880432989004 -0.6029380050795535 11.919191919191919 +0.9025424294354707 -0.43060093249866344 12.121212121212121 +0.9705872127458185 -0.2407497922206855 12.323232323232324 +0.9991547704697801 -0.04110650371268662 12.525252525252524 +0.9870831586770104 0.1602087321472088 12.727272727272727 +0.9348633726492067 0.3550077104499993 12.929292929292929 +0.8446193763599521 0.5353672656012185 13.131313131313131 +0.7200217133240836 0.6939515345770562 13.333333333333334 +0.5661382125698547 0.8243103325011825 13.535353535353535 +0.38922786205169047 0.9211415045489321 13.737373737373737 +0.19648623340319554 0.9805065833960652 13.93939393939394 +-0.004247187491081489 0.9999909806585335 14.141414141414142 +-0.20480786020107072 0.9788021967690197 14.343434343434343 +-0.3970382705782732 0.9178020547461276 14.545454545454545 +-0.5731197257990347 0.8194716467944692 14.747474747474747 +-0.7258903683424182 0.6878104194817846 14.94949494949495 +-0.8491364741458517 0.5281735020569958 15.15151515151515 +-0.9378451868090543 0.3470538943436452 15.353535353535353 +-0.9884084082494465 0.15181837339991294 15.555555555555555 +-0.9987695528527076 -0.04959213944167377 15.757575757575758 +-0.9685071961064762 -0.24898556401922536 15.959595959595958 +-0.8988522154304799 -0.43825186230718777 16.161616161616163 +-0.7926377260247273 -0.609692902437243 16.363636363636363 +-0.6541838480224215 -0.7563355690343919 16.565656565656564 +-0.48912199187635547 -0.8722153845598611 16.767676767676768 +-0.30416580891556017 -0.9526191057745708 16.96969696969697 +-0.106838123325693 -0.9942764280642703 17.171717171717173 +0.09483504780155239 -0.9954930003312314 17.373737373737374 +0.29265094105990214 -0.9562193402649591 17.575757575757574 +0.47856368221963436 -0.8780528469633162 17.77777777777778 +0.645011540479259 -0.7641728290436485 17.97979797979798 +0.7852244908862596 -0.6192111908811196 18.18181818181818 +0.8934995752719529 -0.4490640366237758 18.383838383838384 +0.9654328617943044 -0.26065185471747443 18.585858585858585 +0.9980985684711091 -0.06163803708687286 18.78787878787879 +0.9901680651138731 0.13988281820384094 18.98989898989899 +0.9419639134315667 0.3357141429738816 19.19191919191919 +0.8554467473014667 0.5178907824351968 19.393939393939394 +0.7341355268330447 0.6790029662980626 19.595959595959595 +0.5829644097750302 0.8124976904186563 19.7979797979798 +0.40808206181339196 0.9129452507276277 20.0 +}{\dataDFHNIDGLEFPCLNOOILBDMAJGJEBAMDGP} + +\begin{tikzpicture} + +\definecolor{darkblue}{RGB}{0, 0, 139} + +\begin{axis} +\addplot3+ [mark=none, line width=3, color=darkblue, forget plot] table[x=x, y=y, z=z] {\dataDFHNIDGLEFPCLNOOILBDMAJGJEBAMDGP}; +\end{axis} +\end{tikzpicture} diff --git a/tests/test_scatter3d/test_scatter3d_empty_reference.tex b/tests/test_scatter3d/test_scatter3d_empty_reference.tex new file mode 100644 index 0000000..811f72d --- /dev/null +++ b/tests/test_scatter3d/test_scatter3d_empty_reference.tex @@ -0,0 +1,5 @@ +\begin{tikzpicture} +\begin{axis} +\addplot3 coordinates {}; +\end{axis} +\end{tikzpicture} diff --git a/tests/test_scatter3d/test_scatter3d_view_reference.tex b/tests/test_scatter3d/test_scatter3d_view_reference.tex new file mode 100644 index 0000000..64af757 --- /dev/null +++ b/tests/test_scatter3d/test_scatter3d_view_reference.tex @@ -0,0 +1,19 @@ +\pgfplotstableread{ +x y z +1 4 7 +2 5 8 +3 6 9 +}{\dataMJPPLKDJHBCHLGPPMBABHNCKCPHFLJMO} + +\begin{tikzpicture} + + +\begin{axis}[ +view={45.0}{13.3}, +xmajorgrids=false, +ymajorgrids=false, +zmajorgrids=false +] +\addplot3+ [only marks, mark size=4.5, mark options={solid, fill=red}] table[x=x, y=y, z=z] {\dataMJPPLKDJHBCHLGPPMBABHNCKCPHFLJMO}; +\end{axis} +\end{tikzpicture} diff --git a/tests/test_specific.py b/tests/test_specific.py index 9dade9d..f638320 100644 --- a/tests/test_specific.py +++ b/tests/test_specific.py @@ -36,9 +36,17 @@ def plot_transparent_background(): return fig +def plot_empty_figure(): + fig = go.Figure() + fig.show() + return fig + def test_sanitized_text(): assert_equality(plot_sanitized_text(), os.path.join(this_dir, test_name, test_name + "_sanitized_text_reference.tex")) def test_transparent_background(): assert_equality(plot_transparent_background(), os.path.join(this_dir, test_name, test_name + "_transparent_background_reference.tex")) + +def test_empty_figure(): + assert_equality(plot_empty_figure(), os.path.join(this_dir, "empty_plot.tex")) diff --git a/tests/test_specific/test_specific_sanitized_text_reference.tex b/tests/test_specific/test_specific_sanitized_text_reference.tex index a2115aa..a2069ac 100644 --- a/tests/test_specific/test_specific_sanitized_text_reference.tex +++ b/tests/test_specific/test_specific_sanitized_text_reference.tex @@ -1,16 +1,17 @@ -\pgfplotstableread{data0 x5btestx200bx5d +\pgfplotstableread{ +x x5btestx200bx5d 0 0 1 1 2 4 3 9 4 16 -}\dataZ +}\dataA \begin{tikzpicture} \begin{axis}[ clip=false ] -\addplot+ table[y=x5btestx200bx5d] {\dataZ}; +\addplot+ table[y=x5btestx200bx5d] {\dataA}; \addlegendentry{{[testx200b]}} \node[anchor=south west] at (axis cs:2, \pgfkeysvalueof{/pgfplots/ymin} + 1.05*\pgfkeysvalueof{/pgfplots/ymax}-1.05*\pgfkeysvalueof{/pgfplots/ymin}) {{==[\{x1d54bop text\}]==x9}}; \node[anchor=south west] at (axis cs:2, 2) {Ouais c'est pas faux}; diff --git a/tests/test_specific/test_specific_transparent_background_reference.tex b/tests/test_specific/test_specific_transparent_background_reference.tex index 94083c0..7421700 100644 --- a/tests/test_specific/test_specific_transparent_background_reference.tex +++ b/tests/test_specific/test_specific_transparent_background_reference.tex @@ -1,10 +1,11 @@ -\pgfplotstableread{data0 y0 +\pgfplotstableread{ +x y0 0 0 1 1 2 4 3 9 4 16 -}\dataZ +}\dataA \begin{tikzpicture} @@ -16,6 +17,6 @@ xlabel=x, ylabel=y ] -\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataZ}; +\addplot+ [mark=*, only marks, mark options={solid, fill=636efa}, forget plot] table[y=y0] {\dataA}; \end{axis} \end{tikzpicture} diff --git a/tests/test_tikzplotly.py b/tests/test_tikzplotly.py index 2fa2bd8..dee7f75 100644 --- a/tests/test_tikzplotly.py +++ b/tests/test_tikzplotly.py @@ -18,8 +18,9 @@ def test_tikzplotly(axis_options): else: tikzplotly.save("/tmp/tikzplotly/test_tikzplotly_none.tex", fig) -def test_create_document(): - main_tex_content = tex_create_document(compatibility="newest") +@pytest.mark.parametrize("options", [None, "a4paper"]) +def test_create_document(options): + main_tex_content = tex_create_document(compatibility="newest", options=options) main_tex_content += "\\usepackage{graphicx}\n" main_tex_content += "\n" stack_env = [] @@ -36,4 +37,4 @@ def test_create_document(): with open(main_tex_path, "w") as f: f.write(main_tex_content) - compare_two_files(main_tex_path, os.path.join(this_dir, "test_tikzplotly", "test_create_document.tex")) + compare_two_files(main_tex_path, os.path.join(this_dir, "test_tikzplotly", f"test_create_document_{options}.tex")) diff --git a/tests/test_tikzplotly/test_create_document.tex b/tests/test_tikzplotly/test_create_document_None.tex similarity index 100% rename from tests/test_tikzplotly/test_create_document.tex rename to tests/test_tikzplotly/test_create_document_None.tex diff --git a/tests/test_tikzplotly/test_create_document_a4paper.tex b/tests/test_tikzplotly/test_create_document_a4paper.tex new file mode 100644 index 0000000..25ab1ca --- /dev/null +++ b/tests/test_tikzplotly/test_create_document_a4paper.tex @@ -0,0 +1,15 @@ +\documentclass[a4paper]{article} +\usepackage{pgfplots} +\pgfplotsset{compat=newest} + +\usepackage{graphicx} + +\begin{document} + +\begin{figure} + \includegraphics{example-image-a} + \caption{Test figure} +\end{figure} + + +\end{document}