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

IChartDataSet valueFormatter is now of NSFormatter type #742

Closed
wants to merge 2 commits into from
Closed

IChartDataSet valueFormatter is now of NSFormatter type #742

wants to merge 2 commits into from

Conversation

tedkaminski
Copy link

Using NSFormatter instead of the more concrete NSNumberFormatter allows for greater customization of the way values are displayed.

@liuxuan30
Copy link
Member

Seems every formatter should override stringForObjectValue because the default implementation will raise exception by the doc.
If we are going to write our own formatters, why NSNumberFormatter's sub class is not enough? It's about data/value. Naturally the NSNumberFormatter is the base class I think.

@tedkaminski
Copy link
Author

Sure, I could do that. But lets say that I want to prepend and append some text around the value. Or maybe I don't want to show a number value at all. I can use NSNumberFormatter as the base class, but it's starting to feel a bit forced and makes for a nastier and less flexible library.

@tedkaminski tedkaminski closed this Feb 8, 2016
@danielgindi
Copy link
Collaborator

You are incorrect.
NSNumberFormatter is about formatting numbers into anything that you want to represent that number. For all ObjC cares, you could have an NSNumberFormatter return "Twenty three" when passing [... stringFromNumber:12]
It actually has utilities out of the box for prefixing and suffixing with arbitrary text in a number of different situations.

@dxclancy
Copy link

I think the base class for the formatter should be NSFormatter, and initialized by default to a NSNumberFormater (or checked for nil, not sure how the code is now). This, for instance, allows use of NSDateFormatter, or any other standard or custom NSFormatter override, instead of having to hack a custom subclass of NSNumberFormatter.

Although potentially too heavyweight and definitely a bigger change, Ideally (?) there might be an interface that would allow you to pass the values as a protocol that has a non-optional "getValue" on to get the double value. This protocol could them be called with a format request. This would give you the flexibility to do anything you want, as well as give you more context about your data so you can make richer formatting decisions.

@danielgindi
Copy link
Collaborator

@dxclancy it makes absolutely no sense. The input value is always a number. So it is a number formatter.

Anyway -the interfaces will change in the future to something like the one in MPAndroidChart api, to allow customizing the value based on other positional factors.

@dxclancy
Copy link

To me, it is not a number, it is textual data I want to display to my users, and may only be inspired by the value. For instance, Apple provides an NSByteCountFormatter but it derives from NSFormatter. I can see instances where I'd want a bar chart representing the space different kinds of files take up, and I would want to present the users with the sizes. The number could be a date in the format of a time interval, but I wouldn't be able to use NSDateFormatter without deriving from NSNumberFormatter and forwarding to NSDateFormatter. It could be a chart of weight and want to use NSMassFormatter.

It seems weird that these do not derive from NSNumberFormatter, but I suppose NSNumberFormatter is not actually a number formatter , but an NSNumberFormatter. From the docs: "Instances of NSNumberFormatter format the textual representation of cells that contain NSNumber objects". So I suppose the intention is not to format any data that can represented by a number, but data that can be represented by an NSNumber. "NSFormatter is an abstract class that declares an interface for objects that create, interpret, and validate the textual representation of values. " So I suppose, we can think of NSFormatter as an NSValueFormatter, and what we're formatting are values, not NSNumbers.

It’s fine if these types of usages are considered too complex or nuanced for the API, if we need to draw a line on customization,or even if you just don’t want to do it that way, but I do think they make sense. And, honestly, I'm not sure there is any downside to the formatter being an NSFormatter?

In my particular case, I want something strange. I want to display to the user values that are generally in the hundred thousands as "k". 300,000 = 300k. So I derived from NSNumberFormatter. Fine. But I actually want to exaggerate the value of one of my three stacked bars visually because it is so small it does not show up. So I've multiplied it by 10. But then, I'd like to draw the actual number for the text, not the exaggerated number. In my case, a NSNumberFormatter or even NSFormatter is not ideal. I've actually done a dirty hack where i add a small decimal to the 10x number, and then in my derived formatter, detect that small decimal amount and derive the original value again. Frankly, I'd rather get the index of the value I'm formatting, or called back through an object i passed for that value, or perhaps a block or delegate with the index and value, so that I can reconstruct the context of the value. But that all complicates the interface.

@danielgindi
Copy link
Collaborator

It really does not matter what it is "to you". These values are numeric values. You can read the code if you like. Each y value is a Double (that can represent anything). That's what we are formatting.

@dxclancy
Copy link

Every other example in my post is also a numeric value. And we can't format them because we can't pass any other value formatter. I've read and modified the code. I will chalk this up to "even if you just don’t think we should do it that way". :)

If this should ever be revisited, or if someone else finds they want something similar, I just found a similar pattern in the interface for the Axis:
ChartXAxisValueFormatter.

Perhaps something like this can be done, in BarChartRenderer.
Replace:

    var valueFormatter: NSNumberFormatter? { get set }

with a modified version of ChartXAxisValueFormatter, perhaps something like

var valueFormatter: ChartValueFormatter? { get set }
@objc
public protocol ChartValueFormatter
{
    /// For performance reasons, avoid excessive calculations and memory allocations inside this method.
    ///
    /// - returns: the customized label that is drawn for the value.
    /// - parameter index:             the index of dataSet being drawn
    /// - parameter dataSetIndex:the index of the value currently being drawn
    /// - parameter value:             the original value to be drawn
    ///
    func stringForXValue(dataSetIndex: Int, index: Int, original: double) -> String

}    

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants