import os import pathlib import pytest from selenium.webdriver.support.wait import WebDriverWait ROOT_PATH = pathlib.Path(__file__).resolve().parents[2] TEST_PATH = ROOT_PATH / "packages" / "matplotlib" / "reference-images" TARGET_PATH = ROOT_PATH / "build" / "matplotlib-test" def get_backend(selenium_standalone): selenium = selenium_standalone return selenium.run( """ import matplotlib matplotlib.get_backend() """ ) def get_canvas_data(selenium, prefix): import base64 canvas_tag_property = "//canvas[starts-with(@id, 'matplotlib')]" canvas_element = selenium.driver.find_element_by_xpath(canvas_tag_property) img_script = "return arguments[0].toDataURL('image/png').substring(21)" canvas_base64 = selenium.driver.execute_script(img_script, canvas_element) canvas_png = base64.b64decode(canvas_base64) with open(rf"{TEST_PATH}/{prefix}-{selenium.browser}.png", "wb") as f: f.write(canvas_png) def check_comparison(selenium, prefix, num_fonts): font_wait = WebDriverWait(selenium.driver, timeout=350) font_wait.until(FontsLoaded(num_fonts)) # If we don't have a reference image, write one to disk if not os.path.isfile(f"{TEST_PATH}/{prefix}-{selenium.browser}.png"): get_canvas_data(selenium, prefix) selenium.run( f""" url = 'http://{selenium.server_hostname}:{selenium.server_port}/matplotlib-test/{prefix}-{selenium.browser}.png' threshold = 0 plt.gcf().canvas.compare_reference_image(url, threshold) """ ) wait = WebDriverWait(selenium.driver, timeout=350) wait.until(ResultLoaded()) assert selenium.run("window.font_counter") == num_fonts assert selenium.run("window.deviation") == 0 assert selenium.run("window.result") is True @pytest.mark.skip_refcount_check @pytest.mark.skip_pyproxy_check def test_matplotlib(selenium): if selenium.browser == "node": pytest.xfail("No supported matplotlib backends on node") selenium.load_package("matplotlib") selenium.run( """ from matplotlib import pyplot as plt plt.figure() plt.plot([1,2,3]) plt.show() """ ) @pytest.mark.skip_refcount_check @pytest.mark.skip_pyproxy_check def test_svg(selenium): if selenium.browser == "node": pytest.xfail("No supported matplotlib backends on node") selenium.load_package("matplotlib") selenium.run("from matplotlib import pyplot as plt") selenium.run("plt.figure(); pass") selenium.run("x = plt.plot([1,2,3])") selenium.run("import io") selenium.run("fd = io.BytesIO()") selenium.run("plt.savefig(fd, format='svg')") content = selenium.run("fd.getvalue().decode('utf8')") assert len(content) == 14998 assert content.startswith(" \beta_i,\ " r"\alpha_{i+1}^j = {\rm sin}(2\pi f_j t_i) e^{-5 t_i/\tau},\ " r"\ldots$", 2: r"$\frac{3}{4},\ \binom{3}{4},\ \genfrac{}{}{0}{}{3}{4},\ " r"\left(\frac{5 - \frac{1}{x}}{4}\right),\ \ldots$", 3: r"$\sqrt{2},\ \sqrt[3]{x},\ \ldots$", 4: r"$\mathrm{Roman}\ , \ \mathit{Italic}\ , \ \mathtt{Typewriter} \ " r"\mathrm{or}\ \mathcal{CALLIGRAPHY}$", 5: r"$\acute a,\ \bar a,\ \breve a,\ \dot a,\ \ddot a, \ \grave a, \ " r"\hat a,\ \tilde a,\ \vec a,\ \widehat{xyz},\ \widetilde{xyz},\ " r"\ldots$", 6: r"$\alpha,\ \beta,\ \chi,\ \delta,\ \lambda,\ \mu,\ " r"\Delta,\ \Gamma,\ \Omega,\ \Phi,\ \Pi,\ \Upsilon,\ \nabla,\ " r"\aleph,\ \beth,\ \daleth,\ \gimel,\ \ldots$", 7: r"$\coprod,\ \int,\ \oint,\ \prod,\ \sum,\ " r"\log,\ \sin,\ \approx,\ \oplus,\ \star,\ \varpropto,\ " r"\infty,\ \partial,\ \Re,\ \leftrightsquigarrow, \ \ldots$"} def doall(): # Colors used in mpl online documentation. mpl_blue_rvb = (191. / 255., 209. / 256., 212. / 255.) mpl_orange_rvb = (202. / 255., 121. / 256., 0. / 255.) mpl_grey_rvb = (51. / 255., 51. / 255., 51. / 255.) # Creating figure and axis. plt.figure(figsize=(6, 7)) plt.axes([0.01, 0.01, 0.98, 0.90], facecolor="white", frameon=True) plt.gca().set_xlim(0., 1.) plt.gca().set_ylim(0., 1.) plt.gca().set_title("Matplotlib's math rendering engine", color=mpl_grey_rvb, fontsize=14, weight='bold') plt.gca().set_xticklabels("", visible=False) plt.gca().set_yticklabels("", visible=False) # Gap between lines in axes coords line_axesfrac = (1. / (n_lines)) # Plotting header demonstration formula full_demo = mathext_demos[0] plt.annotate(full_demo, xy=(0.5, 1. - 0.59 * line_axesfrac), color=mpl_orange_rvb, ha='center', fontsize=20) # Plotting features demonstration formulae for i_line in range(1, n_lines): baseline = 1 - (i_line) * line_axesfrac baseline_next = baseline - line_axesfrac title = mathtext_titles[i_line] + ":" fill_color = ['white', mpl_blue_rvb][i_line % 2] plt.fill_between([0., 1.], [baseline, baseline], [baseline_next, baseline_next], color=fill_color, alpha=0.5) plt.annotate(title, xy=(0.07, baseline - 0.3 * line_axesfrac), color=mpl_grey_rvb, weight='bold') demo = mathext_demos[i_line] plt.annotate(demo, xy=(0.05, baseline - 0.75 * line_axesfrac), color=mpl_grey_rvb, fontsize=16) for i in range(n_lines): s = mathext_demos[i] print(i, s) plt.show() doall() """ ) check_comparison(selenium, "canvas-math-text", 1) finally: TARGET_PATH.unlink() @pytest.mark.skip_refcount_check @pytest.mark.skip_pyproxy_check def test_custom_font_text(selenium_standalone): selenium = selenium_standalone if selenium.browser == "node": pytest.xfail("No supported matplotlib backends on node") selenium.load_package("matplotlib") if get_backend(selenium) == "module://matplotlib.backends.wasm_backend": print( "test supported only for html5 canvas backend. wasm backend is currently used. switching to html5 canvas backend" ) TARGET_PATH.symlink_to(TEST_PATH, True) try: selenium.get_driver().set_script_timeout(7000) selenium.run( """ import matplotlib matplotlib.use("module://matplotlib.backends.html5_canvas_backend") from js import window window.testing = True import matplotlib.pyplot as plt import numpy as np f = {'fontname': 'cmsy10'} t = np.arange(0.0, 2.0, 0.01) s = 1 + np.sin(2 * np.pi * t) plt.figure() plt.title('A simple Sine Curve', **f) plt.plot(t, s, linewidth=1.0, marker=11) plt.plot(t, t) plt.grid(True) plt.show() """ ) check_comparison(selenium, "canvas-custom-font-text", 2) finally: TARGET_PATH.unlink() @pytest.mark.skip_refcount_check @pytest.mark.skip_pyproxy_check def test_zoom_on_polar_plot(selenium_standalone): selenium = selenium_standalone if selenium.browser == "node": pytest.xfail("No supported matplotlib backends on node") selenium.load_package("matplotlib") if get_backend(selenium) == "module://matplotlib.backends.wasm_backend": print( "test supported only for html5 canvas backend. wasm backend is currently used. switching to html5 canvas backend" ) TARGET_PATH.symlink_to(TEST_PATH, True) try: selenium.get_driver().set_script_timeout(7000) selenium.run( """ import matplotlib matplotlib.use("module://matplotlib.backends.html5_canvas_backend") from js import window window.testing = True import numpy as np import matplotlib.pyplot as plt np.random.seed(42) # Compute pie slices N = 20 theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False) radii = 10 * np.random.rand(N) width = np.pi / 4 * np.random.rand(N) ax = plt.subplot(111, projection='polar') bars = ax.bar(theta, radii, width=width, bottom=0.0) # Use custom colors and opacity for r, bar in zip(radii, bars): bar.set_facecolor(plt.cm.viridis(r / 10.)) bar.set_alpha(0.5) ax.set_rlim([0,5]) plt.show() """ ) check_comparison(selenium, "canvas-polar-zoom", 1) finally: TARGET_PATH.unlink() @pytest.mark.skip_refcount_check @pytest.mark.skip_pyproxy_check def test_transparency(selenium_standalone): selenium = selenium_standalone if selenium.browser == "node": pytest.xfail("No supported matplotlib backends on node") selenium.load_package("matplotlib") if get_backend(selenium) == "module://matplotlib.backends.wasm_backend": print( "test supported only for html5 canvas backend. wasm backend is currently used. switching to html5 canvas backend" ) TARGET_PATH.symlink_to(TEST_PATH, True) try: selenium.get_driver().set_script_timeout(7000) selenium.run( """ import matplotlib matplotlib.use("module://matplotlib.backends.html5_canvas_backend") from js import window window.testing = True import numpy as np np.random.seed(19680801) import matplotlib.pyplot as plt fig, ax = plt.subplots() for color in ['tab:blue', 'tab:orange', 'tab:green']: n = 100 x, y = np.random.rand(2, n) scale = 200.0 * np.random.rand(n) ax.scatter(x, y, c=color, s=scale, label=color, alpha=0.3, edgecolors='none') ax.legend() ax.grid(True) plt.show() """ ) check_comparison(selenium, "canvas-transparency", 1) finally: TARGET_PATH.unlink() class ResultLoaded: def __call__(self, driver): inited = driver.execute_script("return window.result") return inited is not None class FontsLoaded: def __init__(self, num_fonts): self.num_fonts = num_fonts def __call__(self, driver): font_inited = driver.execute_script("return window.font_counter") return font_inited is not None and font_inited == self.num_fonts