How to draw 2 LineCharts with xAxis with Strings - ios

I am new in programming and swift and I am trying to make a chart with 2 lines. And on top of the chart to enumerate the Array of Strings that I have (DD-MM in my case). I managed to draw just one line like so:
let testArrayTemp = [22.43, 14.86,20.63, 17.08,23.68,14.12,11.09,13.89, 15.0, 9.86, 7.71,10.0,11.94, 8.68, 8.91,6.81, 9.03,8.89, 9.7, 9.26, 9.43,10.22, 9.04,8.04, 7.56,10.44, 7.22, 13.67,9.44, 7.67, 5.99]
let testArrayFeel = [20.43, 13.86,10.63, 15.08,22.68,11.12,10.09,15.89, 13.0, 6.86, 5.71,11.0,10.94, 7.68, 6.91,5.81, 3.03,5.89, 7.7, 8.26, 8.43, 11.22, 6.04,7.04, 6.56,11.44, 6.22, 12.67,10.44, 5.67, 4.99]
let testDayArray = ["Oct 2, 2016", "Oct 3, 2016", "Oct 4, 2016", "Oct 5, 2016", "Oct 6, 2016", "Oct 7, 2016", "Oct 8, 2016", "Oct 9, 2016", "Oct 10, 2016", "Oct 11, 2016", "Oct 12, 2016", "Oct 13, 2016", "Oct 14, 2016", "Oct 15, 2016", "Oct 16, 2016", "Oct 17, 2016", "Oct 18, 2016", "Oct 19, 2016", "Oct 20, 2016", "Oct 21, 2016", "Oct 22, 2016", "Oct 23, 2016", "Oct 24, 2016", "Oct 25, 2016", "Oct 26, 2016", "Oct 27, 2016", "Oct 28, 2016", "Oct 29, 2016", "Oct 30, 2016", "Oct 31, 2016", "Nov 1, 2016"]
setChart(dataPoints: testDayArray, valuesTempChart: testArrayTemp, valuesFeelChart: testArrayFeel)
}
//MARK:- Set Chart
func setChart(dataPoints: [String], valuesTempChart: [Double], valuesFeelChart: [Double])
{
var tempEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count
{
let dataEntry = ChartDataEntry(x: Double(i), y: valuesTempChart[i])
tempEntries.append(dataEntry)
}
let lineChartDataSetTemp = LineChartDataSet(values: tempEntries, label: "Temperature")
lineChartDataSetTemp.setColor(UIColor.red)
// lineChartDataSetTemp.mode = .cubicBezier
lineChartDataSetTemp.drawCirclesEnabled = true
lineChartDataSetTemp.lineWidth = 2.0
lineChartDataSetTemp.circleRadius = 5.0
lineChartDataSetTemp.highlightColor = UIColor.green
lineChartDataSetTemp.drawHorizontalHighlightIndicatorEnabled = true
var dataSets = [IChartDataSet]()
dataSets.append(lineChartDataSetTemp)
let lineChartDataTemp = LineChartData(dataSets: dataSets)
lineChart.data = lineChartDataTemp
lineChart.animate(xAxisDuration: 2.0, yAxisDuration: 2.0)
lineChart.noDataText = "There is no provided data from the server. Please check out later!"
}
but it looks like so:
what I need to do to show the String array on top (with the days) and to add one more line. please any idea, or maybe a link to a tutorial in SWIFT 3 not other version, cause they made a lot of changes, and nothing from swift 2 tutorials works as it should, but the autocorrection does even worse.
I would like it to look something like this: (but with 2 lines and days in stead of months)
Thank you for any suggestions

What you need to do is repeat the process for the feels data. Reference the code below.
func setChart(dataPoints: [String], valuesTempChart: [Double],valuesFeelChart: [Double])
{
var tempEntries: [ChartDataEntry] = []
var feelEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count
{
let dataEntryOne = ChartDataEntry(x: Double(i), y: valuesTempChart[i])
let dataEntryTwo = ChartDataEntry(x: Double(i), y: valuesFeelChart[i])
tempEntries.append(dataEntryOne)
feelEntries.append(dataEntryTwo)
}
let lineChartDataSetTemp = LineChartDataSet(values: tempEntries, label: "Temperature")
let lineChartDataSetFeels = LineChartDataSet(values: feelEntries, label: "Feels")
var dataSets = [IChartDataSet]()
dataSets.append(lineChartDataSetTemp)
dataSets.append(lineChartDataSetFeels)
let lineChartD = LineChartData(dataSets: dataSets)
lineChart.data = lineChartD
lineChart.animate(xAxisDuration: 2.0, yAxisDuration: 2.0)
lineChart.noDataText = "There is no provided data from the server. Please check out later!"
}
Hope this helps!

Related

Ruby: How to sum values of multiple JSON objects into one object?

I have two JSON objects like this:
object1 = {
"Oct 2019": 100,
"Nov 2019": 100,
"Dec 2019": 100,
"Jan 2020": 100,
"Feb 2020": 100,
"Mar 2020": 100,
"Apr 2020": 100,
"May 2020": 100,
"Jun 2020": 100,
"Jul 2020": 100,
"Aug 2020": 100,
"Sep 2020": 100
}
object2 = {
"Oct 2019": 50,
"Nov 2019": 50,
"Dec 2019": 50,
"Jan 2020": 50,
"Feb 2020": 50,
"Mar 2020": 50,
"Apr 2020": 50,
"May 2020": 50,
"Jun 2020": 50,
"Jul 2020": 50,
"Aug 2020": 50,
"Sep 2020": 50
}
How can I sum the values of object1 and object2 so the resulting json object looks like the following?:
result = {
"Oct 2019": 150,
"Nov 2019": 150,
"Dec 2019": 150,
"Jan 2020": 150,
"Feb 2020": 150,
"Mar 2020": 150,
"Apr 2020": 150,
"May 2020": 150,
"Jun 2020": 150,
"Jul 2020": 150,
"Aug 2020": 150,
"Sep 2020": 150
}
(The values in this example are the same for every month, but in my application they are all different values.)
There are many ways to do that, but I find the easiest is to use the form of Hash#merge that employs a block to compute the values of keys that appear in both hashes being merged.
object1.merge(object2) { |_k,v1,v2| v1+v2 }
# = {:"Oct 2019"=>150, :"Nov 2019"=>150, :"Dec 2019"=>150,
# :"Jan 2020"=>150, :"Feb 2020"=>150, :"Mar 2020"=>150,
# :"Apr 2020"=>150, :"May 2020"=>150, :"Jun 2020"=>150,
# :"Jul 2020"=>150, :"Aug 2020"=>150, :"Sep 2020"=>150}
The three block variables, _k, v1 and v2, are defined in the doc. As is common practice, I've begun the name of the common key (_k) with an underscore to signal to the reader that it is not used in the block calculation.
If there were three or more such hashes to combine, write:
object1.merge(object2, object3, ...) { |_k,v1,v2| v1+v2 }
Another way of doing this is quite simple:
keys = (object1.keys + object2.keys).uniq
#=> [:"Oct 2019", :"Nov 2019",..., :"Sep 2020"]
keys.each_with_object({}) do |k,h|
h[k] = object1.fetch(k,0) + object2.fetch(k,0)
end
#=> {:"Oct 2019"=>150, :"Nov 2019"=>150,..., :"Sep 2020"=>150}
See Hash#fetch.
One could replace objectx.fetch(k,0) with objectx[k].to_i, as nil.to_i #=> 0, but I don't think that reads as well.
This could be extended to summing over three or more hashes in the obvious way.

How to filter array of timestamp in order to keep specific hours?

Imagine this array of timestamps [Double] :
hourlyTimes": [1551344400, 1551348000, 1551351600, 1551355200, 1551358800, 1551362400, 1551366000, 1551369600, 1551373200 ... ]
It corresponds to the hours for which I have data to display.
To keep it simple, here is the full array when I display only the hours (UTC) :
Hours = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, 3, 6, 9, 12, 15, 18, 21, 0, 3, 6, 9, 12, 15, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0]
Now here is what I want to achieve, I need to filter this array of timestamp, in order to only keep these specific hours on any day (three-hourly).
[0, 3, 6, 9, 12, 15, 18, 21]
Ok, now let's have a look at the code :
let arrayOfTimestamp = time.hourlyTimes
let arrayOfHours = arrayOfTimestamp.map({ Date.init(timeIntervalSince1970: $0).hoursUTC})
let hoursToKeep = [0, 3, 6, 9, 12, 15, 18, 21]
let filtered = arrayOfHours.intersection(with: hoursToKeep)
Some explanations here:
time in the first line is the response from the backend, returning me all the available timestamps.
struct MultiForecastTimeModel: Codable {
let hourlyTimes: [Double]
let dailyTimes: [Double]
}
.hoursUTC is just a Date extension, in order to retrieve the hour component of the Date object.
var hoursUTC: Int {
var calendar = Calendar.current
let timezone = TimeZone(abbreviation: "UTC")!
calendar.timeZone = timezone
return calendar.component(.hour, from: self)
}
And finally, .intersection is an extension too, in order to do the same as a classic intersection, but also keeping the index and the occurrences.
extension Collection where Element: Equatable {
func intersection(with filter: [Element]) -> [Element] {
return self.filter { element in filter.contains(element) }
}
}
Everything is working fine, my only issue is that I now have to associate all these values as an Array of tuples.
Like this :
let tuples = Array(zip(filtered, filtered.dropFirst()))
But with an actual timestamp (corresponding to real date), not just an array of Int (hour component).
Because in the end, here what I have to do :
self.hourlyMapDataSource.data.value = tuples
and my datasource is expecting a tuple of timestamp (Double, Double)
class HourlyMapDataSource : GenericDataSource<(Double, Double)>, UICollectionViewDataSource { }
Do you have any pieces of advice on how should I improve my code and/or my logic?
Thank you in advance.
EDIT: My tuple array should only contain timestamps whose time has been "validated" through the hoursToKeep array so that it has 3 hours difference between hours.
I will show you with the hours to keep it simple, but it's an actual corresponding timestamp that I want :
[(9, 12), (12, 15), (15, 18) ...]
var tupleArray = hourlyTimes.map { (time: $0, hour: Date.init(timeIntervalSince1970: $0).hoursUTC)}
Now you can run the reduce function on this
var selectedHours = tupleArray.filter { return hoursToKeep.contains($0.hour) }
This will give you an array of tuples which have the validated hours,
[(1551344400, 9), (1551348000, 12)]

What does the Quarter Component in Calender.Component do? (Swift)

I am trying to use yearly quarters in my iOS application but have found that the .quarter component does nothing. There is also no documentation I could find on it.
Calling print(Calendar.current.date(byAdding: .quarter, value: 1, to: Date())) just prints the current date. I would have expected it to add 3 months on to it?
You'd think that wouldn't you — but no, it appears something is broken.
A quick test in a Playground shows it all works until you use a .quarter:
//: Playground - noun: a place where people can play
import UIKit
let result = Calendar.current.date(byAdding: .quarter, value: 1, to: Date())
print (result)
let calendar1 = Calendar.current
let now1 = Date()
let newDate1 = calendar1.date(byAdding: .minute, value: 1, to: now1)
let newDate2 = calendar1.date(byAdding: .hour, value: 1, to: now1)
let newDate3 = calendar1.date(byAdding: .day, value: 1, to: now1)
let newDate4 = calendar1.date(byAdding: .month, value: 1, to: now1)
let newDate5 = calendar1.date(byAdding: .month, value: 3, to: now1)
let newDate6 = calendar1.date(byAdding: .quarter, value: 1, to: now1)
Results in:
"Sep 27, 2016, 3:30 PM"
"Optional(2016-09-27 05:30:03 +0000)\n"
gregorian (current)
"Sep 27, 2016, 3:30 PM"
"Sep 27, 2016, 3:31 PM"
"Sep 27, 2016, 4:30 PM"
"Sep 28, 2016, 3:30 PM"
"Oct 27, 2016, 3:30 PM"
"Dec 27, 2016, 3:30 PM"
"Sep 27, 2016, 3:30 PM"
It looks like as it stands in Xcode 8.0 (8A218a) you will have use months and a value of 3 as shown in the newDate5 line above.

Cut elements of array in Swift 2

I have array of elements (it's a basic array). Type of array is String
basicArray = [1710, 1725, 1740, 1755, 1810, 1825, 1840, 1855, 1925, 1955, 2020, 2050, 2120, 2150, 2220, 2250, 2320, 2350, 2430]
I need to create two new arrays where each element of basicArray must be cut into two parts, for example:
array1 = [17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 20, 20....]
array2 = [10, 25, 40, 55, 10, 25, 40, 55, 25,55, 20, 50...]
How better to do it? Thank you for your advice!
let basic = ["1710", "1725", "1740", "1755", "1810", "1825", "1840", "1855", "1925", "1955", "2020", "2050", "2120", "2150", "2220", "2250", "2320", "2350", "2430"]
let array1 = basic.map { String($0.characters.prefix(2)) }
let array2 = basic.map { String($0.characters.suffix(2)) }
print(array1)
print(array2)
Output:
["17", "17", "17", "17", "18", "18", "18", "18", "19", "19", "20", "20", "21", "21", "22", "22", "23", "23", "24"]
["10", "25", "40", "55", "10", "25", "40", "55", "25", "55", "20", "50", "20", "50", "20", "50", "20", "50", "30"]
Something like this?
Try this (Hints are in the code comments):
var basicArray = [1710, 1725, 1740, 1755, 1810, 1825, 1840, 1855, 1925, 1955, 2020, 2050, 2120, 2150, 2220, 2250, 2320, 2350, 2430]
var firstTwoDigitsArray = [Int]()
var lastTwoDigitsArray = [Int]()
for element in basicArray {
// dividing by 100 shifts the numbers down by the first two digits
firstTwoDigitsArray.append(element/100)
// modulo 100 gets the last two digits
lastTwoDigitsArray.append(element%100)
}
print(firstTwoDigitsArray) // [17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24]
print(lastTwoDigitsArray) // [10, 25, 40, 55, 10, 25, 40, 55, 25, 55, 20, 50, 20, 50, 20, 50, 20, 50, 30]
Swift has a built in method called filter which basically is a closure that iterates over all elements and lets you -- as the name suggests -- filter the elements based on a predicate:
let array = [1,2,3,4,5,6]
let array1 = array.filter { $0 % 2 == 0 }
print(array1) // [2, 4, 6]
let array2 = array.filter { $0 % 2 == 1 }
print(array2) // [1,3,5]
You haven't made clear how you want those arrays to be filtered, so it's hard to explicitly give the answer that you might be looking for...

Make NSDictionary Monthwise from DateArray

I have an array of DateString , in which I have values of date,month and year .
Now I have sorted it in ascending order . Now I have to put it in to dictionary with this key-value pair :-
Key- "January" (Month Name) and Value:- array of dates in that month
can anyone suggest me how to do this ?
You write code, as everyone would do.
You need a dictionary that maps (year, month) to (array).
You start with an empty mutable dictionary. Then you loop through your items. For each item, get the year and month (I assume you don't want Januarys of different years together). Look up the year / month in the dictionary, getting the mutable array value. If it isn't there, add the (year, month) key with a new mutable array as the value. So now you have an array for the (year, month), and add the item to that array.
If your data is fixed at that point, you can iterate through the dictionary and replace all the mutable arrays with immutable arrays (just use copy). And instead of sorting all the items first, just sort the keys of the dictionary, so you are now sorted by month and year, then sort the arrays when you need them sorted. For example in a tableview, you only need those arrays sorted that are actually being displayed.
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
// Set your year and month here
[components setYear:2016];
NSMutableDictionary *dayAndMonthWiseList = [[NSMutableDictionary alloc] init];
for (int i=1; i<=12; i++)
{
[components setMonth:i];
NSDate *date = [calendar dateFromComponents:components];
NSRange range = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date];
NSMutableArray *dayList = [[[NSMutableArray alloc] init] mutableCopy];
for (int j=1; j<=range.length; j++)
{
[dayList addObject:[NSString stringWithFormat:#"%d",j]];
}
[dayAndMonthWiseList setObject:dayList forKey:[NSString stringWithFormat:#"%d",i]];
}
NSLog(#"Dic. :%#",dayAndMonthWiseList);
Result is :
Dic. :{
1 = (
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,
26,
27,
28,
29,
30,
31
);
10 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31
);
11 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30
);
12 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31
);
2 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29
);
3 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31
);
4 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30
);
5 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31
);
6 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30
);
7 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31
);
8 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31
);
9 = (
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30
);
}

Resources