SHAPELY_PLOT

Renders one or more WKT geometries to a 2D plot and returns a base64-encoded PNG image string suitable for display in Excel.

The function parses geometry inputs, draws points/lines/polygons with optional color and transparency, then exports the figure as an inline image URI.

Transparency is controlled by an alpha parameter in the interval:

0 \leq \alpha \leq 1

Excel Usage

=SHAPELY_PLOT(geometries, color, alpha)
  • geometries (list[list], required): List of WKT strings to plot.
  • color (str, optional, default: null): Color of the plot elements.
  • alpha (float, optional, default: 0.5): Transparency (0.0 to 1.0).

Returns (str): Base64 encoded PNG image.

Example 1: Plot a line

Inputs:

geometries
LINESTRING (0 0, 2 2, 4 1)

Excel formula:

=SHAPELY_PLOT(LINESTRING (0 0, 2 2, 4 1))

Expected output:

"chart"

Example 2: Plot mixed geometries

Inputs:

geometries alpha
POINT (0 0),LINESTRING (0 0, 1 2),POLYGON ((2 0, 3 0, 3 1, 2 1, 2 0)) 0.6

Excel formula:

=SHAPELY_PLOT(POINT (0 0),LINESTRING (0 0, 1 2),POLYGON ((2 0, 3 0, 3 1, 2 1, 2 0)), 0.6)

Expected output:

"chart"

Example 3: Plot a square

Inputs:

geometries
POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))

Excel formula:

=SHAPELY_PLOT(POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0)))

Expected output:

"chart"

Example 4: Plot points

Inputs:

geometries color
POINT (0 0),POINT (1 1) red

Excel formula:

=SHAPELY_PLOT(POINT (0 0),POINT (1 1), "red")

Expected output:

"chart"

Python Code

import sys
import matplotlib
if sys.platform == "emscripten":
    matplotlib.use('Agg')
import matplotlib.pyplot as plt
from shapely import wkt
import io
import base64
import numpy as np

def shapely_plot(geometries, color=None, alpha=0.5):
    """
    Plot geometries and return an image.

    See: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        geometries (list[list]): List of WKT strings to plot.
        color (str, optional): Color of the plot elements. Default is None.
        alpha (float, optional): Transparency (0.0 to 1.0). Default is 0.5.

    Returns:
        str: Base64 encoded PNG image.
    """
    try:
        # Helper to flatten inputs
        def flatten(x):
            if isinstance(x, list):
                out = []
                for item in x:
                    out.extend(flatten(item))
                return out
            return [x]

        raw_list = flatten(geometries)
        wkt_list = [str(s) for s in raw_list if s and isinstance(s, str)]

        if not wkt_list:
            return "Error: No geometries provided"

        # Parse geometries
        geoms = []
        for s in wkt_list:
            try:
                geoms.append(wkt.loads(s))
            except:
                pass

        if not geoms:
            return "Error: No valid geometries found"

        # Setup plot
        plt.clf()
        fig, ax = plt.subplots(figsize=(6, 6))

        # Default colors cycle if not provided
        prop_cycle = plt.rcParams['axes.prop_cycle']
        colors = prop_cycle.by_key()['color']

        # Plot helper
        def plot_geom(g, c=None):
            if g.is_empty: return

            if g.geom_type == 'Point':
                x, y = g.x, g.y
                ax.plot(x, y, 'o', color=c, alpha=alpha)

            elif g.geom_type == 'LineString':
                x, y = g.xy
                ax.plot(x, y, '-', color=c, alpha=alpha, linewidth=2)

            elif g.geom_type == 'Polygon':
                # Plot exterior
                x, y = g.exterior.xy
                ax.plot(x, y, '-', color=c, alpha=1.0) # Boundary solid
                ax.fill(x, y, color=c, alpha=alpha) # Fill transparent
                # Plot holes
                for interior in g.interiors:
                    xi, yi = interior.xy
                    ax.plot(xi, yi, '-', color='w', linewidth=1) # Hole boundary

            elif g.geom_type.startswith('Multi') or g.geom_type == 'GeometryCollection':
                for part in g.geoms:
                    plot_geom(part, c)

        for i, g in enumerate(geoms):
            c = color if color else colors[i % len(colors)]
            plot_geom(g, c)

        ax.set_aspect('equal')
        ax.grid(True, linestyle=':', alpha=0.6)

        # Determine bounds logic? matplotlib handles auto-scaling usually.

        # Return image
        buf = io.BytesIO()
        plt.savefig(buf, format='png', bbox_inches='tight')
        plt.close(fig)
        buf.seek(0)
        img_str = base64.b64encode(buf.read()).decode('utf-8')

        return f"data:image/png;base64,{img_str}"

    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

List of WKT strings to plot.
Color of the plot elements.
Transparency (0.0 to 1.0).