SLOPE

Excel Usage

=SLOPE(data, labels, title, color_up, color_down, legend)
  • data (list[list], required): Input data (Labels, Point1, Point2).
  • labels (list[list], required): Labels for the two points.
  • title (str, optional, default: null): Chart title.
  • color_up (str, optional, default: “green”): Increase color.
  • color_down (str, optional, default: “red”): Decrease color.
  • legend (str, optional, default: “false”): Show legend.

Returns (object): Matplotlib Figure object (standard Python) or base64 encoded PNG string (Pyodide).

Examples

Example 1: Simple slope chart

Inputs:

data labels
Product A 20 35 Before After
Product B 30 25
Product C 15 40

Excel formula:

=SLOPE({"Product A",20,35;"Product B",30,25;"Product C",15,40}, {"Before","After"})

Expected output:

"chart"

Example 2: Slope chart with title

Inputs:

data labels title
Team A 100 150 Q1 Q2 Quarterly Comparison
Team B 120 110
Team C 90 140

Excel formula:

=SLOPE({"Team A",100,150;"Team B",120,110;"Team C",90,140}, {"Q1","Q2"}, "Quarterly Comparison")

Expected output:

"chart"

Example 3: Slope chart with custom colors

Inputs:

data labels color_up color_down
Cat 1 50 80 Start End blue orange
Cat 2 70 60
Cat 3 40 90

Excel formula:

=SLOPE({"Cat 1",50,80;"Cat 2",70,60;"Cat 3",40,90}, {"Start","End"}, "blue", "orange")

Expected output:

"chart"

Example 4: Slope chart with legend

Inputs:

data labels legend
Item 1 10 20 2023 2024 true
Item 2 25 15
Item 3 30 35

Excel formula:

=SLOPE({"Item 1",10,20;"Item 2",25,15;"Item 3",30,35}, {2023,2024}, "true")

Expected output:

"chart"

Python Code

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

def slope(data, labels, title=None, color_up='green', color_down='red', legend='false'):
    """
    Create a slope chart for comparing paired changes across categories.

    See: https://matplotlib.org/stable/gallery/lines_bars_and_markers/slope_chart.html

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

    Args:
        data (list[list]): Input data (Labels, Point1, Point2).
        labels (list[list]): Labels for the two points.
        title (str, optional): Chart title. Default is None.
        color_up (str, optional): Increase color. Valid options: Green, Blue. Default is 'green'.
        color_down (str, optional): Decrease color. Valid options: Red, Orange. Default is 'red'.
        legend (str, optional): Show legend. Valid options: True, False. Default is 'false'.

    Returns:
        object: Matplotlib Figure object (standard Python) or base64 encoded PNG string (Pyodide).
    """
    def to2d(x):
        return [[x]] if not isinstance(x, list) else x

    try:
        data = to2d(data)
        labels_2d = to2d(labels)

        if not isinstance(data, list) or len(data) < 1:
            return "Error: Data must be a non-empty list"

        # Extract category labels and point values
        categories = []
        point_one = []
        point_two = []
        for row in data:
            if not isinstance(row, list) or len(row) < 3:
                continue
            try:
                categories.append(str(row[0]))
                point_one.append(float(row[1]))
                point_two.append(float(row[2]))
            except (ValueError, TypeError):
                continue

        if len(categories) == 0 or len(point_one) == 0 or len(point_two) == 0:
            return "Error: No valid data rows found (need 3 columns: Label, Point1, Point2)"

        # Extract point labels
        point_labels = ['Point 1', 'Point 2']
        if isinstance(labels_2d, list) and len(labels_2d) > 0:
            if isinstance(labels_2d[0], list) and len(labels_2d[0]) >= 2:
                point_labels = [str(labels_2d[0][0]), str(labels_2d[0][1])]
            elif len(labels_2d) >= 2:
                point_labels = [str(labels_2d[0]), str(labels_2d[1])]

        # Create figure
        fig, ax = plt.subplots(figsize=(8, 8))

        # Draw slopes
        for i in range(len(categories)):
            # Determine color based on slope direction
            if point_two[i] > point_one[i]:
                color = color_up
            elif point_two[i] < point_one[i]:
                color = color_down
            else:
                color = 'gray'

            # Draw line
            ax.plot([0, 1], [point_one[i], point_two[i]], '-o', color=color, linewidth=2, markersize=8)

            # Add category labels
            ax.text(-0.05, point_one[i], categories[i], ha='right', va='center', fontsize=9)
            ax.text(1.05, point_two[i], categories[i], ha='left', va='center', fontsize=9)

        # Set x-axis labels
        ax.set_xticks([0, 1])
        ax.set_xticklabels(point_labels, fontsize=12, fontweight='bold')
        ax.set_xlim(-0.2, 1.2)

        # Remove y-axis
        ax.set_yticks([])

        if title:
            ax.set_title(title)

        # Handle legend
        if legend == "true":
            from matplotlib.lines import Line2D
            legend_elements = [
                Line2D([0], [0], color=color_up, linewidth=2, label='Increase'),
                Line2D([0], [0], color=color_down, linewidth=2, label='Decrease')
            ]
            ax.legend(handles=legend_elements, loc="best")

        # Clean up spines
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        ax.spines['left'].set_visible(False)
        ax.spines['bottom'].set_visible(False)

        plt.tight_layout()

        if IS_PYODIDE:
            buf = io.BytesIO()
            plt.savefig(buf, format='png', bbox_inches='tight')
            plt.close(fig)
            buf.seek(0)
            img_base64 = base64.b64encode(buf.read()).decode('utf-8')
            return f"data:image/png;base64,{img_base64}"
        else:
            return fig
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator