diff --git a/pyinfraformat/core/core.py b/pyinfraformat/core/core.py index 4a43574..61f8a31 100644 --- a/pyinfraformat/core/core.py +++ b/pyinfraformat/core/core.py @@ -452,22 +452,23 @@ def _get_dataframe(self, update=False): return self._dataframe - def plot(self, backend="matplotlib"): + def plot(self, output="figure", figsize=(4, 4)): """Plot a diagram of a sounding with matplotlib. Parameters ---------- - backend : str - Backend to plot with - possible values 'mpld3' and 'matplotlib' + output : str + Possible values: ['figure', 'svg'] + figsize : tuple + figure size in inches Returns ------- - figure : matplotlib figure or mpld3 html + figure : matplotlib figure or svg """ from ..plots.holes import plot_hole - return plot_hole(self, backend) + return plot_hole(self, output, figsize) class FileHeader: diff --git a/pyinfraformat/plots/holes.py b/pyinfraformat/plots/holes.py index 3f05003..5fbeb56 100644 --- a/pyinfraformat/plots/holes.py +++ b/pyinfraformat/plots/holes.py @@ -1,13 +1,12 @@ """Plot diagrams for a single hole.""" import gc -import json +import io import logging from datetime import datetime import matplotlib.dates as mdates import matplotlib.patches as patches import matplotlib.pyplot as plt -import mpld3 import numpy as np import pandas as pd @@ -18,30 +17,6 @@ logger = logging.getLogger("pyinfraformat") -def convert_numpy(obj): - """Convert numpy float or int to python.""" - if isinstance( - obj, - ( - np.int_, - np.intc, - np.intp, - np.int8, - np.int16, - np.int32, - np.int64, - np.uint8, - np.uint16, - np.uint32, - np.uint64, - ), - ): - return int(obj) - elif isinstance(obj, (np.float_, np.float16, np.float32, np.float64)): - return float(obj) - return json.JSONEncoder().default(obj) - - def strip_date(x): """Strip str date to datetime.""" x = str(x) @@ -63,33 +38,20 @@ def fig_to_hmtl(fig, clear_memory=True): Parameters ---------- fig: matplotlib figure + clear_memory: bool Returns ------- html """ - # mpld3.plugins.clear(fig) - html = mpld3.fig_to_html( - fig, no_extras=True, template_type="simple", d3_url=r"https://d3js.org/d3.v3.min.js" - ) - emtpy_html = ( - html[: html.find("{", html.find("{") + 1)] - + "{replace}" - + html[html.rfind("}", 0, html.rfind("}") - 1) + 1 :] - ) - figure_dict = mpld3.fig_to_dict(fig) - - left, _ = figure_dict["axes"] - del left["axes"][1] - - figure_json = json.dumps(figure_dict, default=convert_numpy) - + str_io = io.StringIO() + fig.savefig(str_io, format="svg") + str_io.seek(0) if clear_memory: fig.clear() plt.close() gc.collect() - - return emtpy_html.replace("{replace}", figure_json) + return str_io.read() def plot_po(one_survey): @@ -500,19 +462,20 @@ def plot_vp(one_survey): return fig -def plot_hole(one_survey, backend="matplotlib"): +def plot_hole(one_survey, output="figure", figsize=(4, 4)): """Plot a diagram of a sounding with matplotlib. Parameters ---------- one_survey : hole object - backend : str - Backend to plot with - possible values 'mpld3' and 'matplotlib' + output : str + Possible values: ['figure', 'svg'] + figsize : tuple + figure size in inches Returns ------- - figure : matplotlib figure or mpld3 html + figure : figure or svg """ def _plot_hole(one_survey): @@ -539,6 +502,7 @@ def _plot_hole(one_survey): else: raise NotImplementedError('Hole object "{}" not supported'.format(hole_type)) fig.tight_layout() + fig.set_size_inches(figsize) return fig try: @@ -548,9 +512,9 @@ def _plot_hole(one_survey): plt.close() raise - if backend == "matplotlib": + if output == "figure": return fig - elif backend == "mpld3": + elif output == "svg": return fig_to_hmtl(fig) else: - raise NotImplementedError("Plotting backend {} not implemented".format(backend)) + raise NotImplementedError("Plotting backend {} not implemented".format(output)) diff --git a/pyinfraformat/plots/maps.py b/pyinfraformat/plots/maps.py index 23262b5..6aa42ce 100644 --- a/pyinfraformat/plots/maps.py +++ b/pyinfraformat/plots/maps.py @@ -3,7 +3,6 @@ from itertools import cycle from pathlib import Path -import branca import folium import numpy as np from folium.plugins import MarkerCluster, MeasureControl, MousePosition @@ -58,7 +57,7 @@ } -def plot_map(holes, render_holes=True): +def plot_map(holes, render_holes=True, popup_size=(3, 3)): """Plot a leaflet map from holes with popup hole plots. Parameters @@ -66,6 +65,8 @@ def plot_map(holes, render_holes=True): holes : holes object render_holes : bool Render popup diagrams for holes + popup_size : tuple + size in inches of popup figure Returns ------- @@ -185,8 +186,6 @@ def plot_map(holes, render_holes=True): clust_icon_kwargs[key] = dict(color=color, icon="") map_fig.add_child(hole_clusters[key]) - width = 300 - height = 300 for i, hole in enumerate(holes_filtered): x, y = [hole.header.XY["X"], hole.header.XY["Y"]] x, y = project_points(x, y, input_epsg) @@ -197,9 +196,8 @@ def plot_map(holes, render_holes=True): key = "Missing survey abbreviation" if render_holes and key != "Missing survey abbreviation": try: - html = plot_hole(hole, backend="mpld3") - iframe = branca.element.IFrame(html=html, width=width, height=height + 5) - popup = folium.Popup(iframe, max_width=width) + hole_svg = plot_hole(hole, output="svg", figsize=popup_size) + popup = folium.Popup(hole_svg) icon = get_icon(key, clust_icon_kwargs) folium.Marker(location=[x, y], popup=popup, icon=icon).add_to(hole_clusters[key]) diff --git a/requirements.txt b/requirements.txt index 499d1c0..fc1dd8e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,7 @@ -branca chardet folium numpy -matplotlib<3.3.3 -mpld3<=0.3 +matplotlib pandas pyproj xmltodict