-1

I understood that I have to use the following line but I don't know how to use it in SwiftUI : chart.xAxis.forceLabelsEnabled = true

Here is my charts :

var sampleData: [Int] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Chart {
                    ForEach(sampleData.indices, id: \.self) { index in
                        BarMark(x: .value("x", String(Calendar.current.monthSymbols[index].prefix(3))),
                                y: .value("y", index))
                    }
                }
                .chartYAxis(.hidden)
                .frame(height: 180)

With the result : FirstChart

In french, June = Juin and July = Juillet.

As the first 3 letters of JUIN and JUILLET are the same then the fusion values. One of the solutions is to put .prefix(4) but that's not what I want

Result in French : Second Chart

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
KaayZenn
  • 103
  • 7
  • 2
    Please add some more context to your question, it’s hard to understand what you’re asking. And do you mean the built in Charts library or the 3rd party framework (I think you mean the former but you have tagged the question with the latter)? – Joakim Danielson Jul 14 '23 at 20:04
  • @JoakimDanielson I updated the question for you to understand better. I use Apple's Framework Charts – KaayZenn Jul 15 '23 at 06:23

2 Answers2

0

To make this work you need, as noted, to keep the x values unique and therefore we need to build the label for the x axis separately using .chartXAxis

First change the BarMark to use the index as the x value

BarMark(x: .value("x", "\(index)"),
        y: .value("y", index))

We need to make it a string to match the type we will be using below as the label data.

Then add a new modifier to Chart

.chartXAxis() {
    AxisMarks { value in
        let month = Calendar.current.monthSymbols[value.index]
        AxisValueLabel { Text(String(month.prefix(3))) }
    }
}
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
0

You should not give your data duplicate X values in the first place. Since your data is date-based, actually create some Dates. For example:

ForEach(sampleData.indices, id: \.self) { index in
    // in reality your data source should this information from your data,
    // instead creating Dates ad hoc like this
    BarMark(x: .value("x", Calendar.current.date(from: .init(month: index + 1))!),
            y: .value("y", index))
}

Then, if you want to format some of them to the same strings, that is totally possible:

.chartXAxis {
    AxisMarks(preset: .aligned, values: .stride(by: .month)) { value in
        AxisValueLabel(monthNames[value.index])
    }
}

where monthNames is an array, e.g.

let monthNames = {
    var calendar = Calendar.current
    // My locale isn't French, so I hardcoded the locale in
    calendar.locale = Locale(identifier: "fr")
    return calendar.monthSymbols.map { String($0.prefix(3)) }
}()

That said, I would recommend using the built-in date formats:

.chartXAxis {
    let format = Date.FormatStyle(locale: .init(identifier: "fr")).month(.abbreviated)
    AxisMarks(format: format, preset: .aligned, values: AxisMarkValues.stride(by: .month))
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313