|
| 1 | +import datetime |
| 2 | + |
| 3 | +import numpy as np |
1 | 4 | import matplotlib.pyplot as plt |
2 | 5 | import plotly.tools as tls |
3 | 6 |
|
@@ -84,3 +87,115 @@ def test_multiple_traces_native_legend(): |
84 | 87 | assert plotly_fig.data[0].mode == "lines" |
85 | 88 | assert plotly_fig.data[1].mode == "markers" |
86 | 89 | assert plotly_fig.data[2].mode == "lines+markers" |
| 90 | + |
| 91 | + |
| 92 | +def test_violinplot_bodies_are_filled_polygons(): |
| 93 | + fig, ax = plt.subplots() |
| 94 | + ax.violinplot(np.random.randn(100, 3)) |
| 95 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 96 | + bodies = [t for t in plotly_fig.data if t.fill == "toself" and len(t.x) > 100] |
| 97 | + assert len(bodies) >= 3 |
| 98 | + |
| 99 | + |
| 100 | +def test_pcolor_rectangles_render(): |
| 101 | + x = np.linspace(-3, 3, 10) |
| 102 | + X, Y = np.meshgrid(x, x) |
| 103 | + fig, ax = plt.subplots() |
| 104 | + ax.pcolor(X, Y, np.sin(X) * np.cos(Y)) |
| 105 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 106 | + assert len(plotly_fig.data) == 100 |
| 107 | + assert all(len(t.x) >= 4 for t in plotly_fig.data) |
| 108 | + |
| 109 | + |
| 110 | +def test_eventplot_segments_render(): |
| 111 | + fig, ax = plt.subplots() |
| 112 | + ax.eventplot([np.random.randn(20) for _ in range(5)]) |
| 113 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 114 | + assert len(plotly_fig.data) == 100 |
| 115 | + |
| 116 | + |
| 117 | +def test_stackplot_areas_render(): |
| 118 | + x = np.arange(10) |
| 119 | + fig, ax = plt.subplots() |
| 120 | + ax.stackplot(x, np.random.rand(10), np.random.rand(10), np.random.rand(10)) |
| 121 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 122 | + assert len(plotly_fig.data) >= 3 |
| 123 | + |
| 124 | + |
| 125 | +def test_fill_between_renders(): |
| 126 | + x = np.linspace(0, 2 * np.pi, 50) |
| 127 | + fig, ax = plt.subplots() |
| 128 | + ax.fill_between(x, np.sin(x), np.cos(x)) |
| 129 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 130 | + assert len(plotly_fig.data) >= 1 |
| 131 | + |
| 132 | + |
| 133 | +def test_collection_alpha(): |
| 134 | + """Collection alpha is baked into the facecolor rgba by matplotlib. if |
| 135 | + fillcolor has an alpha channel, the opacity field should not be set.""" |
| 136 | + x = np.linspace(0, 2 * np.pi, 50) |
| 137 | + fig, ax = plt.subplots() |
| 138 | + ax.fill_between(x, np.sin(x), np.cos(x), color="red", alpha=0.4) |
| 139 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 140 | + trace = plotly_fig.data[0] |
| 141 | + assert trace.fillcolor == "rgba(255,0,0,0.4)" |
| 142 | + assert trace.opacity is None |
| 143 | + |
| 144 | + |
| 145 | +def test_violin_body_default_alpha(): |
| 146 | + """Violin bodies default to alpha=0.3 in matplotlib, which is |
| 147 | + embedded in their facecolor rgba. If the alpha channel in fillcolor |
| 148 | + is set, the opacity field should not be set.""" |
| 149 | + fig, ax = plt.subplots() |
| 150 | + ax.violinplot(np.random.randn(100, 3)) |
| 151 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 152 | + bodies = [ |
| 153 | + t |
| 154 | + for t in plotly_fig.data |
| 155 | + if t.fill == "toself" and t.fillcolor == "rgba(31,119,180,0.3)" |
| 156 | + ] |
| 157 | + assert len(bodies) >= 3 |
| 158 | + assert all(t.opacity is None for t in bodies) |
| 159 | + |
| 160 | + |
| 161 | +def test_stem_plot_renders(): |
| 162 | + x = np.linspace(0, 2 * np.pi, 20) |
| 163 | + fig, ax = plt.subplots() |
| 164 | + ax.stem(x, np.sin(x)) |
| 165 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 166 | + assert len(plotly_fig.data) >= 20 |
| 167 | + |
| 168 | + |
| 169 | +def test_contour_lines_convert(): |
| 170 | + """Contour lines used to crash with an ndarray line width.""" |
| 171 | + x = np.linspace(-3, 3, 30) |
| 172 | + X, Y = np.meshgrid(x, x) |
| 173 | + fig, ax = plt.subplots() |
| 174 | + ax.contour(X, Y, np.sin(X) * np.cos(Y), 10) |
| 175 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 176 | + assert len(plotly_fig.data) > 0 |
| 177 | + |
| 178 | + |
| 179 | +def test_contourf_bands_render(): |
| 180 | + """Contourf bands (multi-subpath collections) must render as fills.""" |
| 181 | + x = np.linspace(-3, 3, 30) |
| 182 | + X, Y = np.meshgrid(x, x) |
| 183 | + fig, ax = plt.subplots() |
| 184 | + ax.contourf(X, Y, np.sin(X) * np.cos(Y), 10) |
| 185 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 186 | + filled = [t for t in plotly_fig.data if t.fill == "toself"] |
| 187 | + assert len(filled) > 0 |
| 188 | + |
| 189 | + |
| 190 | +def test_filled_path_collection_date_xaxis(): |
| 191 | + """Filled path collections with date x-values must export date strings, |
| 192 | + not raw matplotlib date numbers.""" |
| 193 | + dates = [ |
| 194 | + datetime.datetime(2023, 1, 1) + datetime.timedelta(days=i) for i in range(10) |
| 195 | + ] |
| 196 | + fig, ax = plt.subplots() |
| 197 | + ax.fill_between(dates, np.sin(np.arange(10)), np.cos(np.arange(10))) |
| 198 | + plotly_fig = tls.mpl_to_plotly(fig) |
| 199 | + filled = [t for t in plotly_fig.data if t.fill == "toself"] |
| 200 | + assert len(filled) >= 1 |
| 201 | + assert all(isinstance(x, str) for x in filled[0].x) |
0 commit comments