@ggterm/core 0.3.5 → 0.3.8
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-plot.js +151 -31
- package/dist/init.d.ts.map +1 -1
- package/dist/serve.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli-plot.js
CHANGED
|
@@ -14641,6 +14641,8 @@ function handleServe(port) {
|
|
|
14641
14641
|
}
|
|
14642
14642
|
}
|
|
14643
14643
|
}
|
|
14644
|
+
let lastNewPlotTime = 0;
|
|
14645
|
+
let lastBroadcastPlotId = null;
|
|
14644
14646
|
const plotsDir = getPlotsDir();
|
|
14645
14647
|
watch(plotsDir, (_event, filename) => {
|
|
14646
14648
|
if (!filename || !filename.endsWith(".json"))
|
|
@@ -14648,12 +14650,16 @@ function handleServe(port) {
|
|
|
14648
14650
|
if (debounceTimer)
|
|
14649
14651
|
clearTimeout(debounceTimer);
|
|
14650
14652
|
debounceTimer = setTimeout(() => {
|
|
14653
|
+
const latestId = getLatestPlotId();
|
|
14654
|
+
if (!latestId || latestId === lastBroadcastPlotId)
|
|
14655
|
+
return;
|
|
14656
|
+
lastBroadcastPlotId = latestId;
|
|
14657
|
+
lastNewPlotTime = Date.now();
|
|
14651
14658
|
const payload = getLatestPayload();
|
|
14652
14659
|
if (payload)
|
|
14653
14660
|
broadcast(payload);
|
|
14654
14661
|
}, 150);
|
|
14655
14662
|
});
|
|
14656
|
-
const vegaLitePath = join3(getGGTermDir(), "last-plot-vegalite.json");
|
|
14657
14663
|
let styleDebounce = null;
|
|
14658
14664
|
watch(getGGTermDir(), (_event, filename) => {
|
|
14659
14665
|
if (filename !== "last-plot-vegalite.json")
|
|
@@ -14661,15 +14667,23 @@ function handleServe(port) {
|
|
|
14661
14667
|
if (styleDebounce)
|
|
14662
14668
|
clearTimeout(styleDebounce);
|
|
14663
14669
|
styleDebounce = setTimeout(() => {
|
|
14670
|
+
if (Date.now() - lastNewPlotTime < 2000)
|
|
14671
|
+
return;
|
|
14672
|
+
const vegaLitePath = join3(getGGTermDir(), "last-plot-vegalite.json");
|
|
14664
14673
|
if (!existsSync3(vegaLitePath))
|
|
14665
14674
|
return;
|
|
14666
14675
|
try {
|
|
14667
14676
|
const spec = JSON.parse(readFileSync3(vegaLitePath, "utf-8"));
|
|
14668
14677
|
const latestId = getLatestPlotId();
|
|
14669
|
-
const provenance =
|
|
14670
|
-
|
|
14678
|
+
const provenance = {
|
|
14679
|
+
id: latestId || "styled",
|
|
14680
|
+
description: "Styled plot",
|
|
14681
|
+
timestamp: new Date().toISOString(),
|
|
14682
|
+
geomTypes: []
|
|
14683
|
+
};
|
|
14684
|
+
broadcast(JSON.stringify({ type: "update", spec, provenance }));
|
|
14671
14685
|
} catch {}
|
|
14672
|
-
},
|
|
14686
|
+
}, 300);
|
|
14673
14687
|
});
|
|
14674
14688
|
const server = createServer((req, res) => {
|
|
14675
14689
|
const url = new URL(req.url || "/", `http://localhost:${p}`);
|
|
@@ -15080,6 +15094,14 @@ async function renderSpec(spec) {
|
|
|
15080
15094
|
}
|
|
15081
15095
|
}
|
|
15082
15096
|
|
|
15097
|
+
// Re-render on container resize so plot reflows correctly
|
|
15098
|
+
let resizeTimer = null;
|
|
15099
|
+
new ResizeObserver(() => {
|
|
15100
|
+
if (!view) return;
|
|
15101
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
15102
|
+
resizeTimer = setTimeout(() => { view.resize(); }, 150);
|
|
15103
|
+
}).observe(vis);
|
|
15104
|
+
|
|
15083
15105
|
async function showPlot(data) {
|
|
15084
15106
|
await renderSpec(data.spec);
|
|
15085
15107
|
updateMeta(data.provenance);
|
|
@@ -15181,6 +15203,12 @@ function connect() {
|
|
|
15181
15203
|
showPlot(data);
|
|
15182
15204
|
updateNav();
|
|
15183
15205
|
updateHistoryHighlight();
|
|
15206
|
+
} else if (data.type === 'update') {
|
|
15207
|
+
// Style/customize change — replace current plot, don't add to history
|
|
15208
|
+
if (currentIdx >= 0 && currentIdx < history.length) {
|
|
15209
|
+
history[currentIdx] = data;
|
|
15210
|
+
}
|
|
15211
|
+
showPlot(data);
|
|
15184
15212
|
}
|
|
15185
15213
|
};
|
|
15186
15214
|
}
|
|
@@ -15212,7 +15240,7 @@ import { join as join4 } from "path";
|
|
|
15212
15240
|
// src/init.ts
|
|
15213
15241
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync2, existsSync as existsSync2, readdirSync as readdirSync2, statSync } from "fs";
|
|
15214
15242
|
import { join as join2, extname } from "path";
|
|
15215
|
-
var SKILLS_VERSION = "0.3.
|
|
15243
|
+
var SKILLS_VERSION = "0.3.7";
|
|
15216
15244
|
var SKILLS = {
|
|
15217
15245
|
"data-load": {
|
|
15218
15246
|
files: {
|
|
@@ -15489,30 +15517,41 @@ allowed-tools: Read, Write, Bash(npx:*)
|
|
|
15489
15517
|
|
|
15490
15518
|
Modify Vega-Lite specifications based on natural language requests.
|
|
15491
15519
|
|
|
15492
|
-
##
|
|
15520
|
+
## CRITICAL: Which File to Edit
|
|
15521
|
+
|
|
15522
|
+
**ALWAYS read and write \`.ggterm/last-plot-vegalite.json\`** — this is the Vega-Lite spec that the viewer renders.
|
|
15493
15523
|
|
|
15494
|
-
|
|
15495
|
-
- \`.ggterm/last-plot.json\` - Original PlotSpec
|
|
15496
|
-
- \`.ggterm/last-plot-vegalite.json\` - Vega-Lite spec to modify
|
|
15524
|
+
**NEVER modify \`.ggterm/last-plot.json\`** — that is the ggterm terminal format. Changes to it will NOT appear in the viewer.
|
|
15497
15525
|
|
|
15498
15526
|
## Common Customizations
|
|
15499
15527
|
|
|
15528
|
+
All examples below modify properties of the Vega-Lite spec read from \`.ggterm/last-plot-vegalite.json\`:
|
|
15529
|
+
|
|
15500
15530
|
### Title and Labels
|
|
15501
15531
|
|
|
15502
15532
|
\`\`\`javascript
|
|
15503
15533
|
spec.title = "New Title"
|
|
15534
|
+
spec.title = { text: "Title", subtitle: "Subtitle" }
|
|
15504
15535
|
spec.encoding.x.title = "X Axis Label"
|
|
15505
15536
|
spec.encoding.y.title = "Y Axis Label"
|
|
15537
|
+
spec.encoding.color.title = "Legend Title"
|
|
15506
15538
|
\`\`\`
|
|
15507
15539
|
|
|
15508
15540
|
### Colors
|
|
15509
15541
|
|
|
15510
15542
|
\`\`\`javascript
|
|
15511
|
-
|
|
15512
|
-
spec.encoding.color.scale = { scheme: "
|
|
15543
|
+
spec.encoding.color.scale = { scheme: "category10" } // categorical
|
|
15544
|
+
spec.encoding.color.scale = { scheme: "viridis" } // continuous
|
|
15545
|
+
spec.mark.color = "#3366cc" // single color
|
|
15546
|
+
\`\`\`
|
|
15513
15547
|
|
|
15514
|
-
|
|
15515
|
-
|
|
15548
|
+
### Fonts and Config
|
|
15549
|
+
|
|
15550
|
+
\`\`\`javascript
|
|
15551
|
+
spec.config = spec.config || {}
|
|
15552
|
+
spec.config.font = "Helvetica"
|
|
15553
|
+
spec.config.title = { fontSize: 18, fontWeight: "bold" }
|
|
15554
|
+
spec.config.axis = { labelFontSize: 12, titleFontSize: 14 }
|
|
15516
15555
|
\`\`\`
|
|
15517
15556
|
|
|
15518
15557
|
### Dimensions
|
|
@@ -15524,9 +15563,9 @@ spec.height = 400
|
|
|
15524
15563
|
|
|
15525
15564
|
## Workflow
|
|
15526
15565
|
|
|
15527
|
-
1. Read \`.ggterm/last-plot-vegalite.json\`
|
|
15528
|
-
2.
|
|
15529
|
-
3. Write the updated
|
|
15566
|
+
1. Read \`.ggterm/last-plot-vegalite.json\` (NOT last-plot.json)
|
|
15567
|
+
2. Parse as JSON, apply the requested modifications
|
|
15568
|
+
3. Write the updated JSON back to \`.ggterm/last-plot-vegalite.json\`
|
|
15530
15569
|
4. **DONE** — the live viewer auto-detects the change and displays the customized plot
|
|
15531
15570
|
|
|
15532
15571
|
**IMPORTANT**: Do NOT re-create the plot with \`npx ggterm-plot\` after customizing. The viewer watches the spec file and auto-updates. Re-running the plot command would overwrite your customizations.
|
|
@@ -15547,26 +15586,107 @@ allowed-tools: Read, Write, Bash(npx:*)
|
|
|
15547
15586
|
|
|
15548
15587
|
Apply expert-curated style presets to Vega-Lite specifications for publication-quality output.
|
|
15549
15588
|
|
|
15550
|
-
##
|
|
15589
|
+
## CRITICAL: Which File to Edit
|
|
15590
|
+
|
|
15591
|
+
**ALWAYS read and write \`.ggterm/last-plot-vegalite.json\`** — this is the Vega-Lite spec that the viewer renders.
|
|
15551
15592
|
|
|
15552
|
-
|
|
15553
|
-
|--------|-------------|---------------------|
|
|
15554
|
-
| \`wilke\` | Claus Wilke's *Fundamentals of Data Visualization* | Minimal, clean, no chartjunk, subtle gridlines |
|
|
15555
|
-
| \`tufte\` | Edward Tufte's data-ink ratio principles | Maximum data-ink, no grid, no borders |
|
|
15556
|
-
| \`nature\` | Nature journal style | Clean, serif fonts, specific dimensions |
|
|
15557
|
-
| \`economist\` | The Economist charts | Bold colors, distinctive style |
|
|
15558
|
-
| \`minimal\` | Generic minimal style | No grid, no borders, clean |
|
|
15559
|
-
| \`apa\` | APA publication guidelines | Academic papers, grayscale-friendly |
|
|
15593
|
+
**NEVER modify \`.ggterm/last-plot.json\`** — that is the ggterm terminal format. Changes to it will NOT appear in the viewer.
|
|
15560
15594
|
|
|
15561
15595
|
## Workflow
|
|
15562
15596
|
|
|
15563
|
-
1. Read \`.ggterm/last-plot-vegalite.json\`
|
|
15564
|
-
2.
|
|
15565
|
-
3.
|
|
15566
|
-
4.
|
|
15567
|
-
5.
|
|
15597
|
+
1. Read \`.ggterm/last-plot-vegalite.json\` (NOT last-plot.json)
|
|
15598
|
+
2. Parse as JSON
|
|
15599
|
+
3. Set \`spec.config\` to the style config below — do NOT change \`encoding\`, \`data\`, or \`mark\`
|
|
15600
|
+
4. Write the updated JSON back to \`.ggterm/last-plot-vegalite.json\`
|
|
15601
|
+
5. **DONE** — the live viewer auto-detects the change and displays the styled plot
|
|
15602
|
+
|
|
15603
|
+
**IMPORTANT**: Do NOT re-create the plot with \`npx ggterm-plot\` after styling. Re-running would overwrite your style changes.
|
|
15604
|
+
|
|
15605
|
+
## Style Configs (Vega-Lite \`config\` property)
|
|
15606
|
+
|
|
15607
|
+
### Wilke (default for "publication ready")
|
|
15608
|
+
|
|
15609
|
+
\`\`\`json
|
|
15610
|
+
{
|
|
15611
|
+
"font": "Helvetica Neue, Helvetica, Arial, sans-serif",
|
|
15612
|
+
"background": "white",
|
|
15613
|
+
"view": { "stroke": null },
|
|
15614
|
+
"title": { "fontSize": 14, "fontWeight": "normal", "anchor": "start", "offset": 12 },
|
|
15615
|
+
"axis": { "domain": true, "domainColor": "#333333", "domainWidth": 1, "grid": false, "labelColor": "#333333", "labelFontSize": 11, "tickColor": "#333333", "tickSize": 5, "titleColor": "#333333", "titleFontSize": 12, "titleFontWeight": "normal", "titlePadding": 10 },
|
|
15616
|
+
"axisY": { "grid": true, "gridColor": "#ebebeb", "gridWidth": 0.5 },
|
|
15617
|
+
"legend": { "labelFontSize": 11, "titleFontSize": 11, "titleFontWeight": "normal", "symbolSize": 100 },
|
|
15618
|
+
"range": { "category": ["#4C78A8", "#F58518", "#E45756", "#72B7B2", "#54A24B", "#EECA3B", "#B279A2", "#FF9DA6"] }
|
|
15619
|
+
}
|
|
15620
|
+
\`\`\`
|
|
15621
|
+
|
|
15622
|
+
### Tufte
|
|
15623
|
+
|
|
15624
|
+
\`\`\`json
|
|
15625
|
+
{
|
|
15626
|
+
"font": "Georgia, serif",
|
|
15627
|
+
"background": "white",
|
|
15628
|
+
"view": { "stroke": null },
|
|
15629
|
+
"title": { "fontSize": 13, "fontWeight": "normal", "anchor": "start" },
|
|
15630
|
+
"axis": { "domain": false, "grid": false, "labelColor": "#333333", "labelFontSize": 10, "ticks": false, "titleColor": "#333333", "titleFontSize": 11, "titleFontWeight": "normal" },
|
|
15631
|
+
"legend": { "labelFontSize": 10, "titleFontSize": 10, "titleFontWeight": "normal" },
|
|
15632
|
+
"range": { "category": ["#333333", "#666666", "#999999", "#CCCCCC"] }
|
|
15633
|
+
}
|
|
15634
|
+
\`\`\`
|
|
15635
|
+
|
|
15636
|
+
### Nature
|
|
15568
15637
|
|
|
15569
|
-
|
|
15638
|
+
\`\`\`json
|
|
15639
|
+
{
|
|
15640
|
+
"font": "Arial, Helvetica, sans-serif",
|
|
15641
|
+
"background": "white",
|
|
15642
|
+
"view": { "stroke": null },
|
|
15643
|
+
"title": { "fontSize": 10, "fontWeight": "bold" },
|
|
15644
|
+
"axis": { "domain": true, "domainColor": "#000000", "domainWidth": 0.5, "grid": false, "labelColor": "#000000", "labelFontSize": 8, "tickColor": "#000000", "tickSize": 4, "tickWidth": 0.5, "titleColor": "#000000", "titleFontSize": 9, "titleFontWeight": "normal" },
|
|
15645
|
+
"legend": { "labelFontSize": 8, "titleFontSize": 8, "symbolSize": 50 }
|
|
15646
|
+
}
|
|
15647
|
+
\`\`\`
|
|
15648
|
+
|
|
15649
|
+
### Economist
|
|
15650
|
+
|
|
15651
|
+
\`\`\`json
|
|
15652
|
+
{
|
|
15653
|
+
"font": "Officina Sans, Arial, sans-serif",
|
|
15654
|
+
"background": "#d5e4eb",
|
|
15655
|
+
"view": { "stroke": null },
|
|
15656
|
+
"title": { "fontSize": 14, "fontWeight": "bold", "color": "#000000", "anchor": "start" },
|
|
15657
|
+
"axis": { "domain": false, "grid": true, "gridColor": "#ffffff", "gridWidth": 1, "labelColor": "#000000", "labelFontSize": 11, "titleFontSize": 12, "titleFontWeight": "bold" },
|
|
15658
|
+
"axisX": { "grid": false, "domain": true, "domainColor": "#000000" },
|
|
15659
|
+
"legend": { "orient": "top", "labelFontSize": 11, "titleFontSize": 11 },
|
|
15660
|
+
"range": { "category": ["#006BA2", "#3EBCD2", "#379A8B", "#EBB434", "#B4BA39", "#9A607F", "#D73F3F"] }
|
|
15661
|
+
}
|
|
15662
|
+
\`\`\`
|
|
15663
|
+
|
|
15664
|
+
### Minimal
|
|
15665
|
+
|
|
15666
|
+
\`\`\`json
|
|
15667
|
+
{
|
|
15668
|
+
"font": "system-ui, -apple-system, sans-serif",
|
|
15669
|
+
"background": "white",
|
|
15670
|
+
"view": { "stroke": null },
|
|
15671
|
+
"title": { "fontSize": 14, "fontWeight": "normal" },
|
|
15672
|
+
"axis": { "domain": false, "grid": false, "ticks": false, "labelColor": "#666666", "labelFontSize": 11, "titleColor": "#333333", "titleFontSize": 12, "titleFontWeight": "normal" },
|
|
15673
|
+
"legend": { "labelFontSize": 11, "titleFontSize": 11, "titleFontWeight": "normal" }
|
|
15674
|
+
}
|
|
15675
|
+
\`\`\`
|
|
15676
|
+
|
|
15677
|
+
### APA
|
|
15678
|
+
|
|
15679
|
+
\`\`\`json
|
|
15680
|
+
{
|
|
15681
|
+
"font": "Times New Roman, serif",
|
|
15682
|
+
"background": "white",
|
|
15683
|
+
"view": { "stroke": null },
|
|
15684
|
+
"title": { "fontSize": 12, "fontWeight": "bold", "anchor": "middle" },
|
|
15685
|
+
"axis": { "domain": true, "domainColor": "#000000", "grid": false, "labelColor": "#000000", "labelFontSize": 10, "tickColor": "#000000", "titleColor": "#000000", "titleFontSize": 11, "titleFontWeight": "normal", "titleFontStyle": "italic" },
|
|
15686
|
+
"legend": { "labelFontSize": 10, "titleFontSize": 10, "titleFontStyle": "italic" },
|
|
15687
|
+
"range": { "category": ["#000000", "#666666", "#999999", "#CCCCCC"] }
|
|
15688
|
+
}
|
|
15689
|
+
\`\`\`
|
|
15570
15690
|
|
|
15571
15691
|
## Response Format
|
|
15572
15692
|
|
package/dist/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkmBH,wBAAgB,UAAU,IAAI,IAAI,CA2JjC"}
|
package/dist/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwfH,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAqJ/C"}
|