@ggterm/core 0.3.6 → 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 +140 -49
- 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,42 +14650,31 @@ 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
14663
|
let styleDebounce = null;
|
|
14657
|
-
let lastStyleBroadcast = 0;
|
|
14658
14664
|
watch(getGGTermDir(), (_event, filename) => {
|
|
14659
|
-
if (filename !== "last-plot-vegalite.json"
|
|
14665
|
+
if (filename !== "last-plot-vegalite.json")
|
|
14660
14666
|
return;
|
|
14661
14667
|
if (styleDebounce)
|
|
14662
14668
|
clearTimeout(styleDebounce);
|
|
14663
14669
|
styleDebounce = setTimeout(() => {
|
|
14664
|
-
|
|
14665
|
-
|
|
14670
|
+
if (Date.now() - lastNewPlotTime < 2000)
|
|
14671
|
+
return;
|
|
14672
|
+
const vegaLitePath = join3(getGGTermDir(), "last-plot-vegalite.json");
|
|
14673
|
+
if (!existsSync3(vegaLitePath))
|
|
14666
14674
|
return;
|
|
14667
|
-
lastStyleBroadcast = now;
|
|
14668
14675
|
try {
|
|
14669
|
-
|
|
14676
|
+
const spec = JSON.parse(readFileSync3(vegaLitePath, "utf-8"));
|
|
14670
14677
|
const latestId = getLatestPlotId();
|
|
14671
|
-
if (filename === "last-plot.json") {
|
|
14672
|
-
const plotPath = join3(getGGTermDir(), "last-plot.json");
|
|
14673
|
-
if (!existsSync3(plotPath))
|
|
14674
|
-
return;
|
|
14675
|
-
const plot = JSON.parse(readFileSync3(plotPath, "utf-8"));
|
|
14676
|
-
const geomTypes = plot._provenance?.geomTypes || [];
|
|
14677
|
-
const hasCompositeMark = geomTypes.some((t) => COMPOSITE_MARKS.has(t));
|
|
14678
|
-
spec = plotSpecToVegaLite(plot.spec, { interactive: !hasCompositeMark });
|
|
14679
|
-
} else {
|
|
14680
|
-
const vegaLitePath = join3(getGGTermDir(), "last-plot-vegalite.json");
|
|
14681
|
-
if (!existsSync3(vegaLitePath))
|
|
14682
|
-
return;
|
|
14683
|
-
spec = JSON.parse(readFileSync3(vegaLitePath, "utf-8"));
|
|
14684
|
-
}
|
|
14685
|
-
if (!spec)
|
|
14686
|
-
return;
|
|
14687
14678
|
const provenance = {
|
|
14688
14679
|
id: latestId || "styled",
|
|
14689
14680
|
description: "Styled plot",
|
|
@@ -15103,6 +15094,14 @@ async function renderSpec(spec) {
|
|
|
15103
15094
|
}
|
|
15104
15095
|
}
|
|
15105
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
|
+
|
|
15106
15105
|
async function showPlot(data) {
|
|
15107
15106
|
await renderSpec(data.spec);
|
|
15108
15107
|
updateMeta(data.provenance);
|
|
@@ -15241,7 +15240,7 @@ import { join as join4 } from "path";
|
|
|
15241
15240
|
// src/init.ts
|
|
15242
15241
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync2, existsSync as existsSync2, readdirSync as readdirSync2, statSync } from "fs";
|
|
15243
15242
|
import { join as join2, extname } from "path";
|
|
15244
|
-
var SKILLS_VERSION = "0.3.
|
|
15243
|
+
var SKILLS_VERSION = "0.3.7";
|
|
15245
15244
|
var SKILLS = {
|
|
15246
15245
|
"data-load": {
|
|
15247
15246
|
files: {
|
|
@@ -15518,30 +15517,41 @@ allowed-tools: Read, Write, Bash(npx:*)
|
|
|
15518
15517
|
|
|
15519
15518
|
Modify Vega-Lite specifications based on natural language requests.
|
|
15520
15519
|
|
|
15521
|
-
##
|
|
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.
|
|
15522
15523
|
|
|
15523
|
-
|
|
15524
|
-
- \`.ggterm/last-plot.json\` - Original PlotSpec
|
|
15525
|
-
- \`.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.
|
|
15526
15525
|
|
|
15527
15526
|
## Common Customizations
|
|
15528
15527
|
|
|
15528
|
+
All examples below modify properties of the Vega-Lite spec read from \`.ggterm/last-plot-vegalite.json\`:
|
|
15529
|
+
|
|
15529
15530
|
### Title and Labels
|
|
15530
15531
|
|
|
15531
15532
|
\`\`\`javascript
|
|
15532
15533
|
spec.title = "New Title"
|
|
15534
|
+
spec.title = { text: "Title", subtitle: "Subtitle" }
|
|
15533
15535
|
spec.encoding.x.title = "X Axis Label"
|
|
15534
15536
|
spec.encoding.y.title = "Y Axis Label"
|
|
15537
|
+
spec.encoding.color.title = "Legend Title"
|
|
15535
15538
|
\`\`\`
|
|
15536
15539
|
|
|
15537
15540
|
### Colors
|
|
15538
15541
|
|
|
15539
15542
|
\`\`\`javascript
|
|
15540
|
-
|
|
15541
|
-
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
|
+
\`\`\`
|
|
15542
15547
|
|
|
15543
|
-
|
|
15544
|
-
|
|
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 }
|
|
15545
15555
|
\`\`\`
|
|
15546
15556
|
|
|
15547
15557
|
### Dimensions
|
|
@@ -15553,9 +15563,9 @@ spec.height = 400
|
|
|
15553
15563
|
|
|
15554
15564
|
## Workflow
|
|
15555
15565
|
|
|
15556
|
-
1. Read \`.ggterm/last-plot-vegalite.json\`
|
|
15557
|
-
2.
|
|
15558
|
-
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\`
|
|
15559
15569
|
4. **DONE** — the live viewer auto-detects the change and displays the customized plot
|
|
15560
15570
|
|
|
15561
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.
|
|
@@ -15576,26 +15586,107 @@ allowed-tools: Read, Write, Bash(npx:*)
|
|
|
15576
15586
|
|
|
15577
15587
|
Apply expert-curated style presets to Vega-Lite specifications for publication-quality output.
|
|
15578
15588
|
|
|
15579
|
-
##
|
|
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.
|
|
15580
15592
|
|
|
15581
|
-
|
|
15582
|
-
|--------|-------------|---------------------|
|
|
15583
|
-
| \`wilke\` | Claus Wilke's *Fundamentals of Data Visualization* | Minimal, clean, no chartjunk, subtle gridlines |
|
|
15584
|
-
| \`tufte\` | Edward Tufte's data-ink ratio principles | Maximum data-ink, no grid, no borders |
|
|
15585
|
-
| \`nature\` | Nature journal style | Clean, serif fonts, specific dimensions |
|
|
15586
|
-
| \`economist\` | The Economist charts | Bold colors, distinctive style |
|
|
15587
|
-
| \`minimal\` | Generic minimal style | No grid, no borders, clean |
|
|
15588
|
-
| \`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.
|
|
15589
15594
|
|
|
15590
15595
|
## Workflow
|
|
15591
15596
|
|
|
15592
|
-
1. Read \`.ggterm/last-plot-vegalite.json\`
|
|
15593
|
-
2.
|
|
15594
|
-
3.
|
|
15595
|
-
4.
|
|
15596
|
-
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
|
|
15597
15637
|
|
|
15598
|
-
|
|
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
|
+
\`\`\`
|
|
15599
15690
|
|
|
15600
15691
|
## Response Format
|
|
15601
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"}
|