Skip to content

Instantly share code, notes, and snippets.

@ncalm
Created November 18, 2024 23:54
Show Gist options
  • Save ncalm/a0fc974c97acded28f7850f2d816846d to your computer and use it in GitHub Desktop.
Save ncalm/a0fc974c97acded28f7850f2d816846d to your computer and use it in GitHub Desktop.
This gist shows an example of creating a Power BI-style KPI card using Python in Excel
# Create a KPI card
card = KPICard(figsize=(4, 3))
# Add elements to the card
card.add_title("Revenue")
card.add_value(1234567, prefix="$", suffix="")
card.add_change(12.5) # Will show with arrow
card.add_subtitle("vs. Previous Month")
card.add_border()
# Show the card
card.show()
# Clean up
card.close()
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.offsetbox import TextArea, DrawingArea, OffsetImage, AnnotationBbox
import numpy as np
class KPICard:
"""
A class to create KPI card visualizations using matplotlib.
"""
def __init__(self, figsize=(4, 3), dpi=100):
"""
Initialize the KPI card with figure size and DPI settings.
Args:
figsize (tuple): Width and height of the card in inches
dpi (int): Dots per inch for the figure
"""
self.fig, self.ax = plt.subplots(figsize=figsize, dpi=dpi)
self.ax.set_xlim(0, 1)
self.ax.set_ylim(0, 1)
# Remove axes and frame
self.ax.axis('off')
# Set default colors
self.colors = {
'background': '#FFFFFF',
'title': '#666666',
'value': '#000000',
'positive': '#28a745',
'negative': '#dc3545',
'neutral': '#6c757d'
}
# Set default font sizes
self.fontsizes = {
'title': 10,
'value': 24,
'change': 12,
'subtitle': 8
}
def add_title(self, title, pos=(0.1, 0.8)):
"""Add a title to the card"""
self.ax.text(pos[0], pos[1], title,
fontsize=self.fontsizes['title'],
color=self.colors['title'],
fontweight='bold')
def add_value(self, value, prefix="", suffix="", pos=(0.1, 0.5)):
"""Add the main KPI value"""
text = f"{prefix}{value}{suffix}"
self.ax.text(pos[0], pos[1], text,
fontsize=self.fontsizes['value'],
color=self.colors['value'],
fontweight='bold')
def add_change(self, change_value, pos=(0.1, 0.3), show_arrow=True):
"""Add the change indicator with optional arrow"""
if change_value > 0:
color = self.colors['positive']
arrow = "▲" if show_arrow else ""
change_text = f"{arrow} +{change_value}%"
elif change_value < 0:
color = self.colors['negative']
arrow = "▼" if show_arrow else ""
change_text = f"{arrow} {change_value}%"
else:
color = self.colors['neutral']
arrow = "−" if show_arrow else ""
change_text = f"{arrow} {change_value}%"
self.ax.text(pos[0], pos[1], change_text,
fontsize=self.fontsizes['change'],
color=color,
fontweight='bold')
def add_subtitle(self, text, pos=(0.1, 0.2)):
"""Add a subtitle or description"""
self.ax.text(pos[0], pos[1], text,
fontsize=self.fontsizes['subtitle'],
color=self.colors['title'])
def set_background(self, color=None):
"""Set the background color of the card"""
if color:
self.colors['background'] = color
self.fig.patch.set_facecolor(self.colors['background'])
self.ax.set_facecolor(self.colors['background'])
def add_border(self, color='#EEEEEE', linewidth=1):
"""Add a border around the card"""
border = patches.Rectangle((0, 0), 1, 1, fill=False,
edgecolor=color, linewidth=linewidth)
self.ax.add_patch(border)
def save(self, filename):
"""Save the card to a file"""
self.fig.savefig(filename, bbox_inches='tight',
facecolor=self.colors['background'])
def show(self):
"""Display the card"""
plt.show()
def close(self):
"""Close the figure to free memory"""
plt.close(self.fig)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment