Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

classlib: Plotter: extend tick labels #5942

Merged
merged 14 commits into from
Jan 16, 2023

Conversation

mtmccrea
Copy link
Member

@mtmccrea mtmccrea commented Dec 25, 2022

Purpose and Motivation

This follows up #5161, in response to feedback about retaining previous functionality in how the tick labels are handled in DrawGrid.

In particular this adds functionality so that you can achieve the same look as previous version of SC:

  • Move and align tick axis labels
  • Append a string to axis labels
  • Constrain labels to the edges of the grids
  • en/disable labels independently
  • set the Font and Color of tick and axis labels independently

This PR is unfinished but as it's blocking the next RC, I'm posting it early so those involved can comment on what's been done so far. @dyfer @sternsc.

This required basically a complete overhaul of how the new tick/axis label spacing is calculated so that everything resizes properly. As such, I have a good amount of testing to do.

This PR is now ready for review (I'll clean up the commit history at the final stage).

Depending on the timeline of the RC, documentation won't be the priority, but I'll submit that as a separate PR later if the RC makes it out before I get to it.

Here's a few examples of the new interface to set Plot and DrawDrid properties from Plotter.

(     // default behavior plus axis labels
p = [10, 34, 1672].collect({ |f|
	101.collect{ |i| sin((i/1000) * 2pi * f) }
}).plot;
p.axisLabelY_("Amp")
.axisLabelX_((1..3).collect{ |elem| "X label " ++ elem })
)

(    // vertically compact
p = [10, 34, 1672].collect({ |f|
	101.collect{ |i| sin((i/1000) * 2pi * f) }
}).plot;
p.setGridProperties(\y,
	\labelAnchor, \right, \labelAlign, \center,
	\constrainLabelExtents, true, \labelOffset, -3 @ 0
).setGridProperties(\x,
	\labelAnchor, \leftBottom, \labelAlign, \left,
	\constrainLabelExtents, true, \labelOffset, 3 @ -1,
	\fontColor, Color.red, \labelAppendString, " sec"
).specs_([-1.5, 1.5].asSpec) // give data headroom to see inlaid y tick labels
)

(    // minimal
p = [10, 34, 1672].collect({ |f|
	101.collect{ |i| sin((i/1000) * 2pi * f) }
}).plot;
p.setProperties( \showTickLabelsX, false, \showTickLabelsY, false)
)

The three above examples produce these plots:
Screen Shot 2023-01-03 at 21 56 20

Note that because I opted not to add convenience methods to Plotter that would allow direct access to setting grid properties at this time, that is accomplished with the Plotter:-setGridProperties, which mimics the behavior of Plotter:-setGridProperties:-setProperties, in that it accepts a list of key-value pairs.

The advantage is that setting multiple parameters (as is likely when customizing your grid) is more compact than multiple method calls to individual parameters for each axis. The downside is the user doesn't get the benefit of auto-complete for hints about to the available parameters. So I'll add a section to the docs in the future that will list the grid and plot parameters.

Types of changes

  • Documentation
  • Bug fix
  • New feature

To-do list

  • Code is tested
  • All tests are passing
  • Updated documentation (More to follow this PR)
  • This PR is ready for review

SCVersion.txt Outdated Show resolved Hide resolved
@dyfer dyfer added this to the 3.13.0 milestone Dec 25, 2022
@dyfer dyfer added the comp: class library SC class library label Dec 25, 2022
@mtmccrea mtmccrea force-pushed the topic/drawgrid-extend-ticklabels branch from 6160771 to a488f87 Compare December 28, 2022 19:42
SCClassLibrary/Common/Geometry/Rect.sc Outdated Show resolved Hide resolved
SCClassLibrary/Common/GUI/Base/Grid.sc Outdated Show resolved Hide resolved
SCClassLibrary/Common/GUI/Base/Grid.sc Outdated Show resolved Hide resolved
SCClassLibrary/Common/GUI/PlusGUI/Math/PlotView.sc Outdated Show resolved Hide resolved
SCClassLibrary/Common/GUI/PlusGUI/Math/PlotView.sc Outdated Show resolved Hide resolved
SCClassLibrary/Common/GUI/PlusGUI/Math/PlotView.sc Outdated Show resolved Hide resolved
@mtmccrea mtmccrea force-pushed the topic/drawgrid-extend-ticklabels branch from 52ddc9e to 30d0626 Compare January 2, 2023 10:10
Copy link
Member

@dyfer dyfer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mtmccrea ! I have some cosmetic comments/questions. I'm dismissing my comments for now :)

SCClassLibrary/Common/GUI/PlusGUI/Math/PlotView.sc Outdated Show resolved Hide resolved
SCClassLibrary/Common/GUI/Base/Grid.sc Show resolved Hide resolved
SCClassLibrary/Common/GUI/Base/Grid.sc Show resolved Hide resolved
@mtmccrea

This comment was marked as outdated.

@telephon
Copy link
Member

telephon commented Jan 2, 2023

I think it is completely fine to have a discussion like this before a final version.

@mtmccrea
Copy link
Member Author

mtmccrea commented Jan 3, 2023

OK, I would consider this "review-ready" at this point 😆.

I've updated the topic post with some details and examples. As mentioned there, I won't get to complete docs before RC2, but I think the interface is stable at this point (pending any feedback), so could go into the RC.

And I plan to do a hefty cleanup of the commit history once the discussion concludes here.

I've resolved a number of the Conversations above, but left some open in case you'd like to respond, otherwise feel free to Resolve them if you're satisfied.

Thanks!

@mtmccrea mtmccrea force-pushed the topic/drawgrid-extend-ticklabels branch from 150ea1e to f79a73f Compare January 3, 2023 20:42
@sternsc
Copy link

sternsc commented Jan 4, 2023 via email

@mtmccrea
Copy link
Member Author

mtmccrea commented Jan 4, 2023

@sternsc
This PR can be considered as an extension of the previous one which added much more functionality than a modification of labelOffset. Because you noticed there was this breaking change, I wanted to make sure the old functionality was still replicable. But again, that's only a small part of the additions.

So just as a heads up, your code will still likely need to be updated. Here's an example that recreates some of the things you missed about the previous version (in particular labelOffset, and strings appended to tick labels):

// ~ Old Plotter replicated functionality: x labels at top, with strings appended
(
var gridHeight, freq = 22;
p = 101.collect({ |i| sin((i/1000)*2*pi* freq)}).plot;
gridHeight = p.plots[0].plotBounds.height;

p.setGridProperties(\x,
	\labelAnchor, \topLeft,
	\labelAlign, \left,
	\labelOffset, 8 @ gridHeight.neg,
	\labelAppendString, " xxx",
	\constrainLabelExtents, true,
).setGridProperties(\y,
	\labelAnchor, \bottomLeft,
	\labelAlign, \left,
	\labelOffset, 3 @ -3
);
)

If you plan for your views to dynamically resize, you can make sure extreme tick label offsets stay in place this way:

(
// Because use the view height to set the x tick label offset, update label offset on resize.
p.interactionView.onResize_({ |v|
	var gridHeight = p.plots[0].plotBounds.height;
	p.setGridProperties(\x, \labelOffset, 8 @ (gridHeight.neg+10))
});
)

Settable now with, e.g., Size or Point.
add methods labelSize, labelAlign, labelAnchor
optional constraints on label extents
add labelAppendString property
adjust tick label size when string is appended to label
convert labelSize from inst var to method
fix variable inlining
refactor label space calc to its own method
Plotter:-drawLabels update position WRT the grid bounds
unify label padding between plotter and grid, simplify calc
rename labelX/Y -> axisLabelX/Y
enclose multi-conditional bool tests in function
add convenience methods for drawing grid bounding lines
add axis label font, check for gridOn vars before drawing bounding grid lines
axis labels aren't inherent in DrawGrid, so it's misleading to have them in the preview.
@mtmccrea mtmccrea force-pushed the topic/drawgrid-extend-ticklabels branch from f79a73f to 867b5f0 Compare January 4, 2023 21:01
@mtmccrea
Copy link
Member Author

mtmccrea commented Jan 4, 2023

I've cleaned up the commit history.

Copy link
Member

@telephon telephon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only found one typo.

All the rest is good, I think. You made a TODO-note in the code, it would be good to resolve further issues, but I think these are minor things. Thanks a lot!

font, fcolor);
Pen.pop;
};
this.draw; // draw the drid
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drid -> grid

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(you can leave out the comment, it is redundant)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this. Removed.

@mtmccrea mtmccrea force-pushed the topic/drawgrid-extend-ticklabels branch from a80865d to 0de631b Compare January 9, 2023 22:07
@mtmccrea
Copy link
Member Author

mtmccrea commented Jan 9, 2023

Thanks @telephon and @dyfer for your helpful reviews!

@dyfer
Copy link
Member

dyfer commented Jan 10, 2023

Thank you @mtmccrea for your work on this and @telephon for the review.
@sternsc could you confirm that the changes here fix the issues you've encountered?

@sternsc
Copy link

sternsc commented Jan 10, 2023 via email

@dyfer
Copy link
Member

dyfer commented Jan 10, 2023

Unfortunately I won’t have time soon to try the new code – I don’t have a build environment for all of SC set up and ready to go.

For macOS and Windows you can download the builds from GitHub actions (see "details" next to the CI checks, or the "Checks" tab on top, then click "Summary" and find artifacts on the bottom right, after scrolling down).

Would it work to get only the relevant .sc files (Plotter, GridLines etc) from the latest version, and replace the ones in 3.12.2, just to try? If so, which files exactly?

If might. I'd try all the .sc files changed in this PR (see "Files changed" on top) and additionally the ones which were changed in #5161 (but of course taken from the branch in this PR).

@telephon
Copy link
Member

the first thing you can try to just copy the whole class library over. If there weren't any changes to kernel classes and primitives, it might just work. If it doesn't, you could try copy the GUI classes.

@dyfer
Copy link
Member

dyfer commented Jan 11, 2023

the first thing you can try to just copy the whole class library over.

I didn't suggest this since AFAIR there were some changes to the interpreter and when I tried using class library from a recent develop on the SC 3.12 build it didn't work. But yes, this would typically be the first thing to try.

@sternsc
Copy link

sternsc commented Jan 12, 2023 via email

@mtmccrea
Copy link
Member Author

@sternsc here is code that reproduces the grids you showed in your previous post.

Example Code
```
( // Example 1
	var win = Window("DrawGrid test",
		Size(350, 300).asRect.center_(Window.screenBounds.center)
	).front;
	var uview = UserView(win, win.bounds.size.asRect);
	var xspec = [30, 95].asSpec;  // MIDI
	var yspec = [45, 120].asSpec; // dB
	var inset = 2; // border around the grid
	
	d = DrawGrid(uview.bounds.insetBy(inset),
		xspec.grid, yspec.grid
	);
	
	uview.drawFunc_({ |uv| d.draw; })
	.onResize_({ |uv|
		d.bounds = uv.bounds
		.insetBy(inset)
		.moveTo(inset, inset);
	})
	.resize_(5)
	.background_(Color.white)
	;
	
	d.x
	.labelAnchor_(\bottomLeft)
	.labelAlign_(\left)
	.labelOffset_(3 @ -3)
	.labelAppendString_(" MIDI")
	.gridColor_(Color.green)
	.fontColor_(Color.green)
	.font_(Font(Font.defaultSansFace, 11))
	;
	
	d.y
	.labelAnchor_(\topLeft)
	.labelAlign_(\left)
	.labelOffset_(3 @ 3)
	.labelAppendString_(" dB")
	.gridColor_(Color.green)
	.fontColor_(Color.green)
	.font_(Font(Font.defaultSansFace, 11))
	;
)

( // Example 2
	var win = Window("DrawGrid test",
		Size(350, 200).asRect.center_(Window.screenBounds.center)
	).front;
	var uview = UserView(win, win.bounds.size.asRect);
	var xspec = [-4.8, 0].asSpec; // s
	var yspec = [0, 28].asSpec;
	var inset = 2; // border aroudn the grid
	var xtickoffset = 10;
	d = DrawGrid(uview.bounds.insetBy(inset),
		xspec.grid, yspec.grid
	);
	
	uview.drawFunc_({ |uv| d.draw; })
	.onResize_({ |uv|
		d.bounds = uv.bounds
		.insetBy(inset)
		.moveTo(inset, inset);
		d.x.labelOffset_(0@d.bounds.height.neg + xtickoffset)
	})
	.resize_(5)
	.background_(Color.black)
	;
	
	d.x
	.labelAnchor_(\topLeft)
	.labelAlign_(\left)
	.labelOffset_(0@d.bounds.height.neg + xtickoffset)
	.labelAppendString_(" s")
	.gridColor_(Color.gray)
	.fontColor_(Color.gray)
	.font_(Font(Font.defaultSansFace, 11))
	;
	
	d.y
	.labelAnchor_(\topLeft)
	.labelAlign_(\left)
	.labelOffset_(3 @ 3)
	.gridColor_(Color.gray)
	.fontColor_(Color.gray)
	.constrainLabelExtents_(false)
	.font_(Font(Font.defaultSansFace, 11))
	.numTicks_(5)
	;
)
```

Which produces:
Screen Shot 2023-01-13 at 16 39 31

(Including behavior for update on resize).

So I think the functionality you've described is covered here.

@sternsc
Copy link

sternsc commented Jan 13, 2023

Thanks for your kind example @mtmccrea , it looks great! Looking forward to it!

@dyfer
Copy link
Member

dyfer commented Jan 13, 2023

Thanks so much @mtmccrea !
Sorry for looking into the details late in the conversation here.
Do I read correctly that in the process we lost automatic display of ControlSpec units? If so, I'd consider that as a regression from SC 3.12, where units were always displayed.
IMO they should still be displayed by default, but the question is whether that default should be next to the value, or along the axis.
I think it would be best to have a method to switch between these two options easily, e.g.;

DrawGridX/Y -unitDisplay(arg) where arg is \tick (appended to tick labels, 3.12 behavior), \axis (on axis label, "new" behavior), nil (not displayed). Either \tick or \axis` could be the default, depending what we all feel like.

What do you think?

Sorry for dragging this out!

@mtmccrea
Copy link
Member Author

mtmccrea commented Jan 14, 2023

Yes spec unit auto label functionality was removed (IIRC, in response to the last PR).

Some background:

`3.12.2` default behavior:

Just plotting a stereo buffer:
Screen Shot 2023-01-14 at 12 40 21

(
p = (4 ** (-5..0)).plot;
p.specs = \delay;
p.domainSpecs = [0, 10, \lin, 0, 0, " xxx"].asSpec; p.refresh;
)
Screen Shot 2023-01-14 at 12 21 48
`3.13-rc` default behavior: Screen Shot 2023-01-14 at 12 24 03 Screen Shot 2023-01-14 at 12 23 43
`3.13-rc` to achieve the old behavior (with new space padding):
// ... after plotting the buffer
p.axisLabelX = nil;
p.setGridProperties(\x, \labelAppendString, " " ++ p.domainSpecs.first.units)
Screen Shot 2023-01-14 at 12 28 27
(
p = (4 ** (-5..0)).plot;
p.specs = \delay;
p.domainSpecs = [0, 10, \lin, 0, 0, " xxx"].asSpec; p.refresh;

p.setGridProperties(\y, \labelAppendString, p.specs.first.units);
p.setGridProperties(\x, \labelAppendString, p.domainSpecs.first.units);
)
Screen Shot 2023-01-14 at 12 26 19

Notice Buffer:-plot still shows units by default, to align with previous behavior, but shown in the axis label.
Function:-plot does as well, because in both cases the units can be inferred confidently, unlike, e.g., Array:-plot.
I opted to put the units in the axis label because I thought having units on every tick label was redundant and crowded, and axis labels can replace that functionality. The extra vertical space taken is a consideration, so it will omit the unit label when the channel count is >= 4.

Moving forward:
So you can still achieve the same behavior in 3.13. Now the questions are

  • whether spec units should be shown by default (in all cases where a spec has units, rather than just Buffer and Function plots)
  • if so, whether the units should display with tick labels or as the axis label

If I'm not mistaken, @telephon authored the original approach, so may have thoughts on this.

@dyfer
Copy link
Member

dyfer commented Jan 14, 2023

Moving forward: So you can still achieve the same behavior in 3.13. Now the questions are

Yes, but it requires extra code.

  • whether spec units should be shown by default (in all cases where a spec has units, rather than just Buffer and Function plots)

I do think it should.

  • if so, whether the units should display with tick labels or as the axis label

With this one I could go either way. I like the visual aspect of the "new" way, but it does take a bit more space around the plot.

@telephon
Copy link
Member

I'm fine either way, there is much improvement.

@mtmccrea mtmccrea force-pushed the topic/drawgrid-extend-ticklabels branch from 13b6f87 to 10c5a51 Compare January 15, 2023 12:48
@mtmccrea mtmccrea force-pushed the topic/drawgrid-extend-ticklabels branch from 10c5a51 to 470f687 Compare January 15, 2023 19:16
@mtmccrea
Copy link
Member Author

OK thanks, I've made the units show by default (in the axis label—easy to change this default if we hear feedback from users in the RC).

I've also added these methods to the docs.

@telephon
Copy link
Member

good! let us know when it is ready for merge.

@mtmccrea
Copy link
Member Author

It's ready on my end :)

@telephon telephon merged commit 8033de0 into supercollider:3.13 Jan 16, 2023
@dyfer
Copy link
Member

dyfer commented Jan 16, 2023

Thank you @mtmccrea and @telephon !

@sternsc
Copy link

sternsc commented Feb 12, 2023

Super, thanks for 3.13.0-rc2. I've tested the new Grid-related stuff and found the following:

  1. in ExponentialGridLines.getParams there is a small bug (Grid.sc line 751 and following:
    ) { drawLabel = false // drop labels for tightly spaced upper area of the decade };
    But drawLabel must be made true again when increasing to the next decade:
    ) { drawLabel = false // drop labels for tightly spaced upper area of the decade } { drawLabel = true } ; // sternsc: bug fix: restore labels for the next decade
  2. The warp property of a ControlSpec is set using a symbol (\lin or \exp), but the getter function now returns instead an object instance of a subclass of AbstractGridLines. This seems asymmetric and makes it more awkward to inquire for the type of warp. I suggests a getter method called .warper that returns the object, and keeping .warp to return the symbol. Maybe.
  3. It would be great if .formatLabel could have a drawUnits argument in addition to the drawLabel argument. The reason is that it helps to plot the unit only on whole decades, as shown in this figure.

Untitled

I've been able to work my way around to this result by overriding .getParams and twiddling with calls to .appendLabel, as shown by this code excerpt from the end of ExponentialGridLines.getParams:
`

		// p['labels'] = lines.collect({ arg arr, inc;
		// 	var val, drawLabel, thisLabel;
		// 	#val, drawLabel = arr;
		// 	[val, this.formatLabel(val, nfrac ? nfracarr[inc] ? 1), nil, nil, drawLabel.not];
		// });

		//// sternsc's exponential version: draw the label units only at whole decades
		//// It could be neater if .formatLabel had also a drawUnits argument
		p['labels'] = lines.collect({ arg arr, inc;
			var val, drawLabel, thisLabel;
			var saveUnits, retVal;
			#val, drawLabel = arr;
			saveUnits = this.appendLabel;
			if (val.abs.log10.frac > 0.01, { this.appendLabel_(nil) });
			retVal = [val, this.formatLabel(val, nfrac ? nfracarr[inc] ? 1), nil, nil, drawLabel.not];
			this.appendLabel_(saveUnits);
			retVal
		});
	};
	^p

`
4. The usage of the numTicks argument with exponential axes needs to be clarified. So far as I can tell, it means approximately the number of ticks per decade: 1 or 3 or 10; where three gives 1,2,5 (fine!) and anything more than 4 gives up to 10. The default behavior is a bit clunky, so I found myself changing numTicks in the view's .onResize method. This probably can't be automated because it depends on font sizes and units strings as well.

All the linear stuff works fine and I have gotten the grids plotted as I like them. Thanks a lot for your work on this!

Hope this is of some help. And I can live with overriding - you can't cater to everyone's preferences...

@dyfer dyfer mentioned this pull request Feb 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp: class library SC class library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants