0

I am trying to design an ios app to display json data in a line chart.

First of all, this is my json data.

{
TH_5min: [
{
Data: "2019-02-23T00:00:00",
Time: "11:00:00",
XTP_A: 10.5, //temperature 1
XHP_A: 11.5, //humidity 1
XTP_B: 33.5,
XHP_B: 44.6,
XTP_C: 88.9,
XHP_C: 66.6,
XTP_D: 77.9,
XHP_D: 99.6,
XTP_E: 87.87,
XHP_E: 66.66
},
{
Data: "2019-02-23T00:00:00",
Time: "11:05:00",
XTP_A: 55.2,  //temperature 1
XHP_A: 44.3,  //humidity 1
XTP_B: 66.6,
XHP_B: 77.87,
XTP_C: 87.77,
XHP_C: 87.87,
XTP_D: 8.87,
XHP_D: 78.78,
XTP_E: 87.78,
XHP_E: 87.87
}
]
}

This is my implementation of the swift code showing json data.

override func viewDidLoad() {
        super.viewDidLoad()
      apiip = APIip
        getlatestTh_5min()
    @objc func getlatestTh_5min(){
        guard let th_5minUrl = URL(string: "http://" + apiip + "/api/Th_5min") else{
            return
        }
        let request = URLRequest(url: th_5minUrl)
        let task = URLSession.shared.dataTask(with: request, completionHandler: {(data,response,error) -> Void in
            if let error = error {
                print(error)
                return
            }
            if let data = data {
                self.th_5mins = self.pardrJsonData(data: data)
                self.getchat()
            }
        })
        task.resume()
        //getchat()
    }
    func pardrJsonData(data: Data) -> [Th_5min]{
        var th_5mins = [Th_5min]()
        do {
            let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
            let jsonTh_5mins = jsonResult?["TH_5min"] as! [AnyObject]
            print(jsonTh_5mins)
            print(th_5mins.count)
            for jsonTh_5min in jsonTh_5mins{
                var th_5min = Th_5min()
                th_5min.Data = jsonTh_5min["Data"] as! String
                th_5min.Time = jsonTh_5min["Time"] as! String
                th_5min.XTP_A = jsonTh_5min["XTP_A"] as! Double
                th_5min.XHP_A = jsonTh_5min["XHP_A"] as! Double
                print(th_5min)
                th_5mins.append(th_5min)
                //getchat()
            }        }catch{
                print(error)
        }
        //getchat()
        return th_5mins

    }

This is how I draw the line chart, using swift code.

@objc func getchat(){

        chartView = LineChartView()  
        chartView.frame = CGRect(x: 20, y: 80, width: self.view.bounds.width-20,height: self.view.bounds.height-100)
        self.view.addSubview(chartView)
        var dataEntries1 = [ChartDataEntry]()
        for i in 0..<th_5mins.count {
            chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: [th_5mins[i].Time])
            let y = th_5mins[i].XTP_A
            let entry = ChartDataEntry.init(x: Double(i), y: Double(y))
            dataEntries1.append(entry)
        }
        let chartDataSet1 = LineChartDataSet(entries: dataEntries1, label: "temperature")

        chartDataSet1.colors = [NSUIColor.red]

        var dataEntries2 = [ChartDataEntry]()
        for i in 0..<th_5mins.count {
            chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: [th_5mins[i].Time])
            let y = th_5mins[i].XHP_A
            let entry = ChartDataEntry.init(x: Double(i), y: Double(y))
            dataEntries2.append(entry)

        }
        let chartDataSet2 = LineChartDataSet(entries: dataEntries2, label: "humidity")
        chartDataSet2.colors = [NSUIColor.black]

        let chartData = LineChartData(dataSets: [chartDataSet1, chartDataSet2])

        chartView.data = chartData
    }
}

This is the result of my work.

enter image description here

Although the json data is successfully displayed, I don't know why it is loading for a long time, and I hope that the "time" in my json data can be displayed on the X axis above, marked with my temperature and humidity, and cannot be successful. I also hope that my line chart view can be implemented as a layout.

sinnnnenene
  • 71
  • 1
  • 11

1 Answers1

0
  1. "I don't know why it is loading for a long time". Do you mean that the graph does not load immediately upon opening the view? This is because the data is loading asynchronously from a remote source (correctly now, well done). It may well take a few seconds for your JSON to download over the web. That is ok. You can test the endpoint in a browser and see how long the response takes.

  2. "I hope that the 'time' in my json data can be displayed on the X axis above". Yes. You can take the assignation of IndexAxisValueFormatter outside of the loop and you should pass all labels as values into the constructor. Try this code, replacing the equivalent loop:-

    var labels: [String] = []
    for i in 0..<th_5mins.count {
        let y = th_5mins[i].XTP_A
        let entry = ChartDataEntry.init(x: Double(i), y: Double(y))
        dataEntries1.append(entry)
        labels.append(th_5mins[i].Time)
    }
    chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: labels)
    

Note that the method you use for plotting against dates will result in an evenly spread graph, irrespective of your time gaps (e.g. if readings are 5 mins apart between the first two, but 5 years apart for the next two, they will still appear with even gaps between them.

Chris Shaw
  • 1,610
  • 2
  • 10
  • 14
  • Thank you for your patience and explanation, but I still don't understand how to adjust my swift code, how do I use this new class? – sinnnnenene Apr 02 '19 at 04:46
  • Where have you defined IndexAxisValueFormatter? You are using it in your code already. Replace it with mine. – Chris Shaw Apr 02 '19 at 04:48
  • for i in 0.. String { let i = round(Double) return th_5mins[i].Time } } //chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: [th_5mins[i].Time]) let y = th_5mins[i].XTP_A let entry = ChartDataEntry.init(x: Double(i), y: Double(y)) dataEntries1.append(entry) } . I – sinnnnenene Apr 02 '19 at 04:51
  • I just replace chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: [th_5mins[i].Time]) to class IndexAxisValueFormatter: NSObject, IndexAxisValueFormatter { func stringforvalue(value: Double , axis: AxisBase?) -> String { let i = round(Double) return th_5mins[i].Time } } – sinnnnenene Apr 02 '19 at 04:52
  • No. Revert to your code as above. Hold Command and click on IndexAxisValueFormatter. Go to definition. You must have defined it somewhere. Replace its definition - not its usage - with mine. If not, put the definition I gave outside of your `getchat` function. Change the `chartView.xAxis.valueFormatter =` line exactly as I've shown you in the answer. – Chris Shaw Apr 02 '19 at 04:59
  • understood! I went to the definition of IndexAxisValueFormatter. There was a lot of code in it. I replaced it with your method, but it shows such an error. 1.Consecutive statements on a line must be separated by ';' 2.Method 'stringForValue(_:axis:)' must be declared public because it matches a requirement in public protocol 'IAxisValueFormatter'Mark the instance method as 'public' to satisfy the requirement 3.Use of unresolved identifier 'th_5mins' – sinnnnenene Apr 02 '19 at 05:33
  • If i add new class outside of my getchat getchat still have some error.1.Instance member 'th_5mins' of type 'linechartViewController' cannot be used on instance of nested type 'linechartViewController.IndexAxisValueFormatter' 2.Consecutive statements on a line must be separated by ';' – sinnnnenene Apr 02 '19 at 05:46
  • You're right - ok, then put my code just above the `getchat` function. Rename it so as not to cause a name clash (DateAxisValueFormatter) and then use `chartView.xAxis.valueFormatter = DateAxisValueFormatter(th_5mins)`. It needs to use the `th_5mins` array. Accept the array in the constructor. Alternatively, make your view controller conform to IAxisValueFormatter and make the `stringForValue` a member function. – Chris Shaw Apr 02 '19 at 05:46
  • 1. put class DataAxisValueFormatter: NSObject, IAxisValueFormatter { func stringForValue(_ value: Double, axis: AxisBase?) -> String { let i = round(value); return th_5mins[i].Time } } outside of my getchat() 2. replace chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values:[th_5mins[i].Time]) to chartView.xAxis.valueFormatter = DataAxisValueFormatter() when i done those step still show Instance member 'th_5mins' of type 'linechartViewController' cannot be used on instance of nested type 'linechartViewController.DataAxisValueFormatter' in my new class – sinnnnenene Apr 02 '19 at 05:55
  • I am very sorry, I have not studied swift, thank you for your patience. – sinnnnenene Apr 02 '19 at 05:56
  • If you can, can you teach me the steps of fixing from start?plesae. – sinnnnenene Apr 02 '19 at 06:13
  • Accept the array in the constructor. Alternatively, make your view controller conform to IAxisValueFormatter and make the stringForValue a member function. I don't understand what this means.What should I do in my swift code? – sinnnnenene Apr 02 '19 at 10:29
  • Ok. Reworked the answer. Ignore the previous work about rewriting IndexAxisValueFormatter. Return to the original code and follow the new answer. – Chris Shaw Apr 02 '19 at 11:19
  • Thank you very much for your patient explanation, I solved my problem! But I still don't understand how code is used. If you can, can you tell me how you know how to use these codes? – sinnnnenene Apr 02 '19 at 11:56
  • Years of experience, reading the docs, following StackOverflow, studying tutorials.... Find a good tutorial site and do lots of work. Ray Wenderlich is good IMO. That's all I can do to help. But read a lot more about swift and coding before asking questions on here. – Chris Shaw Apr 02 '19 at 22:01
  • I have a question. You said that json data will not be displayed immediately, but I open the view and the loading time is about 8~15 seconds. Is this normal? My other pages are also displayed in the view cell using json. The response time is less than one second. Is there a problem with the code I am drawing line chart? – sinnnnenene Apr 03 '19 at 05:53
  • Is not beyond the realms of possibility. Open a web browser on the API page (`"http://" + apiip + "/api/Th_5min"`) and see how long the page takes to load. It will be a few seconds probably. Your app will experience this delay too. – Chris Shaw Apr 03 '19 at 06:01
  • Ok! Thank you so much! Thank you again for your help. – sinnnnenene Apr 03 '19 at 06:04