Initial commit
This commit is contained in:
167
skills/xlsx/engines/chart-templates.md
Executable file
167
skills/xlsx/engines/chart-templates.md
Executable file
@@ -0,0 +1,167 @@
|
||||
# Chart Templates — Implementation Code
|
||||
|
||||
> Load on demand when you need specific chart code. Do NOT load upfront.
|
||||
|
||||
---
|
||||
|
||||
## Native Excel Charts (openpyxl.chart)
|
||||
|
||||
### Bar Chart
|
||||
```python
|
||||
from openpyxl.chart import BarChart, Reference
|
||||
from templates.base import make_chart_title
|
||||
|
||||
chart = BarChart()
|
||||
chart.type = "col"
|
||||
chart.title = make_chart_title("Revenue by Product", 14)
|
||||
chart.y_axis.title = make_chart_title("Revenue ($)", 10, bold=False, axis=True)
|
||||
chart.x_axis.title = make_chart_title("Product", 10, bold=False)
|
||||
|
||||
data = Reference(ws, min_col=3, min_row=4, max_col=3, max_row=last_row)
|
||||
cats = Reference(ws, min_col=2, min_row=5, max_row=last_row)
|
||||
|
||||
chart.add_data(data, titles_from_data=True)
|
||||
chart.set_categories(cats)
|
||||
chart.shape = 4
|
||||
chart.width = 18
|
||||
chart.height = 10
|
||||
|
||||
ws.add_chart(chart, "J4")
|
||||
```
|
||||
|
||||
### Line Chart
|
||||
```python
|
||||
from openpyxl.chart import LineChart, Reference
|
||||
from templates.base import make_chart_title
|
||||
|
||||
chart = LineChart()
|
||||
chart.title = make_chart_title("Monthly Trend", 14)
|
||||
chart.y_axis.title = make_chart_title("Amount", 10, bold=False, axis=True)
|
||||
chart.style = 10
|
||||
|
||||
data = Reference(ws, min_col=3, max_col=5, min_row=4, max_row=last_row)
|
||||
cats = Reference(ws, min_col=2, min_row=5, max_row=last_row)
|
||||
|
||||
chart.add_data(data, titles_from_data=True)
|
||||
chart.set_categories(cats)
|
||||
for series in chart.series:
|
||||
series.smooth = True
|
||||
|
||||
ws.add_chart(chart, "J4")
|
||||
```
|
||||
|
||||
### Pie Chart
|
||||
```python
|
||||
from openpyxl.chart import PieChart, Reference
|
||||
from openpyxl.chart.label import DataLabelList
|
||||
from templates.base import make_chart_title
|
||||
|
||||
chart = PieChart()
|
||||
chart.title = make_chart_title("Market Share", 14)
|
||||
|
||||
data = Reference(ws, min_col=3, min_row=4, max_row=last_row)
|
||||
cats = Reference(ws, min_col=2, min_row=5, max_row=last_row)
|
||||
|
||||
chart.add_data(data, titles_from_data=True)
|
||||
chart.set_categories(cats)
|
||||
|
||||
chart.dataLabels = DataLabelList()
|
||||
chart.dataLabels.dLblPos = 'bestFit'
|
||||
chart.dataLabels.showLeaderLines = True
|
||||
chart.dataLabels.showCatName = True
|
||||
chart.dataLabels.showPercent = True
|
||||
chart.dataLabels.showVal = False
|
||||
|
||||
ws.add_chart(chart, "J4")
|
||||
```
|
||||
|
||||
### Combo Chart (Bar + Line, dual axis)
|
||||
```python
|
||||
from openpyxl.chart import BarChart, LineChart, Reference
|
||||
from templates.base import make_chart_title
|
||||
|
||||
bar = BarChart()
|
||||
bar.add_data(Reference(ws, min_col=2, max_col=2, min_row=1, max_row=10), titles_from_data=True)
|
||||
bar.title = make_chart_title("Revenue vs Growth", 14)
|
||||
bar.y_axis.title = make_chart_title("Revenue ($)", 10, bold=False, axis=True)
|
||||
|
||||
line = LineChart()
|
||||
line.add_data(Reference(ws, min_col=3, max_col=3, min_row=1, max_row=10), titles_from_data=True)
|
||||
line.y_axis.title = make_chart_title("Growth %", 10, bold=False, axis=True)
|
||||
line.y_axis.axId = 200
|
||||
|
||||
bar += line
|
||||
ws.add_chart(bar, "E2")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Matplotlib Charts (embedded as images)
|
||||
|
||||
### Chinese Font Setup
|
||||
```python
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
import os
|
||||
|
||||
_font_path = os.path.join(os.path.dirname(__file__), '..', '..', '..', 'fonts', 'truetype', 'chinese', 'SimHei.ttf')
|
||||
if not os.path.exists(_font_path):
|
||||
# Fallback: try workspace fonts
|
||||
_font_path = os.path.expanduser('/usr/share/fonts/truetype/chinese/SimHei.ttf')
|
||||
if os.path.exists(_font_path):
|
||||
matplotlib.font_manager.fontManager.addfont(_font_path)
|
||||
plt.rcParams['font.sans-serif'] = ['SimHei']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
```
|
||||
|
||||
### Standard Template
|
||||
```python
|
||||
fig, ax = plt.subplots(figsize=(10, 6))
|
||||
ax.bar(categories, values, color='#4A90D9')
|
||||
ax.set_title('Chart Title', fontsize=14, fontweight='bold', pad=15)
|
||||
ax.set_xlabel('X Label', fontsize=11)
|
||||
ax.set_ylabel('Y Label', fontsize=11)
|
||||
ax.spines['top'].set_visible(False)
|
||||
ax.spines['right'].set_visible(False)
|
||||
ax.tick_params(axis='x', rotation=45)
|
||||
fig.tight_layout(pad=2.0)
|
||||
plt.legend(loc='best', fontsize='small')
|
||||
fig.savefig('chart.png', dpi=150, bbox_inches='tight', facecolor='white')
|
||||
plt.close()
|
||||
```
|
||||
|
||||
### Embed in Excel (preserving aspect ratio)
|
||||
```python
|
||||
from openpyxl.drawing.image import Image as XlImage
|
||||
from PIL import Image as PILImage
|
||||
|
||||
pil_img = PILImage.open('chart.png')
|
||||
orig_w, orig_h = pil_img.size
|
||||
target_w = 600
|
||||
scale = target_w / orig_w
|
||||
|
||||
xl_img = XlImage('chart.png')
|
||||
xl_img.width = target_w
|
||||
xl_img.height = int(orig_h * scale)
|
||||
|
||||
ws.add_image(xl_img, 'B20')
|
||||
```
|
||||
|
||||
### Smart Chart Recommend Function
|
||||
```python
|
||||
def recommend_chart(df, x_col, y_cols):
|
||||
if pd.api.types.is_datetime64_any_dtype(df[x_col]):
|
||||
return "line"
|
||||
n_categories = df[x_col].nunique()
|
||||
n_series = len(y_cols)
|
||||
if n_series == 1:
|
||||
vals = df[y_cols[0]]
|
||||
if vals.sum() > 95 and vals.sum() < 105:
|
||||
return "pie" if n_categories <= 5 else "bar_horizontal"
|
||||
if n_categories <= 6:
|
||||
return "bar_grouped" if n_series > 1 else "bar"
|
||||
elif n_categories <= 15:
|
||||
return "bar_horizontal"
|
||||
else:
|
||||
return "bar_top10"
|
||||
```
|
||||
Reference in New Issue
Block a user