BULLET
Excel Usage
=BULLET(data, title, target, color_ranges, color_measure, legend)
data(list[list], required): Input data (Labels, Measured).title(str, optional, default: null): Chart title.target(float, optional, default: 0): Target value.color_ranges(str, optional, default: null): Zone colors (comma-separated).color_measure(str, optional, default: “black”): Measured bar color.legend(str, optional, default: “false”): Show legend.
Returns (object): Matplotlib Figure object (standard Python) or base64 encoded PNG string (Pyodide).
Examples
Example 1: Basic bullet chart with target
Inputs:
| data | target | |
|---|---|---|
| Sales | 80 | 100 |
| Revenue | 120 |
Excel formula:
=BULLET({"Sales",80;"Revenue",120}, 100)
Expected output:
"chart"
Example 2: Bullet chart with title
Inputs:
| data | target | title | |
|---|---|---|---|
| Q1 | 90 | 100 | Quarterly Performance |
| Q2 | 110 |
Excel formula:
=BULLET({"Q1",90;"Q2",110}, 100, "Quarterly Performance")
Expected output:
"chart"
Example 3: Bullet chart with colored zones
Inputs:
| data | target | color_ranges | |
|---|---|---|---|
| Metric A | 75 | 100 | lightgray,yellow,lightgreen |
Excel formula:
=BULLET({"Metric A",75}, 100, "lightgray,yellow,lightgreen")
Expected output:
"chart"
Example 4: Bullet chart with legend
Inputs:
| data | target | legend | |
|---|---|---|---|
| Score | 85 | 90 | true |
Excel formula:
=BULLET({"Score",85}, 90, "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 bullet(data, title=None, target=0, color_ranges=None, color_measure='black', legend='false'):
"""
Create a bullet chart for visual comparison against a target.
See: https://matplotlib.org/stable/gallery/lines_bars_and_markers/barh.html
This example function is provided as-is without any representation of accuracy.
Args:
data (list[list]): Input data (Labels, Measured).
title (str, optional): Chart title. Default is None.
target (float, optional): Target value. Default is 0.
color_ranges (str, optional): Zone colors (comma-separated). Default is None.
color_measure (str, optional): Measured bar color. Default is 'black'.
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)
if not isinstance(data, list) or len(data) == 0:
return "Error: Data must be a non-empty 2D list"
# Extract labels and measured values
labels = []
measured = []
for row in data:
if not isinstance(row, list) or len(row) < 2:
continue
try:
label = str(row[0]) if row[0] else "Item"
value = float(row[1])
labels.append(label)
measured.append(value)
except (TypeError, ValueError):
continue
if len(labels) == 0:
return "Error: No valid data found"
# Create the figure
fig, ax = plt.subplots(figsize=(10, max(3, len(labels) * 0.8)))
y_pos = np.arange(len(labels))
# Determine the maximum value for scaling
max_value = max(max(measured), target if target > 0 else 0)
# Parse color ranges for background zones
if color_ranges:
colors = [c.strip() for c in str(color_ranges).split(',')]
# Draw background zones
zone_width = max_value / len(colors)
for i, color in enumerate(colors):
ax.barh(y_pos, zone_width, left=i * zone_width,
color=color, alpha=0.3, height=0.8)
# Draw measured bars
ax.barh(y_pos, measured, height=0.4, color=color_measure,
edgecolor='black', linewidth=1, label='Measured' if legend == "true" else None)
# Draw target line if specified
if target > 0:
for i in y_pos:
ax.plot([target, target], [i - 0.4, i + 0.4],
color='red', linewidth=2, label='Target' if i == 0 and legend == "true" else None)
ax.set_yticks(y_pos)
ax.set_yticklabels(labels)
ax.invert_yaxis()
ax.set_xlabel('Value')
if title:
ax.set_title(str(title))
if legend == "true":
handles, labels_legend = ax.get_legend_handles_labels()
# Remove duplicate labels
by_label = dict(zip(labels_legend, handles))
ax.legend(by_label.values(), by_label.keys(), loc='best')
ax.grid(True, axis='x', alpha=0.3)
plt.tight_layout()
if IS_PYODIDE:
buf = io.BytesIO()
plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
buf.seek(0)
img_base64 = base64.b64encode(buf.read()).decode('utf-8')
plt.close(fig)
return f"data:image/png;base64,{img_base64}"
else:
return fig
except Exception as e:
return f"Error: {str(e)}"