A graph draws the art of a column or marker design inside a series again
from the stored design. Rows, effects and graphic styles that a command
gave that art were lost the next time the graph's data, type or size
changed. The paint commands already left the art out.
- The appearance.* row and whole-appearance commands, effect.apply,
appearance.addEffect and the effect.* commands that edit, move or
remove an effect, threeD.mapGraphic, graphicStyle.apply,
graphicStyle.addFromLibrary with apply, transparency.set with a fill
or stroke item, and appearance.copyFrom (as the target) leave out any
object inside a series group other than a path directly in it, given
by id, selected or reached through target: "contents". They edit the
other objects given, and a command whose objects are all design art
is an error.
- appearance.transfer with design art as its target, or as its source
without copy, is an error.
- A Pathfinder effect no longer groups selected design art.
- The paint commands given a design's copy with a fill or stroke item
leave it out as well.
docs/mcp.md states the rule, and the Graphs line in
docs/target-app-parity.md names it.
A legacy .ai graph (%_Gs ... %_GS) opened as plain art, with its table,
type, axes and settings left out. A grouped column, stacked column, line
or area graph now keeps them on its group when every record has the
shape and values the version 7 specification's appendix A gives, the
table holds at least one number, the drawn art strokes the plot's left
and bottom edges, and each series group is tagged once as a whole
column, holds only paths and paints them with one fill and one stroke.
The saved art stays as it is on open; Graph Data redraws the graph from
its data afterward, with each series' fill and stroke kept.
Any other graph (pie and scatter graphs, designs, customizations, record
shapes of later versions, tables past 10,000 categories, 256 series or
2,600,000 cells) keeps its art as plain objects with the existing note.
Saving a graph to .ai, in either form, now warns that its data and
settings are not written.
A path directly in a graph series lost what these commands gave it when
the graph was drawn again, for example after graph.setData:
- While Global Edit is on in an isolated graph, a match that is a series
path, or a series group whose paths take the edit, now has what
changed on its paths stored for their series: the paint, weight,
opacity and blend mode of the topmost visible fill and stroke, and the
object's opacity and blend mode. The edited match is stored by its own
command as before.
- addon.arrange.randomizeOpacity and addon.arrange.sort with apply
"opacity" now store the object opacity, with the blend mode, of the
series paths whose opacity they change. When they change several
paths of one series, the frontmost of them sets what the graph
stores, as for the other commands.
The graph stores them in the same undo step as the edit. The params
text of addon.arrange.randomizeOpacity and addon.arrange.sort,
docs/mcp.md and docs/target-app-parity.md describe the new behavior.
A fill or stroke row that the Appearance commands gave a graph label, its
object opacity, and the characters the Eyedropper gave it lasted only
until the graph was drawn again: the graph stored nothing for a label's
rows, and the Eyedropper's character attributes were not stored.
- The graph keeps, for value axis numbers, category labels and legend
labels, the paint, weight, opacity and blend mode of a label's topmost
visible fill and stroke row, their order and place relative to the
Characters row, and the label's object opacity and blend mode
(labelStyles valuesRows, categoriesRows, legendRows). Every label of
the kind gets those rows when the graph is drawn again, with a placed
gradient fitted to each label.
- Every appearance.* command stores them, and so do graphicStyle.apply
and redefine and the paint, stroke, gradient and transparency edits
aimed at a row, even when the label already showed them.
transparency.set without a row and object.setProps store only the
object opacity and blend mode. With several labels of a kind, the last
one edited wins.
- appearance.copyFrom onto all of a label's text stores the character
attributes it applied and, from type, the paragraph attributes; a
transparency pick stores the object opacity and blend mode, and
append stores the rows.
- paint.setFill and paint.setStroke store a character fill or stroke
only when the characters take the paint (the whole label, or all of
its text highlighted with the Type tool); aimed at a row, they store
the row.
- Document Color Mode and swatch edits reach the kept rows.
Docs: docs/mcp.md, the commands' params text, docs/target-app-parity.md.
The graph compares the paints a command leaves on it with the paints it
stored before the command, not with the value before each mark's
capture. Apply Fill to Stroke on two marks whose strokes already had
their fills stored the back mark's stroke and then the front mark's
again, and recorded an undo step with nothing changed. The same
comparison applies to the opacity and blend mode a series keeps.
docs/mcp.md states that only the topmost visible row's paint is stored,
and the Graphs line of docs/target-app-parity.md states that a series
that draws Filled Lines bands keeps no stroke paint or weight.
vectorcraft_testkit::temp_dir returns a bare path, so every engine test
that wrote into one left the folder in the system temporary folder.
- testkit: TempDir, a test's own folder made through temp_dir (same
private creation and ownership checks) under a tag no other TempDir in
the process uses, removed with its contents when dropped, also when
the test panics.
- Engine unit and integration tests hold a TempDir for the whole test
instead of calling temp_dir: graph, fileio, compare, journal, library,
shortcut set, spelling, store, web export, cancel, containers, build,
color settings, command sweep, font folder, removed font, model-based
and the font search fuzz.
- The DCS and swatch library tests' own helpers and the PDF editing
tests' shared vc-pdfedit-<pid> folder use a TempDir per test too.
- The font and link file search, store, color settings and font folder
helpers no longer delete the private folder temp_dir checked and make
it again with default permissions.
A graph draws its series groups again with no rows of their own, so a
fill, stroke, opacity or graphic style that a command put on a series
group was lost the next time the graph's data, type or size changed,
and the graph stored nothing. paint.setFill and paint.setStroke already
pass a series group's id on to the paths directly inside it.
- appearance.addFill, addStroke, setItem, removeItem, duplicateItem and
moveItem, graphicStyle.apply and transparency.set with a fill or
stroke item now edit the paths directly in a series group given by id
or picked with Group Selection, and the graph stores what they change.
A series group with no such path, or with a fill or stroke row of its
own, is still edited itself, and appearance.moveItem from "contents"
still moves the group's own Contents row.
- appearance.clear, appearance.reduceToBasic, appearance.showAllHidden
and graphicStyle.breakLink edit the group as well as its paths.
- graphicStyle.apply without add and appearance.transfer onto a series
group clear the group's own opacity, blend mode, isolation, knockout,
effects and style link, and graphicStyle.apply with add unlinks the
group. A transfer source that is one of the group's paths keeps its
look, and a source that is the group's only path is an error.
- graphicStyle.redefine passes the style to the paths of a linked series
group, other than the source and the linked paths whose look was
edited, and clears and unlinks the group.
- graphicStyle.new, graphicStyle.redefine and appearance.transfer read a
series group that holds no row, effect, opacity, blend mode,
isolation, knockout or style link of its own through the topmost path
directly in it, and a move clears each of those paths. A series group
that holds one of them is read itself, as before.
- The Graphic Styles panel reads the style link of such a selected
series group from that path.
Docs: docs/mcp.md, docs/target-app-parity.md. Not yet: the Appearance
panel and appearance.setActiveItem still read the selected group's own
rows, and the effect commands and the paint, stroke and gradient
commands with an item still edit the group itself.
Follows #5501.
paint.setFill, paint.setStroke, paint.none, Apply Fill to Stroke, Apply
Stroke to Fill and a library gradient or pattern applied with library.use
stored the topmost fill or stroke row of a graph series mark on the graph
even when that row was hidden, and stored a stroke set on a Filled Lines
band. When the graph was drawn again, every mark of the series took a
paint that the edited mark never showed, and a band took the stroke color
as its fill.
These commands now follow the rules of the Appearance commands:
- The graph stores the paint only when the row the command wrote is the
topmost visible row of its kind, or when the command changed what the
mark shows. With `item`, that is the named row.
- A series that draws Filled Lines bands stores no stroke paint or
weight; the band keeps its own outline.
- A row without paint before and after the command keeps what the graph
stores, so None on a marker without a stroke no longer removes the
line's stored stroke.
- When one command writes several marks of a series, the frontmost mark
sets what the graph stores, whatever the order of the ids.
- Apply Fill to Stroke and Apply Stroke to Fill on a mark whose row
already has the paint store it, as paint.setFill does.
A document without graph series marks among the edited objects skips the
comparison of paints.
Docs: docs/mcp.md and the params text of the paint commands.
A stroke weight set with stroke.set or stroke.weightUp/weightDown, a
gradient made, placed or edited with paint.editGradient,
paint.setGradientGeom or the freeform gradient edits, and colors changed
by paint.invert, paint.complement, the Edit Colors recolor and Blend
commands, recolor.apply, addon.color.filter,
addon.color.applyNearestSwatch or the ink limit of
addon.color.printFixes changed a series mark but not the paint the graph
stores, so the mark went back to the old paint when the graph was drawn
again.
appearance::edit_items now stores what its edit changes on the topmost
visible fill and stroke of series marks, as the Appearance commands do,
and the recolor pass does the same for the series marks it reaches,
including those inside a series group or a graph it is given. When one
command changes several marks of a series, the frontmost one sets the
stored paint. A gradient is stored with its placement.
These commands do not store the colors they give a graph's axes and
labels. docs/mcp.md, the params text and the Graphs line in
docs/target-app-parity.md say what is stored.
A whole pick from a source with no fill row, or no stroke row, removes
that row from the target. When the target is a graph series mark whose
row had paint, the pick now replaces the row opacity and blend mode the
graph keeps for that kind of row in the series. A row that had no paint
before the pick still leaves the kept values as they are, and a pick of
some attributes from such a source is unchanged.
An Eyedropper pick that includes transparency now counts a fill or stroke
row that had paint before the pick and has none after it when it stores
the series' row opacity and blend mode on the graph, as graphic styles
already do. Before, such a pick left the opacity and blend mode another
mark of the series had stored, and the series was drawn with them again
after its data changed. A row that had no paint before the pick still
leaves the stored values as they are.
graph.setType read `axisMin: "10"` as a cleared bound, so the axis went
back to the calculated range, and it ignored a string or number given for
a true/false option, a string for a number and a number for a text option.
graph.setData and graph.create ignored a `csv` that is not a string and
`series`, `categories` or `rows` that are not lists, and read a string in
`rows` as a blank cell.
The three commands now refuse such a value with an error naming the key,
and leave the graph and the undo history as they were. A null is still
read as a key left out, and a null axis bound still goes back to the
calculated value. A negative tick count is refused too.
A centered label such as Q||1 has no baseline for its empty middle
line, so a label that keeps more leading was not moved back to its
place. The graph now centers a label whose first and last lines hold
characters, whatever the lines between them hold.
Category labels beside an axis and labels in pie wedges are centered
on their place by the default leading. A multi-line label that keeps
more leading or paragraph spacing ran down from that place instead.
The graph now puts the middle of such a label's first and last
baselines on its place.
The legend measured each label with System Layout off, while the graph
draws the labels with the document's setting. With System Layout on,
a long legend label could run over the next swatch in Legend Across
Top. The legend now measures labels with the same setting.
Paragraph settings given to all of a graph label's text with
text.setFormat (indents, spacing, hyphenation, Justification options,
composer, direction, kashida, kinsoku, mojikumi, burasagari and the
rest) and the label's anti-aliasing method were lost when the graph
drew its labels again, because the graph kept only a character style
for each kind of label. Each kind now also keeps its paragraph settings
and anti-aliasing method, saved with the graph in its label styles, and
the graph still sets each label's alignment for its place.
The legend spaces its entries by the kept legend settings: Legend
Across Top measures each label with its indents and spacing, both
legend layouts make room for extra leading or paragraph spacing, and a
label with a negative indent or negative space before moves right or
down so it stays clear of its swatch and of the entry above it.
Found while testing crates/engine/src/cmd/graph/data.rs:51 (parse_csv); written by crates/doc/src/graph.rs:497 (GraphSpec::to_csv)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/graph/data.rs:45-47 (parse_csv)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/graph/data.rs:166-172 (fmt_value)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Applying or redefining a graphic style on a series mark whose fill or
stroke had paint, when the style leaves that row without paint, now
stores the row's opacity and blend mode on the graph. Before, the
opacity and blend mode another mark of the series left stayed, so a
Filled Lines band's outline kept a stroke opacity after a style without
a stroke went on a stroked marker. A row with no paint before and after
the edit still keeps what the graph stores.
appearance.addFill, appearance.addStroke and appearance.duplicateItem can
put a new topmost row on a series mark with the paint the mark already
shows. When another mark of the series had set a different stored paint,
the mark's top paint did not change, so the graph kept the other mark's
paint and drew it again. A new topmost visible row now stores its paint,
as an Eyedropper append already does.
The Appearance commands do not store a stroke paint or weight for a series
that draws a Filled Lines band, but they do store a stroke opacity set on the
band, and the band's 0.25 pt black outline takes it when the graph is drawn
again. docs/mcp.md now says so, and a test covers it.
paint.setFill, paint.setStroke, paint.none, Apply Fill to Stroke and Apply
Stroke to Fill stored a series' paint on the graph. appearance.setItem, the
Eyedropper, appearance.transfer, Clear Appearance, Reduce to Basic Appearance
and the add, remove, move and duplicate row commands stored no paint or weight.
An Eyedropper pick of a blue fill at 40% onto a red column drew red at 40%
after the next redraw.
These commands and Show All Hidden Attributes now store the paint and weight
of the topmost visible fill and stroke of a path directly in a series group,
in the same undo step. A color, weight or opacity that a command writes to that
row replaces the stored value even when the mark's own value does not change. A
row that has no paint before and after the command does not change the stored
paint. These commands store no stroke for a series that draws Filled Lines
bands, and a band no longer takes its color from an empty stored stroke.
The stored opacity also comes from the topmost visible row: hiding a top row
stores the row under it, and an opacity set on a hidden top row is not stored.
Follows #5501.
An object opacity or blend mode set on a path directly in a graph series, and
the blend mode of its topmost visible fill or stroke, were lost when the graph
was drawn again. The graph now stores them per series next to the row opacity
it already stores, and puts them on every path directly in the series when it
draws the series again.
- transparency.set and object.setProps store the object's opacity and blend
mode. A value the mark already has still replaces the value another mark of
the series stored.
- appearance.clear, appearance.transfer, appearance.copyFrom with Transparency
picked up, graphicStyle.apply without add and graphicStyle.redefine store
the object's opacity and blend mode they leave on the mark.
- The other Appearance and style commands store them when they change them
on a mark.
- Every command that stores the opacity of the topmost visible fill or stroke
also stores its blend mode. A Filled Lines band's outline takes the stored
stroke opacity and blend mode and keeps its black 0.25 pt stroke.
- An opacity and blend mode are stored as a pair from the edited mark:
setting only the opacity of one mark also stores that mark's blend mode.
- A graph design's copy in a series keeps its own values.
Docs: docs/mcp.md, docs/target-app-parity.md.
Applying a graphic style, Redefine Graphic Style, Default Fill and Stroke
and Swap Fill and Stroke on a path in a graph series changed the path
but not the paint the graph stores for the series. When the graph was
drawn again, the series went back to its earlier paint.
These commands now store the mark's topmost visible fill and stroke on
the graph, in the same undo step as the command:
- graphicStyle.apply stores the paint, weight and opacity of both kinds
of row. With `add` it stores only the kinds of row that are visible
in the style.
- graphicStyle.redefine stores the paint, weight and opacity of the
marks still linked to the style.
- paint.default stores the white fill and the 1 pt black stroke, both
opaque.
- paint.swap stores the swapped paints and the stroke weight and keeps
the stored opacity. It swaps the topmost rows even when they are
hidden, and a hidden row it swaps is not stored.
The rule for each kind of mark is the one docs/mcp.md gives for the
Appearance commands. docs/mcp.md also says what the graph does not
store from a graphic style and that a series group given to a graphic
style command is not stored. The params text, docs/mcp.md and the
Graphs line in docs/target-app-parity.md list the commands.
paint.setFill, paint.setStroke, paint.none, Apply Fill to Stroke and Apply
Stroke to Fill stored a series' paint on the graph. appearance.setItem, the
Eyedropper, appearance.transfer, Clear Appearance, Reduce to Basic Appearance
and the add, remove, move and duplicate row commands stored no paint or weight.
An Eyedropper pick of a blue fill at 40% onto a red column drew red at 40%
after the next redraw.
These commands and Show All Hidden Attributes now store the paint and weight
of the topmost visible fill and stroke of a path directly in a series group,
in the same undo step. A color, weight or opacity that a command writes to that
row replaces the stored value even when the mark's own value does not change. A
row that has no paint before and after the command does not change the stored
paint. These commands store no stroke for a series that draws Filled Lines
bands, and a band no longer takes its color from an empty stored stroke.
The stored opacity also comes from the topmost visible row: hiding a top row
stores the row under it, and an opacity set on a hidden top row is not stored.
Follows #5501.
A graph keeps the paint and stroke weight given to a series' marks, but not
the opacity of their fill or stroke row. An opacity set with
`transparency.set {item}` or `appearance.setItem {opacity}` on a column,
bar, line or other series path was lost the next time the graph was drawn
(a data, type or option change).
- `SeriesPaint` gains `fillOpacity` and `strokeOpacity`. A setItem opacity
on the topmost fill or stroke of a series path stores it, in the same
undo step, and the generator puts it on the topmost fill and stroke of
every path directly in that series' group. Graph designs keep their own
opacity. A value read from a file is held to 0..1.
- The Appearance commands that change the opacity of a series path's
topmost fill or stroke (add, remove, duplicate and move a row, Clear
Appearance, Reduce to Basic Appearance, `appearance.transfer` and the
Eyedropper) update the stored opacity. They do not change the stored
paint, which only `paint.setFill` and `paint.setStroke` set.
- An edit that leaves a series path fully opaque stores nothing for a
series the graph keeps nothing for.
A stroke color given without strokeWidth left characters at weight 0, so
nothing was drawn. As paint.setStroke does, a painted stroke now gives a
run with no weight 1 pt, for the characters and for the label styles a
graph keeps; an explicit strokeWidth still sets the weight.