I wanted to ask some chart styling and data questions. My chart currently looks like this:
I would like to add a border around the chart with rounded edges, I have tried using the following code to no avail:
_chart.layer.cornerRadius = 10.0;
_chart.layer.borderWidth = 0.7;
_chart.layer.borderColor = [UIColorwhiteColor].CGColor;
I would also like to add labels to the bars to indicate their values, but have no idea how to do so.
My final question is regarding the data in the chart. Despite having a data structure in the correct order, the data appears scrambled in terms of order (it should read M T W TH F S SU). My data structure is:
_sales[0] = #{#"M" : #1.6, #"T" : #5.6, #"W" : #10.6, #"TH" : #12.6, #"F" : #15.6, #"S" : #3.6, #"Su" : #4.6};
and is used in the following way:
- (id<SChartData>)sChart:(ShinobiChart *)chart dataPointAtIndex:(NSInteger)dataIndex forSeriesAtIndex:(NSInteger)seriesIndex {
SChartDataPoint *datapoint = [[SChartDataPointalloc] init];
NSString* key = _sales[seriesIndex].allKeys[dataIndex];
datapoint.xValue = key;
datapoint.yValue = _sales[seriesIndex][key];
return datapoint;
}
Any advice or input would be appreciate, thanks in advance!
Disclaimer: I work for ShinobiControls
Chart Border
Instead of using layer.borderWidth you can use borderThickness and instead of using layer.borderColor you can use borderColor.
The following worked for me when I tested it:
_chart.borderColor = [UIColor redColor];
_chart.borderThickness = #(5);
_chart.layer.cornerRadius = 10.0;
Data Point Labels
You can turn data point labels on and control their style via the series you are returning from your data source:
series.style.dataPointLabelStyle.showLabels = YES;
Data Order
You mention that your data structure is "in the correct order", but unfortunately that isn't quite true. You are using an NSDictionary which does not guarantee order. When you call allKeys on your NSDictionary the array that is returned is not necessarily in order. As per the NSDictionary API documentation for allKeys:
The order of the elements in the array is not defined.
In order to fix this you'll need to switch to a data structure that does guarantee order.
I hope all that info is useful!
Note: There are a number of different questions in the original post, so this response contains several answers. I'm not really sure what the etiquette is for editing/splitting questions on SO is, so I've left it alone. If anyone comes across this question and has suggestions along those lines then feel free to make edits or add comments etc.
Related
I read many posts similar to my questions but for some reasons they still don't work.
I'm working on the well known plotly database 'tips'. I want to show 2 subplots by 'sex' and then edit both subplots' titles. I start from this code:
df=px.data.tips()
names={'Femmine':'Plot1','Maschi':'Plot2'}
fig=px.box(df,x='day',y='tip',facet_col='sex')
Now I'd like to edit the default subtitles outcome('sex=Female', 'sex=Male') and replace them with
two names i stored in the dictioanry names. I tried this:
fig.for_each_annotation(lambda a: a.update(text=str(names.keys())))
fig
But the output gives me this:
Really, i know the solution is there but ...I simply can't find it. Any help?
Thanks
Based on the answer here: How to change titles (facet_col )in imshow (plotly)
df=px.data.tips()
names={'Femmine':'Plot1','Maschi':'Plot2'}
fig=px.box(df,x='day',y='tip',facet_col='sex')
for i, label in enumerate(names):
fig.layout.annotations[i]['text'] = label
fig.show()
Note that this works because your dictionary keys are the title you wish to update.
Otherwise, if you wanted the value instead (Plot1, Plot2), you should instead use:
for i, (key, value) in enumerate(names.items()):
fig.layout.annotations[i]['text'] = value
I've been making a game with the LOVE2D game engine, and I've stumbled across an issue. I want to access a variable inside a nested table, but I don't know how.
Here's my code right now:
local roomNum = 1
local rooms = { r1 = { complete = false, name = "Room 1" }
if rooms[roomNum].complete == true then --problematic line
--do stuff
end
If I replace rooms[roomNum].complete with rooms.r1.complete then it works.
Any help would be appreciated!
'http://lua-users.org/wiki/TablesTutorial'
The provided link gives easy to understand examples on tables in Lua, so it may prove a useful resource in the future.
As for the why the replacement code worked, a dictionary is just sets of key/value pairs (kvp) . In examples from other languages, these pairs are normally shown as something like KeyValuePair.
In your case, you are using a variation on how dictionaries are used. As you have seen, you can use numbered indexes like room[1], or you can use a string like room["kitchen"]. It gets interesting when you provide a set of data to initialize the dictionary.
Building off of the provided data, you have the following:
local rooms = { r1 = { complete = false, name = "Room 1" }
r1 is equivalent to using rooms["r1"] without the dataset. In providing the dataset, any "named" Key can be referenced like it is a property of the dictionary (think of classes with public getter/setter). For the named keys of a dataset, you can provide a key as numbers as well.
local rooms = { [1] = { complete = false, name = "Room 1" }
This indexing fits the direction you were headed on providing a room index. So, you could either swap the dataset to use integers instead of r1, r2 and so on, or you could concatenate r and the index numbering. That is pretty much up to you. Keep in mind as you go further down nesting the same rules apply. So, complete could look like rooms[1].complete, rooms["r1" ].complete, or rooms.r1.complete.
I have an array of core data objects called samples, each sample has a depthFrom and depthToo. I load each sample into a tableView to show the depthFrom and Too. I need to check for gaps between the values and if there is, insert a new sample.
The samples in the table could look like below with depthFrom and depthToo,
The issue is since there is a gap between the numbers from 100 to 210 new samples should be added to the table. using a gap of 50 as much as possible so it would look like this with the auto generated samples.
What im unsure of is how to compare the values, i would rather do it as the view loads before cellForRowAtIndexPath is called so i would not need to reload the table again. I was thinking of looping through each value and comparing them but there all in the same array so im not sure how i would do this. I have all the data displaying correctly in my app its just the gaps i need to account for and if im able to find a way to compare the values in the array then i can manage adding in the new objects i just need pointing in the right direction as this is new to me.
If theres anything about my question that is confusing then just add a comment and i will update it accordingly, thanks for any help.
To fix the gaps, you must keep track of the last depthTo and check if there's a gap between it and the current sample. If there is, insert samples with a spacing of 50*, until we reach our current sample.
Here's a pseudocode solution:
samples = NSMutableArray
int lastDepthTo = 0;
for (i = 0; i < [samples count]; i++) {
s = samples[i]
// add missing samples (upto current s.depthFrom)
while (s.depthFrom > lastDepthTo) {
genDepthTo = MIN(d.depthFrom, lastDepthTo+50)
generated = new sample(depthFrom: lastDepthTo, depthTo: genDepthTo)
[samples insert:generated atIndex:i]
i++ // increment i to skip inserted sample
lastDepthTo = genDepthTo
}
lastDepthTo = s.depthTo
}
Note: this is untested, maybe off by 1 for the indexing of i.
Working on a grails application, wherein I am using dc-crossfilter to plot 5 bar graphs which are interconnected to each other.
Now, I want to do a simple thing here : In my first bar graph, there are 14 bars ( x number of departments and 1 "All" graph)
So the problem here is that the presence of "All" in the graph really messes up every other department's number as they are way too low (All is summation of all x number of departments) So each department number is so low that it's not even visible clearly.
But, it is very important to load the data for "All", as all the remaining 4 bar charts are filtered for "All" only.
So, is there any way how I can hide "All" in my first bar graph even though data is loaded? Is this even feasible?
There has to be some simple workaround to do this.
All approaches/suggestions are most welcome.
UPDATE :
Code:
This is the part where I define the groups and dimensions
var devValue = facts.dimension(function (d) {return d.c;});
var devValueGroupSum = devValue.group().reduceSum(function(d) { return +d.g;});
var mvValue = facts.dimension(function(d,i) {return d.b;});
var mvValueGroupSum = mvValue.group().reduceSum(function(d) {return +d.g;});
Now, where and how exactly do I define a fake group and prefilter the data. But will "ALL" be included in the actual dataset ( and not visualization part) even after prefiltering the data.
Code for fake group as in documentation :
var group = {
all:function () {
var cumulate = 0;
var g = [];
_group.all().forEach(function(d,i) {
cumulate += d.value;
g.push({key:d.key,value:cumulate})
});
return g;
}
};
I am really not able to understand the documentation as in how to implement this, can you help me in implementing this?
You can use a "fake group" to prefilter the data. Whenever the chart fetches the data it will go through your fake group, which then fetches the data from the real group and changes it.
The technique is described in the FAQ.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Solution:
I have marked #BlackRider's answer as correct as it is the most versatile especially for complex comparisons however there are other very good answers and comments. I would encourage anyone with the same or similar question to review them and evaluate the best course of action for your specific situation.
In my situation, I am actually not using BlackRider's solution in my implementation. I have elected to use my own solution (see Edit #2 below) with help from #JoshCaswell's comments as well as #voromax's suggestion of indexesOfObjectsWithOptions:passingTest: due to the fact that my comparisons are very simple in this situation.
Thanks to everyone who answered and provided insight.
I am looking for an efficient way to retrieve an object from an NSArray based on a property of that object (a unique identifier, in this case). In C#.NET using Linq I would do something like
MyObject obj = myList.Single(o => o.uuid == myUUID);
I am also wondering if there is an efficient way to get an array of objects matching a non-unique property. Again, with Linq it would look like
List<MyObject> objs = myList.Where(o => o.flag == true).ToList();
Of course I can write loops to do this but they would not be reusable and I'm suspicious of their performance.
Finding an object with a unique ID:
-(MyObject*)findObjectWithUUID:(NSString*)searchUUID{
for (MyObject* obj in _myArray){
if([obj.uuid isEqualToString: searchUUID])
return obj;
}
}
Finding an array of objects:
-(NSArray*)findObjectsWithFlag:(BOOL)f{
NSMutableArray* arr = [NSMutableArray array];
for (MyObject* obj in _myArray){
if(obj.flag == f)
[arr addObject:obj];
}
return arr;
}
-- EDIT --
Luckily in the first situation the object I am looking for has a unique identifier and I know there will only be one. I came up with a solution to implement isEqual on my object which will be invoked by indexOfObject:
- (BOOL)isEqual:(id)object{
return [self.uuid isEqualToString: ((MyObject*)object).uuid];
}
And then create a "fake" lookup object and use that to find the real one
MyObject *lookupObject = [[MyObject alloc] init];
lookupObject.uuid = searchUUID;
MyObject *actualObject =
[_myArray objectAtIndex:[_myArray indexOfObject:lookupObject]];
This is essentially the same as the for-in loop I posted above, but might be more readable & be more reusable. Of course, this only works for finding one unique object and does not address the second half of my question.
-- EDIT 2 --
Checking Class and implementing hash as recommended in comments.
- (BOOL)isEqual:(id)object{
return [object isKindOfClass:[MyObject class]] &&
[self.uuid isEqualToString: ((MyObject*)object).uuid];
}
- (NSUInteger)hash{
return [self.uuid hash];
}
You can use [NSPredicate], which gives you a query-like syntax for search. Check out this page for the predicate syntax description. Here's a simple example:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"propertyName == %#", #"value"];
NSArray *filteredArray = [myArray filteredArrayUsingPredicate:predicate];
As to performance, I think your solution is OK since any search in an array needs to iterate through all the elements anyway, and then, for each object, compare the value of a field against the value you search for. You can optimize repeat searches within the same data, e.g. by creating and populating a dictionary that maps values of some field to the matching objects (or collections of objects, if the mapping is one to many).
You may also look at modern block syntax: indexOfObjectWithOptions:passingTest: or indexesOfObjectsWithOptions:passingTest: which support concurrency and search order.
I was intrigued by rmaddys comment so I've checked the difference between looping and predicate.
Let's assume a simple object with NSString property. I've inserted it into array 10 000 times , every time with different property value.
In the worst case scenario when desired object was on the last position of the array, loop approach was 3.5x faster than NSPredicate (0.39s vs 0.11s, arraySize = 10000, 10 iterations, iPad Mini)
Code I used for reference: pastebin
I know its related with NSArray but if we do it using Swift and using the swift Array which is a struct, then that will be lot easier.
Swift 2.2 / Swift 3.0 / Swift 4.x Working fine on all versions
Lets assume we have a custom model class
class User {
var userId = 0
var userName = ""
}
And lets assume we have an array named as usersArray which has custom objects of User class.
And we want to fetch an object from this array with userId = 100 for example:-
let filteredArray = usersArray.filter({$0.userId == 100})
This filtered array will contain all the custom objects which have userId as 100
print(filteredArray[0].userName) //will print the name of the user with userId = 100
just for those who are interested, I've found the fastest way to search through NSArray is by using a for loop on a background thread. using the [self performSelectorInBackground...] method.
In an NSArray of 10000 custom objects I searched through the whole thing thoroughly in around 1 second. On the main thread it took around 10 seconds or more.