Add custom label formatter support for crosshair#1173
Add custom label formatter support for crosshair#1173swharden merged 6 commits intoScottPlot:masterfrom
Conversation
bclehmann
left a comment
There was a problem hiding this comment.
Looks good, just a few minor things. They're not about your code so much as maintaining a consistent API, as anyone who uses this feature probably is also using the custom formatter on the axis as well. So those features should probably expose a similar API.
Maybe even the crosshair label formatter should use the axis formatter? I don't know how easy that would be though, especially now that we have support for multiple axes. It would also introduce a lot of coupling.
src/ScottPlot/Plottable/Crosshair.cs
Outdated
| /// <summary> | ||
| /// If defined, this function will be used to generate labels from X position, value of StringFormatX and IsDateTimeX will be ignored | ||
| /// </summary> | ||
| public Func<double, string> ManualStringFormatterX = null; |
There was a problem hiding this comment.
I think TickLabelFormat is ignored if it's a datetime axis, so this introduces an inconsistency.
I think it's probably better that it isn't ignored for datetime axes, but that change would mean changing the axis code as well.
There was a problem hiding this comment.
I think
TickLabelFormatis ignored if it's a datetime axis
Maybe there should be a NumericFormatter and DateTimeFormatter?
There was a problem hiding this comment.
I think it's fine for the user to figure that out themselves, as they should know whether or not it's a DateTime axis.
Although I suppose we could make it easier for them by having DateTimeFormatter take in a DateTime instead of a double.
src/ScottPlot/Plottable/Crosshair.cs
Outdated
| gfx.DrawLine(pen, dims.DataOffsetX, yPixel, dims.DataOffsetX + dims.DataWidth, yPixel); | ||
|
|
||
| string yLabel = IsDateTimeY ? DateTime.FromOADate(Y).ToString(StringFormatY) : Y.ToString(StringFormatY); | ||
| string yLabel = ManualStringFormatterY != null ? ManualStringFormatterY(Y) : IsDateTimeY ? DateTime.FromOADate(Y).ToString(StringFormatY) : Y.ToString(StringFormatY); |
There was a problem hiding this comment.
This ternary within a ternary is pretty unwieldly.
There was a problem hiding this comment.
Thanks. I'll avoid using it in future.
src/ScottPlot/ScottPlot.csproj
Outdated
| <Version>4.1.16</Version> | ||
| <AssemblyVersion>4.1.16.0</AssemblyVersion> | ||
| <FileVersion>4.1.16.0</FileVersion> | ||
| <Version>4.1.17</Version> |
There was a problem hiding this comment.
I think Scott will bump the version himself once this is merged and any other PRs have been merged in.
There was a problem hiding this comment.
Indeed! This can be left as 4.1.16 for now 👍
There was a problem hiding this comment.
I didn't intentionally change the version number, probably because I'm not familiar with ScottPlot's automated build system. I also think this small change should not change the version number.
|
|
||
| // use the custom formatter for crosshair labels | ||
| ch.ManualStringFormatterX = customTickFormatter; | ||
| ch.ManualStringFormatterY = customTickFormatter; |
There was a problem hiding this comment.
Again on the consistency argument, it's a little weird that for one of them you pass in a formatter delegate to a function and for the other you set a property.
I think that setting a property is probably the better API, but if we want consistency that would mean changing the axis code.
There was a problem hiding this comment.
The consistency argument is also present in the original API. I think changing the axis code is a good way.
|
Also, it looks like you made this PR from your master branch, instead of a new branch. That's not a problem for us but it could make it more difficult for you to fetch new commits that get merged in. |
|
Hi @Maoyao233, thank you for this PR! I really like the idea of exposing custom formatters in more places throughout ScottPlot, and this is a great improvement. Thinking out loud, an alternative to allowing formatters to be I think separate functions would be helpful, but I recognize this is super verbose:
Maybe this is an indication this class should be refactored as two smaller objects (because this isn't the only duplication of X and Y properties). Alternatively I wonder if these advanced label features should be added to |
One could allow the user to pass in one function (or class) which would override one or several of these? It could be done with the decorator pattern. There is a way to do this where they pass in a function, where they're passed an object, and setting fields of that object sets the formatter. The formatter should probably be allowed to be null just so it's easy for them to reset it. Both of these are departures from the rest of the ScottPlot API however. |
|
@Maoyao233 thanks again for this PR and your feedback! When you're done making changes to this PR let me know and I'll make a few small changes of my own then merge this in 👍
@bclehmann this is a good observation! This trend could be taken to its logical conclusion by having a fully-abstracted "configuration object" or "styling object" that could be instantiated and modified by the user and passed into plots or plottables. This would help separate code for configuration, styling, and rendering. If ScottPlot were a private library that only I used, I would prefer this. Since it's a public library and I strive to make it quick and easy to learn for new users, I find myself preferring the simplicity of having users assign public fields. |
|
@swharden I have finished my work on this PR.
I ended up using different formatter for numeric and datetime to avoid the first problem, and I think changing the axis code to keep consistency is valuable. Thanks again to @swharden and @bclehmann. I've learnt a lot. |
|
I wonder if we should have a demo as well, for the datetime axes? Perhaps that should wait for when axes get custom datetime formatters. |
|
Thanks @Maoyao233 this looks fantastic! I also appreciate your input along the way @bclehmann I'll be refactoring the Crosshair module shortly. I intend to add support for position labels to axis lines, and when I do that I'll be sure to support this type of custom formatter support as well. I suspect the |
New Contributors:
please review CONTRIBUTING.md
Purpose:
#1172
New Functionality: