@miao-vision/cli 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +95 -31
- package/dist/examples/campaign-data.csv +33 -0
- package/dist/examples/campaign-report-deck.yaml +115 -0
- package/dist/examples/executive-overview-deck.yaml +137 -0
- package/dist/examples/executive-overview.csv +37 -0
- package/examples/campaign-data.csv +33 -0
- package/examples/campaign-report-deck.yaml +115 -0
- package/examples/executive-overview-deck.yaml +137 -0
- package/examples/executive-overview.csv +37 -0
- package/package.json +1 -1
- package/dist/examples/sales-dashboard.yaml +0 -54
- package/examples/sales-dashboard.yaml +0 -54
package/dist/cli.cjs
CHANGED
|
@@ -41719,7 +41719,19 @@ var defaultTheme = {
|
|
|
41719
41719
|
labelColor: "#475569"
|
|
41720
41720
|
},
|
|
41721
41721
|
css: `
|
|
41722
|
-
:root {
|
|
41722
|
+
:root {
|
|
41723
|
+
color-scheme: light;
|
|
41724
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
41725
|
+
--mv-paper: #f8fafc;
|
|
41726
|
+
--mv-surface: #ffffff;
|
|
41727
|
+
--mv-border: #e2e8f0;
|
|
41728
|
+
--mv-ink: #0f172a;
|
|
41729
|
+
--mv-muted: #64748b;
|
|
41730
|
+
--mv-soft: #475569;
|
|
41731
|
+
--mv-brand: #2563eb;
|
|
41732
|
+
--mv-serif: Georgia, "Times New Roman", serif;
|
|
41733
|
+
--mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
|
|
41734
|
+
}
|
|
41723
41735
|
body { margin: 0; background: #f8fafc; color: #0f172a; }
|
|
41724
41736
|
.miao-viz-report { max-width: 1120px; margin: 0 auto; padding: 40px 24px 56px; }
|
|
41725
41737
|
header { margin-bottom: 28px; }
|
|
@@ -41760,6 +41772,7 @@ var editorialTheme = {
|
|
|
41760
41772
|
--mv-ink: #141413;
|
|
41761
41773
|
--mv-muted: #6b6a64;
|
|
41762
41774
|
--mv-soft-text: #504e49;
|
|
41775
|
+
--mv-soft: #504e49;
|
|
41763
41776
|
--mv-brand: #1b365d;
|
|
41764
41777
|
--mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
|
|
41765
41778
|
--mv-serif: Charter, Georgia, "Times New Roman", serif;
|
|
@@ -41824,6 +41837,7 @@ var darkTheme = {
|
|
|
41824
41837
|
--mv-ink: #e2e0d8;
|
|
41825
41838
|
--mv-muted: #737069;
|
|
41826
41839
|
--mv-soft-text: #a8a69f;
|
|
41840
|
+
--mv-soft: #a8a69f;
|
|
41827
41841
|
--mv-brand: #7eb8f7;
|
|
41828
41842
|
--mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
|
|
41829
41843
|
--mv-serif: Charter, Georgia, "Times New Roman", serif;
|
|
@@ -41881,7 +41895,19 @@ var minimalTheme = {
|
|
|
41881
41895
|
labelColor: "#6b7280"
|
|
41882
41896
|
},
|
|
41883
41897
|
css: `
|
|
41884
|
-
:root {
|
|
41898
|
+
:root {
|
|
41899
|
+
color-scheme: light;
|
|
41900
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
|
|
41901
|
+
--mv-paper: #ffffff;
|
|
41902
|
+
--mv-surface: #ffffff;
|
|
41903
|
+
--mv-border: #e5e7eb;
|
|
41904
|
+
--mv-ink: #111111;
|
|
41905
|
+
--mv-muted: #6b7280;
|
|
41906
|
+
--mv-soft: #374151;
|
|
41907
|
+
--mv-brand: #1d4ed8;
|
|
41908
|
+
--mv-serif: Georgia, "Times New Roman", serif;
|
|
41909
|
+
--mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
|
|
41910
|
+
}
|
|
41885
41911
|
body { margin: 0; background: #fff; color: #111; }
|
|
41886
41912
|
.miao-viz-report { max-width: 960px; margin: 0 auto; padding: 48px 24px 64px; }
|
|
41887
41913
|
header { margin-bottom: 32px; }
|
|
@@ -58128,6 +58154,42 @@ function parseAnalyzeContext(value) {
|
|
|
58128
58154
|
function withSize(chart, width, height) {
|
|
58129
58155
|
return { ...chart, style: { ...chart.style, width, height } };
|
|
58130
58156
|
}
|
|
58157
|
+
function formatMetricValue(num, fmt) {
|
|
58158
|
+
const hasCurrency = fmt.includes("$");
|
|
58159
|
+
const hasPercent = fmt.includes("%");
|
|
58160
|
+
const hasThousands = fmt.includes(",");
|
|
58161
|
+
const hasSiPrefix = fmt.includes("s");
|
|
58162
|
+
const precisionMatch = fmt.match(/\.(\d+)/);
|
|
58163
|
+
let precision = precisionMatch ? parseInt(precisionMatch[1], 10) : void 0;
|
|
58164
|
+
let value = num;
|
|
58165
|
+
let suffix = "";
|
|
58166
|
+
if (hasPercent) {
|
|
58167
|
+
value = num < 2 ? num * 100 : num;
|
|
58168
|
+
suffix = "%";
|
|
58169
|
+
if (precision === void 0) precision = 1;
|
|
58170
|
+
}
|
|
58171
|
+
if (hasSiPrefix) {
|
|
58172
|
+
const abs = Math.abs(value);
|
|
58173
|
+
if (abs >= 1e9) {
|
|
58174
|
+
value /= 1e9;
|
|
58175
|
+
suffix = "B" + suffix;
|
|
58176
|
+
} else if (abs >= 1e6) {
|
|
58177
|
+
value /= 1e6;
|
|
58178
|
+
suffix = "M" + suffix;
|
|
58179
|
+
} else if (abs >= 1e3) {
|
|
58180
|
+
value /= 1e3;
|
|
58181
|
+
suffix = "K" + suffix;
|
|
58182
|
+
}
|
|
58183
|
+
if (precision === void 0) precision = 0;
|
|
58184
|
+
}
|
|
58185
|
+
if (precision === void 0 && hasThousands) precision = 0;
|
|
58186
|
+
const fixed = precision !== void 0 ? value.toFixed(precision) : Math.round(value).toString();
|
|
58187
|
+
const [intPart, decPart] = fixed.split(".");
|
|
58188
|
+
const formattedInt = hasThousands ? intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : intPart;
|
|
58189
|
+
const formatted = decPart !== void 0 ? `${formattedInt}.${decPart}` : formattedInt;
|
|
58190
|
+
const prefix = hasCurrency ? "$" : "";
|
|
58191
|
+
return prefix + formatted + suffix;
|
|
58192
|
+
}
|
|
58131
58193
|
function resolveMetricValue(metric, rows) {
|
|
58132
58194
|
let raw = metric.value;
|
|
58133
58195
|
if (raw === void 0 && metric.data?.transform?.length) {
|
|
@@ -58137,10 +58199,7 @@ function resolveMetricValue(metric, rows) {
|
|
|
58137
58199
|
}
|
|
58138
58200
|
const num = Number(raw);
|
|
58139
58201
|
if (!Number.isFinite(num)) return String(raw ?? "\u2014");
|
|
58140
|
-
|
|
58141
|
-
if (fmt.includes("$")) return "$" + Math.round(num).toLocaleString();
|
|
58142
|
-
if (fmt.includes("%")) return (num < 2 ? (num * 100).toFixed(1) : num.toFixed(1)) + "%";
|
|
58143
|
-
return Math.round(num).toLocaleString();
|
|
58202
|
+
return formatMetricValue(num, metric.format ?? "");
|
|
58144
58203
|
}
|
|
58145
58204
|
function renderEyebrow(text) {
|
|
58146
58205
|
return `<div class="slide-eyebrow">${escapeHtml(text)}</div>`;
|
|
@@ -58166,21 +58225,22 @@ function pageFooter(index, _total, mark) {
|
|
|
58166
58225
|
<div class="slide-page-num">${String(index + 1).padStart(2, "0")}</div>`;
|
|
58167
58226
|
}
|
|
58168
58227
|
var COVER_DECO = `<svg viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg" style="width:260px;opacity:0.9">
|
|
58169
|
-
<circle cx="160" cy="160" r="140" fill="none" stroke="#e5e3d8" stroke-width="1"/>
|
|
58170
|
-
<circle cx="160" cy="160" r="100" fill="none" stroke="#e5e3d8" stroke-width="1"/>
|
|
58171
|
-
<circle cx="160" cy="160" r="60" fill="#eef2f7" stroke="#1b365d" stroke-width="1.2"/>
|
|
58172
|
-
<path d="M160 20 A140 140 0 0 1 300 160" fill="none" stroke="#1b365d" stroke-width="2.2" stroke-linecap="round"/>
|
|
58173
|
-
<path d="M300 160 A140 140 0 0 1 160 300" fill="none" stroke="#6b6a64" stroke-width="1" stroke-linecap="round"/>
|
|
58174
|
-
<path d="M160 300 A140 140 0 0 1 20 160" fill="none" stroke="#6b6a64" stroke-width="1" stroke-linecap="round"/>
|
|
58175
|
-
<path d="M20 160 A140 140 0 0 1 160 20" fill="none" stroke="#6b6a64" stroke-width="1" stroke-linecap="round"/>
|
|
58228
|
+
<circle cx="160" cy="160" r="140" fill="none" stroke="var(--mv-border, #e5e3d8)" stroke-width="1"/>
|
|
58229
|
+
<circle cx="160" cy="160" r="100" fill="none" stroke="var(--mv-border, #e5e3d8)" stroke-width="1"/>
|
|
58230
|
+
<circle cx="160" cy="160" r="60" fill="var(--mv-surface, #eef2f7)" stroke="var(--mv-brand, #1b365d)" stroke-width="1.2"/>
|
|
58231
|
+
<path d="M160 20 A140 140 0 0 1 300 160" fill="none" stroke="var(--mv-brand, #1b365d)" stroke-width="2.2" stroke-linecap="round"/>
|
|
58232
|
+
<path d="M300 160 A140 140 0 0 1 160 300" fill="none" stroke="var(--mv-muted, #6b6a64)" stroke-width="1" stroke-linecap="round"/>
|
|
58233
|
+
<path d="M160 300 A140 140 0 0 1 20 160" fill="none" stroke="var(--mv-muted, #6b6a64)" stroke-width="1" stroke-linecap="round"/>
|
|
58234
|
+
<path d="M20 160 A140 140 0 0 1 160 20" fill="none" stroke="var(--mv-muted, #6b6a64)" stroke-width="1" stroke-linecap="round"/>
|
|
58176
58235
|
</svg>`;
|
|
58177
|
-
function renderCoverSlide(slide, _rows, _svg, index, total) {
|
|
58236
|
+
function renderCoverSlide(slide, _rows, _svg, index, total, deckDescription) {
|
|
58237
|
+
const subtitle = slide.claim ?? deckDescription;
|
|
58178
58238
|
return `<div class="slide">
|
|
58179
58239
|
<div class="slide-cover">
|
|
58180
58240
|
<div class="slide-cover-left">
|
|
58181
58241
|
<div class="slide-mark">miao-vision</div>
|
|
58182
58242
|
<h1>${escapeHtml(slide.title ?? "Presentation")}</h1>
|
|
58183
|
-
${
|
|
58243
|
+
${subtitle ? `<div class="sub">${escapeHtml(subtitle)}</div>` : ""}
|
|
58184
58244
|
<div class="line"></div>
|
|
58185
58245
|
<div class="meta">${escapeHtml(slide.eyebrow ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10))}</div>
|
|
58186
58246
|
</div>
|
|
@@ -58266,18 +58326,6 @@ function renderEndingSlide(slide, _rows, _svg, index, total) {
|
|
|
58266
58326
|
|
|
58267
58327
|
// src/deck-renderer.ts
|
|
58268
58328
|
var SLIDE_CSS = `
|
|
58269
|
-
:root {
|
|
58270
|
-
--mv-paper: #f5f4ed;
|
|
58271
|
-
--mv-surface: #faf9f5;
|
|
58272
|
-
--mv-brand: #1b365d;
|
|
58273
|
-
--mv-ink: #141413;
|
|
58274
|
-
--mv-muted: #6b6a64;
|
|
58275
|
-
--mv-soft: #504e49;
|
|
58276
|
-
--mv-border: #e5e3d8;
|
|
58277
|
-
--mv-serif: Charter, Georgia, "Times New Roman", serif;
|
|
58278
|
-
--mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
|
|
58279
|
-
--slide-scale: 1;
|
|
58280
|
-
}
|
|
58281
58329
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
58282
58330
|
body { font-family: var(--mv-serif); -webkit-font-smoothing: antialiased; }
|
|
58283
58331
|
|
|
@@ -58369,7 +58417,7 @@ var SLIDE_CSS = `
|
|
|
58369
58417
|
.slide:last-child { break-after: auto; page-break-after: auto; }
|
|
58370
58418
|
.slide-nav { display: none !important; }
|
|
58371
58419
|
}
|
|
58372
|
-
@page { size: A4 landscape; margin: 0; background: #f5f4ed; }
|
|
58420
|
+
@page { size: A4 landscape; margin: 0; background: var(--mv-paper, #f5f4ed); }
|
|
58373
58421
|
`;
|
|
58374
58422
|
var SLIDE_JS = `
|
|
58375
58423
|
(function() {
|
|
@@ -58421,10 +58469,14 @@ var SLIDE_JS = `
|
|
|
58421
58469
|
goTo(0);
|
|
58422
58470
|
})();
|
|
58423
58471
|
`;
|
|
58424
|
-
function
|
|
58472
|
+
function extractRootVars(css) {
|
|
58473
|
+
const match = css.match(/:root\s*\{([\s\S]*?)\}/);
|
|
58474
|
+
return match ? `:root {${match[1]}}` : "";
|
|
58475
|
+
}
|
|
58476
|
+
function renderSlide(slide, rows, svgTheme, index, total, deckDescription) {
|
|
58425
58477
|
switch (slide.layout) {
|
|
58426
58478
|
case "cover":
|
|
58427
|
-
return renderCoverSlide(slide, rows, svgTheme, index, total);
|
|
58479
|
+
return renderCoverSlide(slide, rows, svgTheme, index, total, deckDescription);
|
|
58428
58480
|
case "title-only":
|
|
58429
58481
|
return renderTitleOnlySlide(slide, rows, svgTheme, index, total);
|
|
58430
58482
|
case "text-points":
|
|
@@ -58443,16 +58495,19 @@ function renderSlide(slide, rows, svgTheme, index, total) {
|
|
|
58443
58495
|
}
|
|
58444
58496
|
function renderDeckHtml(spec, rows, themeOverride) {
|
|
58445
58497
|
const theme = getTheme(themeOverride ?? spec.theme ?? "editorial");
|
|
58498
|
+
const themeRootVars = extractRootVars(theme.css);
|
|
58446
58499
|
const title = spec.title ?? "Presentation";
|
|
58447
58500
|
const total = spec.slides.length;
|
|
58448
|
-
const slidesHtml = spec.slides.map((slide, i) => renderSlide(slide, rows, theme.svg, i, total)).join("\n");
|
|
58501
|
+
const slidesHtml = spec.slides.map((slide, i) => renderSlide(slide, rows, theme.svg, i, total, spec.description)).join("\n");
|
|
58449
58502
|
return `<!doctype html>
|
|
58450
58503
|
<html lang="en">
|
|
58451
58504
|
<head>
|
|
58452
58505
|
<meta charset="utf-8" />
|
|
58453
58506
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
58507
|
+
${spec.description ? `<meta name="description" content="${escapeHtml(spec.description)}" />` : ""}
|
|
58454
58508
|
<title>${escapeHtml(title)}</title>
|
|
58455
58509
|
<style>${SLIDE_CSS}</style>
|
|
58510
|
+
${themeRootVars ? `<style id="miao-deck-theme">${themeRootVars}</style>` : ""}
|
|
58456
58511
|
</head>
|
|
58457
58512
|
<body class="present-mode">
|
|
58458
58513
|
<div class="slide-viewport">
|
|
@@ -58574,6 +58629,14 @@ function validateDeckSpecSemantics(spec) {
|
|
|
58574
58629
|
hint: hintForIssue(path, "at most 4 metrics")
|
|
58575
58630
|
});
|
|
58576
58631
|
}
|
|
58632
|
+
if (slide.charts && slide.charts.length > 1) {
|
|
58633
|
+
const path = `slides[${index}].charts`;
|
|
58634
|
+
errors.push({
|
|
58635
|
+
path,
|
|
58636
|
+
message: `${path}: A slide can include at most 1 chart.`,
|
|
58637
|
+
hint: hintForIssue(path, "at most 1 chart")
|
|
58638
|
+
});
|
|
58639
|
+
}
|
|
58577
58640
|
if (slide.layout === "table-full" && slide.charts?.[0] && slide.charts[0].type !== "table") {
|
|
58578
58641
|
const path = `slides[${index}].charts[0].type`;
|
|
58579
58642
|
errors.push({
|
|
@@ -58686,6 +58749,7 @@ function hintForIssue(path, message) {
|
|
|
58686
58749
|
if (message.includes("requires at least one chart")) return `Add a chart under ${path}.`;
|
|
58687
58750
|
if (message.includes("requires at least one metric")) return `Add one to four metrics under ${path}.`;
|
|
58688
58751
|
if (message.includes("at most 4 metrics")) return `Reduce ${path} to four metrics or split them across multiple slides.`;
|
|
58752
|
+
if (message.includes("at most 1 chart")) return `Reduce ${path} to a single chart or spread multiple charts across separate slides.`;
|
|
58689
58753
|
if (message.includes("only accepts a table chart")) return `Change ${path} to 'table' or use a chart-focused layout.`;
|
|
58690
58754
|
return `Check ${path} in the DeckSpec.`;
|
|
58691
58755
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
week,channel,impressions,clicks,conversions,spend
|
|
2
|
+
2025-W01,Social,52000,2100,85,3400
|
|
3
|
+
2025-W01,Search,38000,1850,72,2900
|
|
4
|
+
2025-W01,Email,15000,980,45,1200
|
|
5
|
+
2025-W01,Display,28000,620,18,2100
|
|
6
|
+
2025-W02,Social,58000,2400,98,3600
|
|
7
|
+
2025-W02,Search,42000,2100,84,3100
|
|
8
|
+
2025-W02,Email,17000,1050,50,1250
|
|
9
|
+
2025-W02,Display,31000,680,22,2200
|
|
10
|
+
2025-W03,Social,65000,2750,112,3800
|
|
11
|
+
2025-W03,Search,46000,2300,92,3200
|
|
12
|
+
2025-W03,Email,19000,1120,55,1300
|
|
13
|
+
2025-W03,Display,35000,750,26,2300
|
|
14
|
+
2025-W04,Social,72000,3100,128,4000
|
|
15
|
+
2025-W04,Search,51000,2500,101,3400
|
|
16
|
+
2025-W04,Email,21000,1200,60,1400
|
|
17
|
+
2025-W04,Display,38000,820,30,2400
|
|
18
|
+
2025-W05,Social,68000,2900,118,3900
|
|
19
|
+
2025-W05,Search,48000,2400,95,3300
|
|
20
|
+
2025-W05,Email,20000,1150,57,1350
|
|
21
|
+
2025-W05,Display,36000,790,28,2350
|
|
22
|
+
2025-W06,Social,76000,3300,135,4200
|
|
23
|
+
2025-W06,Search,54000,2650,108,3500
|
|
24
|
+
2025-W06,Email,23000,1280,65,1450
|
|
25
|
+
2025-W06,Display,40000,860,33,2500
|
|
26
|
+
2025-W07,Social,81000,3550,148,4400
|
|
27
|
+
2025-W07,Search,58000,2800,115,3600
|
|
28
|
+
2025-W07,Email,25000,1350,70,1500
|
|
29
|
+
2025-W07,Display,43000,910,36,2600
|
|
30
|
+
2025-W08,Social,88000,3900,162,4600
|
|
31
|
+
2025-W08,Search,62000,3000,125,3800
|
|
32
|
+
2025-W08,Email,27000,1420,75,1550
|
|
33
|
+
2025-W08,Display,46000,960,40,2700
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
title: Campaign Performance Report
|
|
2
|
+
theme: dark
|
|
3
|
+
slides:
|
|
4
|
+
- layout: cover
|
|
5
|
+
eyebrow: "2025 · Q1 Campaigns"
|
|
6
|
+
title: "Campaign Performance"
|
|
7
|
+
claim: "Social and Search channels drove 74% of conversions with improving efficiency."
|
|
8
|
+
|
|
9
|
+
- layout: metrics-chart
|
|
10
|
+
eyebrow: "01 · CAMPAIGN SNAPSHOT"
|
|
11
|
+
title: "Scale Improved While Efficiency Stayed Strong"
|
|
12
|
+
metrics:
|
|
13
|
+
- label: Total Impressions
|
|
14
|
+
format: ".0s"
|
|
15
|
+
data:
|
|
16
|
+
transform:
|
|
17
|
+
- type: aggregate
|
|
18
|
+
measures:
|
|
19
|
+
- field: impressions
|
|
20
|
+
op: sum
|
|
21
|
+
as: v
|
|
22
|
+
- label: Total Clicks
|
|
23
|
+
format: ".0s"
|
|
24
|
+
data:
|
|
25
|
+
transform:
|
|
26
|
+
- type: aggregate
|
|
27
|
+
measures:
|
|
28
|
+
- field: clicks
|
|
29
|
+
op: sum
|
|
30
|
+
as: v
|
|
31
|
+
- label: Total Spend
|
|
32
|
+
format: "$,.0f"
|
|
33
|
+
data:
|
|
34
|
+
transform:
|
|
35
|
+
- type: aggregate
|
|
36
|
+
measures:
|
|
37
|
+
- field: spend
|
|
38
|
+
op: sum
|
|
39
|
+
as: v
|
|
40
|
+
charts:
|
|
41
|
+
- type: line
|
|
42
|
+
title: Weekly Clicks
|
|
43
|
+
data:
|
|
44
|
+
transform:
|
|
45
|
+
- type: aggregate
|
|
46
|
+
groupBy: [week]
|
|
47
|
+
measures:
|
|
48
|
+
- field: clicks
|
|
49
|
+
op: sum
|
|
50
|
+
as: total
|
|
51
|
+
- type: sort
|
|
52
|
+
field: week
|
|
53
|
+
order: asc
|
|
54
|
+
encoding:
|
|
55
|
+
x: { field: week }
|
|
56
|
+
y: { field: total }
|
|
57
|
+
|
|
58
|
+
- layout: text-chart
|
|
59
|
+
eyebrow: "02 · CHANNEL EFFICIENCY"
|
|
60
|
+
title: "Social Scales While Email Converts"
|
|
61
|
+
annotation: "Social drives the most volume; Email has the best conversion rate per impression."
|
|
62
|
+
bullets:
|
|
63
|
+
- "Social: 41% of conversions, CPA trending down over the campaign."
|
|
64
|
+
- "Search: consistent volume with stable CPA."
|
|
65
|
+
- "Display: lowest CTR at 2.2%, but useful for top-of-funnel reach."
|
|
66
|
+
charts:
|
|
67
|
+
- type: scatter
|
|
68
|
+
title: Spend vs Conversions
|
|
69
|
+
data:
|
|
70
|
+
transform:
|
|
71
|
+
- type: aggregate
|
|
72
|
+
groupBy: [channel]
|
|
73
|
+
measures:
|
|
74
|
+
- field: spend
|
|
75
|
+
op: sum
|
|
76
|
+
as: total_spend
|
|
77
|
+
- field: conversions
|
|
78
|
+
op: sum
|
|
79
|
+
as: total_conversions
|
|
80
|
+
encoding:
|
|
81
|
+
x: { field: total_spend }
|
|
82
|
+
y: { field: total_conversions }
|
|
83
|
+
|
|
84
|
+
- layout: title-only
|
|
85
|
+
title: "03 · Channel Performance"
|
|
86
|
+
|
|
87
|
+
- layout: chart-full
|
|
88
|
+
eyebrow: "04 · DISTRIBUTION"
|
|
89
|
+
title: "Impression Distribution"
|
|
90
|
+
charts:
|
|
91
|
+
- type: histogram
|
|
92
|
+
title: Impression Distribution
|
|
93
|
+
encoding:
|
|
94
|
+
x: { field: impressions }
|
|
95
|
+
|
|
96
|
+
- layout: table-full
|
|
97
|
+
eyebrow: "05 · TOP CAMPAIGNS"
|
|
98
|
+
title: "Top Campaigns by Conversions"
|
|
99
|
+
charts:
|
|
100
|
+
- type: table
|
|
101
|
+
title: Top Campaigns
|
|
102
|
+
data:
|
|
103
|
+
transform:
|
|
104
|
+
- type: sort
|
|
105
|
+
field: conversions
|
|
106
|
+
order: desc
|
|
107
|
+
- type: limit
|
|
108
|
+
value: 10
|
|
109
|
+
encoding:
|
|
110
|
+
x: { field: channel }
|
|
111
|
+
y: { field: conversions }
|
|
112
|
+
|
|
113
|
+
- layout: ending
|
|
114
|
+
title: "Scale Social, protect Search, test Email retargeting"
|
|
115
|
+
claim: "Increase Social budget 15% and test Display retargeting in Q2."
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
title: Executive Overview
|
|
2
|
+
description: Revenue grew 22% QoQ driven by Alpha product adoption in East and South regions.
|
|
3
|
+
theme: editorial
|
|
4
|
+
slides:
|
|
5
|
+
- layout: cover
|
|
6
|
+
eyebrow: "2025 · Q1 Review"
|
|
7
|
+
title: "Executive Overview"
|
|
8
|
+
claim: "Revenue grew 22% QoQ driven by strong Enterprise product adoption."
|
|
9
|
+
|
|
10
|
+
- layout: title-only
|
|
11
|
+
title: "01 · Performance Highlights"
|
|
12
|
+
|
|
13
|
+
- layout: metrics-chart
|
|
14
|
+
eyebrow: "01 · PERFORMANCE HIGHLIGHTS"
|
|
15
|
+
title: "Revenue Growth Accelerated While Margins Held"
|
|
16
|
+
metrics:
|
|
17
|
+
- label: Total Revenue
|
|
18
|
+
format: "$,.0f"
|
|
19
|
+
data:
|
|
20
|
+
transform:
|
|
21
|
+
- type: aggregate
|
|
22
|
+
measures:
|
|
23
|
+
- field: revenue
|
|
24
|
+
op: sum
|
|
25
|
+
as: v
|
|
26
|
+
- label: Total Units
|
|
27
|
+
format: ",.0f"
|
|
28
|
+
data:
|
|
29
|
+
transform:
|
|
30
|
+
- type: aggregate
|
|
31
|
+
measures:
|
|
32
|
+
- field: units
|
|
33
|
+
op: sum
|
|
34
|
+
as: v
|
|
35
|
+
- label: Total Profit
|
|
36
|
+
format: "$,.0f"
|
|
37
|
+
data:
|
|
38
|
+
transform:
|
|
39
|
+
- type: aggregate
|
|
40
|
+
measures:
|
|
41
|
+
- field: profit
|
|
42
|
+
op: sum
|
|
43
|
+
as: v
|
|
44
|
+
- label: Avg Revenue
|
|
45
|
+
format: "$,.0f"
|
|
46
|
+
data:
|
|
47
|
+
transform:
|
|
48
|
+
- type: aggregate
|
|
49
|
+
measures:
|
|
50
|
+
- field: revenue
|
|
51
|
+
op: avg
|
|
52
|
+
as: v
|
|
53
|
+
charts:
|
|
54
|
+
- type: area
|
|
55
|
+
title: Monthly Revenue
|
|
56
|
+
data:
|
|
57
|
+
transform:
|
|
58
|
+
- type: derive-month
|
|
59
|
+
field: date
|
|
60
|
+
as: month
|
|
61
|
+
- type: aggregate
|
|
62
|
+
groupBy: [month]
|
|
63
|
+
measures:
|
|
64
|
+
- field: revenue
|
|
65
|
+
op: sum
|
|
66
|
+
as: total
|
|
67
|
+
- type: sort
|
|
68
|
+
field: month
|
|
69
|
+
order: asc
|
|
70
|
+
encoding:
|
|
71
|
+
x: { field: month }
|
|
72
|
+
y: { field: total }
|
|
73
|
+
|
|
74
|
+
- layout: text-points
|
|
75
|
+
eyebrow: "02 · KEY INSIGHTS"
|
|
76
|
+
title: "Revenue Drivers"
|
|
77
|
+
claim: "Three trends shaped the quarter: Enterprise expansion, regional balance, and product mix."
|
|
78
|
+
bullets:
|
|
79
|
+
- "Enterprise segment (Alpha + Gamma) contributed 68% of total revenue across all regions."
|
|
80
|
+
- "East region grew 29% QoQ, the fastest among all four regions."
|
|
81
|
+
- "Product Alpha leads with 42% revenue share, up from 40% in January."
|
|
82
|
+
callout: "Recommendation: Expand Alpha capacity in North region to capture untapped demand."
|
|
83
|
+
|
|
84
|
+
- layout: title-only
|
|
85
|
+
title: "02 · Revenue Breakdown"
|
|
86
|
+
|
|
87
|
+
- layout: text-chart
|
|
88
|
+
eyebrow: "03 · PRODUCT MIX"
|
|
89
|
+
title: "Product Revenue Is Concentrated in Alpha"
|
|
90
|
+
annotation: "Alpha is the top revenue product across every region."
|
|
91
|
+
bullets:
|
|
92
|
+
- "Alpha: 42% share, driven by Enterprise accounts."
|
|
93
|
+
- "Beta: 31% share, strongest in East and South."
|
|
94
|
+
- "Gamma: 27% share, growth opportunity in West."
|
|
95
|
+
charts:
|
|
96
|
+
- type: pie
|
|
97
|
+
title: Revenue by Product
|
|
98
|
+
data:
|
|
99
|
+
transform:
|
|
100
|
+
- type: aggregate
|
|
101
|
+
groupBy: [product]
|
|
102
|
+
measures:
|
|
103
|
+
- field: revenue
|
|
104
|
+
op: sum
|
|
105
|
+
as: total
|
|
106
|
+
- type: sort
|
|
107
|
+
field: total
|
|
108
|
+
order: desc
|
|
109
|
+
encoding:
|
|
110
|
+
label: { field: product }
|
|
111
|
+
value: { field: total }
|
|
112
|
+
|
|
113
|
+
- layout: chart-full
|
|
114
|
+
eyebrow: "04 · REGIONAL"
|
|
115
|
+
title: "Revenue by Region"
|
|
116
|
+
charts:
|
|
117
|
+
- type: bar
|
|
118
|
+
title: Revenue by Region
|
|
119
|
+
data:
|
|
120
|
+
transform:
|
|
121
|
+
- type: aggregate
|
|
122
|
+
groupBy: [region]
|
|
123
|
+
measures:
|
|
124
|
+
- field: revenue
|
|
125
|
+
op: sum
|
|
126
|
+
as: total
|
|
127
|
+
- type: sort
|
|
128
|
+
field: total
|
|
129
|
+
order: desc
|
|
130
|
+
encoding:
|
|
131
|
+
x: { field: region }
|
|
132
|
+
y: { field: total }
|
|
133
|
+
color: { field: region }
|
|
134
|
+
|
|
135
|
+
- layout: ending
|
|
136
|
+
title: "Focus on North region growth"
|
|
137
|
+
claim: "Enterprise product expansion in North is the highest-ROI opportunity for Q2."
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
date,region,product,segment,revenue,units,cost,profit
|
|
2
|
+
2025-01-01,East,Alpha,Enterprise,45000,120,28000,17000
|
|
3
|
+
2025-01-01,East,Beta,SMB,32000,85,21000,11000
|
|
4
|
+
2025-01-01,East,Gamma,Enterprise,28000,70,19000,9000
|
|
5
|
+
2025-01-01,West,Alpha,Enterprise,38000,100,25000,13000
|
|
6
|
+
2025-01-01,West,Beta,SMB,29000,78,20000,9000
|
|
7
|
+
2025-01-01,West,Gamma,Enterprise,22000,55,16000,6000
|
|
8
|
+
2025-01-01,North,Alpha,Enterprise,31000,82,21000,10000
|
|
9
|
+
2025-01-01,North,Beta,SMB,24000,65,17000,7000
|
|
10
|
+
2025-01-01,North,Gamma,Enterprise,18000,48,13000,5000
|
|
11
|
+
2025-01-01,South,Alpha,Enterprise,35000,92,23000,12000
|
|
12
|
+
2025-01-01,South,Beta,SMB,26000,70,18000,8000
|
|
13
|
+
2025-01-01,South,Gamma,Enterprise,20000,52,14000,6000
|
|
14
|
+
2025-02-01,East,Alpha,Enterprise,51000,135,31000,20000
|
|
15
|
+
2025-02-01,East,Beta,SMB,36000,95,23000,13000
|
|
16
|
+
2025-02-01,East,Gamma,Enterprise,32000,80,21000,11000
|
|
17
|
+
2025-02-01,West,Alpha,Enterprise,42000,110,27000,15000
|
|
18
|
+
2025-02-01,West,Beta,SMB,32000,86,22000,10000
|
|
19
|
+
2025-02-01,West,Gamma,Enterprise,25000,62,18000,7000
|
|
20
|
+
2025-02-01,North,Alpha,Enterprise,35000,92,23000,12000
|
|
21
|
+
2025-02-01,North,Beta,SMB,27000,72,19000,8000
|
|
22
|
+
2025-02-01,North,Gamma,Enterprise,21000,55,15000,6000
|
|
23
|
+
2025-02-01,South,Alpha,Enterprise,39000,102,25000,14000
|
|
24
|
+
2025-02-01,South,Beta,SMB,29000,78,20000,9000
|
|
25
|
+
2025-02-01,South,Gamma,Enterprise,23000,60,16000,7000
|
|
26
|
+
2025-03-01,East,Alpha,Enterprise,58000,150,34000,24000
|
|
27
|
+
2025-03-01,East,Beta,SMB,40000,105,25000,15000
|
|
28
|
+
2025-03-01,East,Gamma,Enterprise,36000,90,23000,13000
|
|
29
|
+
2025-03-01,West,Alpha,Enterprise,48000,125,30000,18000
|
|
30
|
+
2025-03-01,West,Beta,SMB,36000,95,24000,12000
|
|
31
|
+
2025-03-01,West,Gamma,Enterprise,29000,72,20000,9000
|
|
32
|
+
2025-03-01,North,Alpha,Enterprise,40000,105,26000,14000
|
|
33
|
+
2025-03-01,North,Beta,SMB,31000,82,21000,10000
|
|
34
|
+
2025-03-01,North,Gamma,Enterprise,24000,62,17000,7000
|
|
35
|
+
2025-03-01,South,Alpha,Enterprise,44000,115,28000,16000
|
|
36
|
+
2025-03-01,South,Beta,SMB,33000,88,22000,11000
|
|
37
|
+
2025-03-01,South,Gamma,Enterprise,26000,68,18000,8000
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
week,channel,impressions,clicks,conversions,spend
|
|
2
|
+
2025-W01,Social,52000,2100,85,3400
|
|
3
|
+
2025-W01,Search,38000,1850,72,2900
|
|
4
|
+
2025-W01,Email,15000,980,45,1200
|
|
5
|
+
2025-W01,Display,28000,620,18,2100
|
|
6
|
+
2025-W02,Social,58000,2400,98,3600
|
|
7
|
+
2025-W02,Search,42000,2100,84,3100
|
|
8
|
+
2025-W02,Email,17000,1050,50,1250
|
|
9
|
+
2025-W02,Display,31000,680,22,2200
|
|
10
|
+
2025-W03,Social,65000,2750,112,3800
|
|
11
|
+
2025-W03,Search,46000,2300,92,3200
|
|
12
|
+
2025-W03,Email,19000,1120,55,1300
|
|
13
|
+
2025-W03,Display,35000,750,26,2300
|
|
14
|
+
2025-W04,Social,72000,3100,128,4000
|
|
15
|
+
2025-W04,Search,51000,2500,101,3400
|
|
16
|
+
2025-W04,Email,21000,1200,60,1400
|
|
17
|
+
2025-W04,Display,38000,820,30,2400
|
|
18
|
+
2025-W05,Social,68000,2900,118,3900
|
|
19
|
+
2025-W05,Search,48000,2400,95,3300
|
|
20
|
+
2025-W05,Email,20000,1150,57,1350
|
|
21
|
+
2025-W05,Display,36000,790,28,2350
|
|
22
|
+
2025-W06,Social,76000,3300,135,4200
|
|
23
|
+
2025-W06,Search,54000,2650,108,3500
|
|
24
|
+
2025-W06,Email,23000,1280,65,1450
|
|
25
|
+
2025-W06,Display,40000,860,33,2500
|
|
26
|
+
2025-W07,Social,81000,3550,148,4400
|
|
27
|
+
2025-W07,Search,58000,2800,115,3600
|
|
28
|
+
2025-W07,Email,25000,1350,70,1500
|
|
29
|
+
2025-W07,Display,43000,910,36,2600
|
|
30
|
+
2025-W08,Social,88000,3900,162,4600
|
|
31
|
+
2025-W08,Search,62000,3000,125,3800
|
|
32
|
+
2025-W08,Email,27000,1420,75,1550
|
|
33
|
+
2025-W08,Display,46000,960,40,2700
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
title: Campaign Performance Report
|
|
2
|
+
theme: dark
|
|
3
|
+
slides:
|
|
4
|
+
- layout: cover
|
|
5
|
+
eyebrow: "2025 · Q1 Campaigns"
|
|
6
|
+
title: "Campaign Performance"
|
|
7
|
+
claim: "Social and Search channels drove 74% of conversions with improving efficiency."
|
|
8
|
+
|
|
9
|
+
- layout: metrics-chart
|
|
10
|
+
eyebrow: "01 · CAMPAIGN SNAPSHOT"
|
|
11
|
+
title: "Scale Improved While Efficiency Stayed Strong"
|
|
12
|
+
metrics:
|
|
13
|
+
- label: Total Impressions
|
|
14
|
+
format: ".0s"
|
|
15
|
+
data:
|
|
16
|
+
transform:
|
|
17
|
+
- type: aggregate
|
|
18
|
+
measures:
|
|
19
|
+
- field: impressions
|
|
20
|
+
op: sum
|
|
21
|
+
as: v
|
|
22
|
+
- label: Total Clicks
|
|
23
|
+
format: ".0s"
|
|
24
|
+
data:
|
|
25
|
+
transform:
|
|
26
|
+
- type: aggregate
|
|
27
|
+
measures:
|
|
28
|
+
- field: clicks
|
|
29
|
+
op: sum
|
|
30
|
+
as: v
|
|
31
|
+
- label: Total Spend
|
|
32
|
+
format: "$,.0f"
|
|
33
|
+
data:
|
|
34
|
+
transform:
|
|
35
|
+
- type: aggregate
|
|
36
|
+
measures:
|
|
37
|
+
- field: spend
|
|
38
|
+
op: sum
|
|
39
|
+
as: v
|
|
40
|
+
charts:
|
|
41
|
+
- type: line
|
|
42
|
+
title: Weekly Clicks
|
|
43
|
+
data:
|
|
44
|
+
transform:
|
|
45
|
+
- type: aggregate
|
|
46
|
+
groupBy: [week]
|
|
47
|
+
measures:
|
|
48
|
+
- field: clicks
|
|
49
|
+
op: sum
|
|
50
|
+
as: total
|
|
51
|
+
- type: sort
|
|
52
|
+
field: week
|
|
53
|
+
order: asc
|
|
54
|
+
encoding:
|
|
55
|
+
x: { field: week }
|
|
56
|
+
y: { field: total }
|
|
57
|
+
|
|
58
|
+
- layout: text-chart
|
|
59
|
+
eyebrow: "02 · CHANNEL EFFICIENCY"
|
|
60
|
+
title: "Social Scales While Email Converts"
|
|
61
|
+
annotation: "Social drives the most volume; Email has the best conversion rate per impression."
|
|
62
|
+
bullets:
|
|
63
|
+
- "Social: 41% of conversions, CPA trending down over the campaign."
|
|
64
|
+
- "Search: consistent volume with stable CPA."
|
|
65
|
+
- "Display: lowest CTR at 2.2%, but useful for top-of-funnel reach."
|
|
66
|
+
charts:
|
|
67
|
+
- type: scatter
|
|
68
|
+
title: Spend vs Conversions
|
|
69
|
+
data:
|
|
70
|
+
transform:
|
|
71
|
+
- type: aggregate
|
|
72
|
+
groupBy: [channel]
|
|
73
|
+
measures:
|
|
74
|
+
- field: spend
|
|
75
|
+
op: sum
|
|
76
|
+
as: total_spend
|
|
77
|
+
- field: conversions
|
|
78
|
+
op: sum
|
|
79
|
+
as: total_conversions
|
|
80
|
+
encoding:
|
|
81
|
+
x: { field: total_spend }
|
|
82
|
+
y: { field: total_conversions }
|
|
83
|
+
|
|
84
|
+
- layout: title-only
|
|
85
|
+
title: "03 · Channel Performance"
|
|
86
|
+
|
|
87
|
+
- layout: chart-full
|
|
88
|
+
eyebrow: "04 · DISTRIBUTION"
|
|
89
|
+
title: "Impression Distribution"
|
|
90
|
+
charts:
|
|
91
|
+
- type: histogram
|
|
92
|
+
title: Impression Distribution
|
|
93
|
+
encoding:
|
|
94
|
+
x: { field: impressions }
|
|
95
|
+
|
|
96
|
+
- layout: table-full
|
|
97
|
+
eyebrow: "05 · TOP CAMPAIGNS"
|
|
98
|
+
title: "Top Campaigns by Conversions"
|
|
99
|
+
charts:
|
|
100
|
+
- type: table
|
|
101
|
+
title: Top Campaigns
|
|
102
|
+
data:
|
|
103
|
+
transform:
|
|
104
|
+
- type: sort
|
|
105
|
+
field: conversions
|
|
106
|
+
order: desc
|
|
107
|
+
- type: limit
|
|
108
|
+
value: 10
|
|
109
|
+
encoding:
|
|
110
|
+
x: { field: channel }
|
|
111
|
+
y: { field: conversions }
|
|
112
|
+
|
|
113
|
+
- layout: ending
|
|
114
|
+
title: "Scale Social, protect Search, test Email retargeting"
|
|
115
|
+
claim: "Increase Social budget 15% and test Display retargeting in Q2."
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
title: Executive Overview
|
|
2
|
+
description: Revenue grew 22% QoQ driven by Alpha product adoption in East and South regions.
|
|
3
|
+
theme: editorial
|
|
4
|
+
slides:
|
|
5
|
+
- layout: cover
|
|
6
|
+
eyebrow: "2025 · Q1 Review"
|
|
7
|
+
title: "Executive Overview"
|
|
8
|
+
claim: "Revenue grew 22% QoQ driven by strong Enterprise product adoption."
|
|
9
|
+
|
|
10
|
+
- layout: title-only
|
|
11
|
+
title: "01 · Performance Highlights"
|
|
12
|
+
|
|
13
|
+
- layout: metrics-chart
|
|
14
|
+
eyebrow: "01 · PERFORMANCE HIGHLIGHTS"
|
|
15
|
+
title: "Revenue Growth Accelerated While Margins Held"
|
|
16
|
+
metrics:
|
|
17
|
+
- label: Total Revenue
|
|
18
|
+
format: "$,.0f"
|
|
19
|
+
data:
|
|
20
|
+
transform:
|
|
21
|
+
- type: aggregate
|
|
22
|
+
measures:
|
|
23
|
+
- field: revenue
|
|
24
|
+
op: sum
|
|
25
|
+
as: v
|
|
26
|
+
- label: Total Units
|
|
27
|
+
format: ",.0f"
|
|
28
|
+
data:
|
|
29
|
+
transform:
|
|
30
|
+
- type: aggregate
|
|
31
|
+
measures:
|
|
32
|
+
- field: units
|
|
33
|
+
op: sum
|
|
34
|
+
as: v
|
|
35
|
+
- label: Total Profit
|
|
36
|
+
format: "$,.0f"
|
|
37
|
+
data:
|
|
38
|
+
transform:
|
|
39
|
+
- type: aggregate
|
|
40
|
+
measures:
|
|
41
|
+
- field: profit
|
|
42
|
+
op: sum
|
|
43
|
+
as: v
|
|
44
|
+
- label: Avg Revenue
|
|
45
|
+
format: "$,.0f"
|
|
46
|
+
data:
|
|
47
|
+
transform:
|
|
48
|
+
- type: aggregate
|
|
49
|
+
measures:
|
|
50
|
+
- field: revenue
|
|
51
|
+
op: avg
|
|
52
|
+
as: v
|
|
53
|
+
charts:
|
|
54
|
+
- type: area
|
|
55
|
+
title: Monthly Revenue
|
|
56
|
+
data:
|
|
57
|
+
transform:
|
|
58
|
+
- type: derive-month
|
|
59
|
+
field: date
|
|
60
|
+
as: month
|
|
61
|
+
- type: aggregate
|
|
62
|
+
groupBy: [month]
|
|
63
|
+
measures:
|
|
64
|
+
- field: revenue
|
|
65
|
+
op: sum
|
|
66
|
+
as: total
|
|
67
|
+
- type: sort
|
|
68
|
+
field: month
|
|
69
|
+
order: asc
|
|
70
|
+
encoding:
|
|
71
|
+
x: { field: month }
|
|
72
|
+
y: { field: total }
|
|
73
|
+
|
|
74
|
+
- layout: text-points
|
|
75
|
+
eyebrow: "02 · KEY INSIGHTS"
|
|
76
|
+
title: "Revenue Drivers"
|
|
77
|
+
claim: "Three trends shaped the quarter: Enterprise expansion, regional balance, and product mix."
|
|
78
|
+
bullets:
|
|
79
|
+
- "Enterprise segment (Alpha + Gamma) contributed 68% of total revenue across all regions."
|
|
80
|
+
- "East region grew 29% QoQ, the fastest among all four regions."
|
|
81
|
+
- "Product Alpha leads with 42% revenue share, up from 40% in January."
|
|
82
|
+
callout: "Recommendation: Expand Alpha capacity in North region to capture untapped demand."
|
|
83
|
+
|
|
84
|
+
- layout: title-only
|
|
85
|
+
title: "02 · Revenue Breakdown"
|
|
86
|
+
|
|
87
|
+
- layout: text-chart
|
|
88
|
+
eyebrow: "03 · PRODUCT MIX"
|
|
89
|
+
title: "Product Revenue Is Concentrated in Alpha"
|
|
90
|
+
annotation: "Alpha is the top revenue product across every region."
|
|
91
|
+
bullets:
|
|
92
|
+
- "Alpha: 42% share, driven by Enterprise accounts."
|
|
93
|
+
- "Beta: 31% share, strongest in East and South."
|
|
94
|
+
- "Gamma: 27% share, growth opportunity in West."
|
|
95
|
+
charts:
|
|
96
|
+
- type: pie
|
|
97
|
+
title: Revenue by Product
|
|
98
|
+
data:
|
|
99
|
+
transform:
|
|
100
|
+
- type: aggregate
|
|
101
|
+
groupBy: [product]
|
|
102
|
+
measures:
|
|
103
|
+
- field: revenue
|
|
104
|
+
op: sum
|
|
105
|
+
as: total
|
|
106
|
+
- type: sort
|
|
107
|
+
field: total
|
|
108
|
+
order: desc
|
|
109
|
+
encoding:
|
|
110
|
+
label: { field: product }
|
|
111
|
+
value: { field: total }
|
|
112
|
+
|
|
113
|
+
- layout: chart-full
|
|
114
|
+
eyebrow: "04 · REGIONAL"
|
|
115
|
+
title: "Revenue by Region"
|
|
116
|
+
charts:
|
|
117
|
+
- type: bar
|
|
118
|
+
title: Revenue by Region
|
|
119
|
+
data:
|
|
120
|
+
transform:
|
|
121
|
+
- type: aggregate
|
|
122
|
+
groupBy: [region]
|
|
123
|
+
measures:
|
|
124
|
+
- field: revenue
|
|
125
|
+
op: sum
|
|
126
|
+
as: total
|
|
127
|
+
- type: sort
|
|
128
|
+
field: total
|
|
129
|
+
order: desc
|
|
130
|
+
encoding:
|
|
131
|
+
x: { field: region }
|
|
132
|
+
y: { field: total }
|
|
133
|
+
color: { field: region }
|
|
134
|
+
|
|
135
|
+
- layout: ending
|
|
136
|
+
title: "Focus on North region growth"
|
|
137
|
+
claim: "Enterprise product expansion in North is the highest-ROI opportunity for Q2."
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
date,region,product,segment,revenue,units,cost,profit
|
|
2
|
+
2025-01-01,East,Alpha,Enterprise,45000,120,28000,17000
|
|
3
|
+
2025-01-01,East,Beta,SMB,32000,85,21000,11000
|
|
4
|
+
2025-01-01,East,Gamma,Enterprise,28000,70,19000,9000
|
|
5
|
+
2025-01-01,West,Alpha,Enterprise,38000,100,25000,13000
|
|
6
|
+
2025-01-01,West,Beta,SMB,29000,78,20000,9000
|
|
7
|
+
2025-01-01,West,Gamma,Enterprise,22000,55,16000,6000
|
|
8
|
+
2025-01-01,North,Alpha,Enterprise,31000,82,21000,10000
|
|
9
|
+
2025-01-01,North,Beta,SMB,24000,65,17000,7000
|
|
10
|
+
2025-01-01,North,Gamma,Enterprise,18000,48,13000,5000
|
|
11
|
+
2025-01-01,South,Alpha,Enterprise,35000,92,23000,12000
|
|
12
|
+
2025-01-01,South,Beta,SMB,26000,70,18000,8000
|
|
13
|
+
2025-01-01,South,Gamma,Enterprise,20000,52,14000,6000
|
|
14
|
+
2025-02-01,East,Alpha,Enterprise,51000,135,31000,20000
|
|
15
|
+
2025-02-01,East,Beta,SMB,36000,95,23000,13000
|
|
16
|
+
2025-02-01,East,Gamma,Enterprise,32000,80,21000,11000
|
|
17
|
+
2025-02-01,West,Alpha,Enterprise,42000,110,27000,15000
|
|
18
|
+
2025-02-01,West,Beta,SMB,32000,86,22000,10000
|
|
19
|
+
2025-02-01,West,Gamma,Enterprise,25000,62,18000,7000
|
|
20
|
+
2025-02-01,North,Alpha,Enterprise,35000,92,23000,12000
|
|
21
|
+
2025-02-01,North,Beta,SMB,27000,72,19000,8000
|
|
22
|
+
2025-02-01,North,Gamma,Enterprise,21000,55,15000,6000
|
|
23
|
+
2025-02-01,South,Alpha,Enterprise,39000,102,25000,14000
|
|
24
|
+
2025-02-01,South,Beta,SMB,29000,78,20000,9000
|
|
25
|
+
2025-02-01,South,Gamma,Enterprise,23000,60,16000,7000
|
|
26
|
+
2025-03-01,East,Alpha,Enterprise,58000,150,34000,24000
|
|
27
|
+
2025-03-01,East,Beta,SMB,40000,105,25000,15000
|
|
28
|
+
2025-03-01,East,Gamma,Enterprise,36000,90,23000,13000
|
|
29
|
+
2025-03-01,West,Alpha,Enterprise,48000,125,30000,18000
|
|
30
|
+
2025-03-01,West,Beta,SMB,36000,95,24000,12000
|
|
31
|
+
2025-03-01,West,Gamma,Enterprise,29000,72,20000,9000
|
|
32
|
+
2025-03-01,North,Alpha,Enterprise,40000,105,26000,14000
|
|
33
|
+
2025-03-01,North,Beta,SMB,31000,82,21000,10000
|
|
34
|
+
2025-03-01,North,Gamma,Enterprise,24000,62,17000,7000
|
|
35
|
+
2025-03-01,South,Alpha,Enterprise,44000,115,28000,16000
|
|
36
|
+
2025-03-01,South,Beta,SMB,33000,88,22000,11000
|
|
37
|
+
2025-03-01,South,Gamma,Enterprise,26000,68,18000,8000
|
package/package.json
CHANGED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
title: Sales Dashboard
|
|
2
|
-
description: Example Miao Vision report generated from sales.csv.
|
|
3
|
-
charts:
|
|
4
|
-
- type: bigvalue
|
|
5
|
-
title: Total Sales
|
|
6
|
-
data:
|
|
7
|
-
transform:
|
|
8
|
-
- type: aggregate
|
|
9
|
-
measures:
|
|
10
|
-
- field: sales
|
|
11
|
-
op: sum
|
|
12
|
-
as: total_sales
|
|
13
|
-
encoding:
|
|
14
|
-
value:
|
|
15
|
-
field: total_sales
|
|
16
|
-
- type: line
|
|
17
|
-
title: Monthly Sales Trend
|
|
18
|
-
data:
|
|
19
|
-
transform:
|
|
20
|
-
- type: derive-month
|
|
21
|
-
field: order_date
|
|
22
|
-
as: order_month
|
|
23
|
-
- type: aggregate
|
|
24
|
-
groupBy: [order_month]
|
|
25
|
-
measures:
|
|
26
|
-
- field: sales
|
|
27
|
-
op: sum
|
|
28
|
-
as: total_sales
|
|
29
|
-
- type: sort
|
|
30
|
-
field: order_month
|
|
31
|
-
order: asc
|
|
32
|
-
encoding:
|
|
33
|
-
x:
|
|
34
|
-
field: order_month
|
|
35
|
-
y:
|
|
36
|
-
field: total_sales
|
|
37
|
-
- type: bar
|
|
38
|
-
title: Sales by Region
|
|
39
|
-
data:
|
|
40
|
-
transform:
|
|
41
|
-
- type: aggregate
|
|
42
|
-
groupBy: [region]
|
|
43
|
-
measures:
|
|
44
|
-
- field: sales
|
|
45
|
-
op: sum
|
|
46
|
-
as: total_sales
|
|
47
|
-
- type: sort
|
|
48
|
-
field: total_sales
|
|
49
|
-
order: desc
|
|
50
|
-
encoding:
|
|
51
|
-
x:
|
|
52
|
-
field: region
|
|
53
|
-
y:
|
|
54
|
-
field: total_sales
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
title: Sales Dashboard
|
|
2
|
-
description: Example Miao Vision report generated from sales.csv.
|
|
3
|
-
charts:
|
|
4
|
-
- type: bigvalue
|
|
5
|
-
title: Total Sales
|
|
6
|
-
data:
|
|
7
|
-
transform:
|
|
8
|
-
- type: aggregate
|
|
9
|
-
measures:
|
|
10
|
-
- field: sales
|
|
11
|
-
op: sum
|
|
12
|
-
as: total_sales
|
|
13
|
-
encoding:
|
|
14
|
-
value:
|
|
15
|
-
field: total_sales
|
|
16
|
-
- type: line
|
|
17
|
-
title: Monthly Sales Trend
|
|
18
|
-
data:
|
|
19
|
-
transform:
|
|
20
|
-
- type: derive-month
|
|
21
|
-
field: order_date
|
|
22
|
-
as: order_month
|
|
23
|
-
- type: aggregate
|
|
24
|
-
groupBy: [order_month]
|
|
25
|
-
measures:
|
|
26
|
-
- field: sales
|
|
27
|
-
op: sum
|
|
28
|
-
as: total_sales
|
|
29
|
-
- type: sort
|
|
30
|
-
field: order_month
|
|
31
|
-
order: asc
|
|
32
|
-
encoding:
|
|
33
|
-
x:
|
|
34
|
-
field: order_month
|
|
35
|
-
y:
|
|
36
|
-
field: total_sales
|
|
37
|
-
- type: bar
|
|
38
|
-
title: Sales by Region
|
|
39
|
-
data:
|
|
40
|
-
transform:
|
|
41
|
-
- type: aggregate
|
|
42
|
-
groupBy: [region]
|
|
43
|
-
measures:
|
|
44
|
-
- field: sales
|
|
45
|
-
op: sum
|
|
46
|
-
as: total_sales
|
|
47
|
-
- type: sort
|
|
48
|
-
field: total_sales
|
|
49
|
-
order: desc
|
|
50
|
-
encoding:
|
|
51
|
-
x:
|
|
52
|
-
field: region
|
|
53
|
-
y:
|
|
54
|
-
field: total_sales
|