2

I am trying to plot some line charts using SwiftUI. In general, there is less data shown than available (in my example, I want to show values from 0…100, even though I am placing LineMarks for 0…200).

My code works; however, there is an overflow on the right side of the chart. How do I get rid of this?

import SwiftUI
import Charts

struct ContentView: View {
    var body: some View {
        GroupBox(label: Text("My Chart")) { 
            Chart {
                ForEach(Range(0...200), id: \.self) { x in
                    LineMark(
                        x: .value("X", x),
                        y: .value("Y", x)
                    )
                    .foregroundStyle(by: .value("Function", "x"))
                    LineMark(
                        x: .value("X", x),
                        y: .value("Y", Double(x) / 2)
                    )
                    .foregroundStyle(by: .value("Function", "x/2"))
                }
            }
            .chartXScale(domain: 0...100)
            .chartYScale(domain: 0...100)
        }
    }
}

The ultimate goal is to create a horizontally scrollable Chart. I left out that logic to simplify the question.

For this example, I could simply reduce the range from 0…200 to 0…100. However, in general, this might not be an appropriate solution as we cannot know the next (hidden) value and the line should still go into the right direction (cut off though).

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Philipp
  • 23
  • 4

1 Answers1

2

Use .mask { } modifier with a RectangleMark() struct (inside a closure) that specifies Chart content that represents data using rectangles.

import SwiftUI
import Charts

struct ContentView: View {
    var body: some View {
        GroupBox(label: Text("My Chart")) {
            Chart {
                ForEach(Range(0...200), id: \.self) { x in
                    LineMark(
                        x: .value("X", x),
                        y: .value("Y", x)
                    )
                    .foregroundStyle(by: .value("Function", "x"))
                    .mask { RectangleMark() }
                    
                    LineMark(
                        x: .value("X", x),
                        y: .value("Y", Double(x) / 2)
                    )
                    .foregroundStyle(by: .value("Function", "x/2"))
                    .mask { RectangleMark() }
                }
            }
            .chartXScale(domain: 0...100)
            .chartYScale(domain: 0...100)
        }
    }
}

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • 1
    Awesome, thanks for the straight forward answer! Btw, if you want to for example extend the mask a bit to show the chart symbols, you can add some offset like this `RectangleMark().offset(yStart: -10, yEnd: 10)` – alexkaessner Aug 30 '23 at 22:47