Как пропустить нулевые значения при построении диаграммы SwiftUI

Я рисую диаграмму SwiftUI из структуры, которая выглядит следующим образом:

struct BestWeights: Identifiable
{
    let id = UUID()
    let date: String
    let maxWeight: Int
}

Затем я создаю массив этой структуры, который буду использовать для построения диаграммы:

 private var bestWeights: [BestWeights] {           
     let unformattedMonth = DateFormatter().monthSymbols[month - 1]
     let formattedMonth =  String(unformattedMonth.prefix(3))
     bestWeights.append(BestWeights(date: formattedMonth, maxWeight: bestWeightOfPeriod))
    
     //decrementing down one month
     selectedDate = Calendar.current.date(byAdding: .month, value: -1, to: selectedDate) ?? selectedDate
}

Затем я перебираю bestWeights и строю их график:

Chart {
    ForEach(bestWeights) { bestWeight in
                        
        LineMark(x: .value("Date",bestWeight.date), y: .value("MaxWeight", bestWeight.maxWeight))
            .symbol {
                Circle()
                    .fill(.blue)
                    .frame(width: 7, height: 7)
            }                        
    }
}

Результат:

Это не то, чего я хочу. Я не хочу, чтобы 0 отображались на оси Y. Поэтому я добавил проверку, чтобы не добавлять bestWeight, если вес равен 0:

if (bestWeightOfPeriod != 0) {
    bestWeights.append(BestWeights(date: formattedMonth, maxWeight: bestWeightOfPeriod))
}

Это именно то, чего я хочу, но это создает еще одну проблему на моей оси X, где пропускаются месяцы. Это идет с февраля прямо по июнь. Я все еще хочу отметить все месяцы. Поскольку дата хранится в моей структуре и пропускает месяцы, имеющие вес 0, диаграмма помечается неправильно.

Как я могу обозначить эти недостающие месяцы?

Мне нужна ось Y второго изображения, но ось X первого изображения.

Это одна и та же ось Y на обоих изображениях, не так ли? Я думаю, вам нужны значения (точки) второго изображения.

Joakim Danielson 01.08.2024 19:17

нет, второй не включает в себя никаких записей с весом 0, поэтому его ось x неправильная, как на первом изображении, да, без этих точек, удаляющих нижнюю часть графика, это то, что я ищу

john smith 01.08.2024 19:44

Итак, вы хотите, чтобы февраль был всего лишь одной точкой, а линия начиналась с июня?

Sweeper 02.08.2024 04:02

нет, я хочу, чтобы февраль соединился с июнем. Моя единственная проблема со вторым изображением заключается в том, что на оси X в качестве метки отсутствует март, апрель, май.

john smith 02.08.2024 16:01
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
4
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Фильтрация maxWeight == 0 точек данных идет в правильном направлении. Тебе следует продолжать это делать.

Проблема в том, что вы используете строки для обозначения месяцев. Поскольку вы рисуете строки, диаграмма считает, что это категориальные данные, а не временной ряд.

Сначала замените BestWeights на Date:

struct BestWeights: Identifiable
{
    let id = UUID()
    let date: Date // keep this a Date!
    let maxWeight: Int
}

Вот пример набора данных:

func weightsData() -> [BestWeights] {
    let calendar = Calendar.current
    var weights = [BestWeights]()
    for (month, weight) in zip(2...8, [90, 0, 0, 0, 100, 180, 100]) {
        let dateComponents = DateComponents(year: 2023, month: month, day: 1)
        let date = calendar.date(from: dateComponents)!
        weights.append(
            BestWeights(date: date, maxWeight: weight)
        )
    }
    return weights
}

и вот график:

struct ContentView: View {
    @State var weights = weightsData().filter { $0.maxWeight > 0 }
    
    var body: some View {
        Chart(weights) { weight in
            LineMark(
                x: .value("Month", weight.date, unit: .month), // note the ".month" argument here!
                y: .value("Max Weights", weight.maxWeight)
            )
            .symbol {
                // Also consider using a PointMark here
                Circle()
                    .fill(.blue)
                    .frame(width: 7, height: 7)
            }
        }
        .chartXAxis {
            // here we add one axis mark per month
            AxisMarks(values: .stride(by: .month)) {
                // and here we format the date into an abbreviated month format
                AxisValueLabel(format: .dateTime.month(.abbreviated), centered: true)
            }
        }
        .padding()
    }
}

Обратите внимание: я никогда явно не превращал Date в String. Я только что передал стиль формата AxisValueLabel, и он позаботился о форматировании.

Выход:

Сейчас он работает лучше, но сейчас на втором изображении он работает в феврале, апреле, июне. Марта, мая и июля все еще нет.

john smith 05.08.2024 12:21

Я отредактировал ответ, включив в него ваш код

john smith 05.08.2024 12:46

@johnsmith Вам следует удалить первый модификатор chartXAxis, куда вы добавили AxisMarks(stroke: StrokeStyle(lineWidth: 0)). Вам это не нужно — линий сетки нет, потому что я не поставил AxisGridLine в закрытие конструктора AxisMarks, где я поставил AxisValueLabel.

Sweeper 05.08.2024 12:53

@johnsmith Если вам нужны линии сетки, вы можете добавить AxisGridLine(stroke: StrokeStyle(lineWidth: 1)) после AxisValueLabel.

Sweeper 05.08.2024 12:54

Спасибо за отличный ответ. Я уверен, что это поможет многим людям, ресурсы на диаграммах весьма ограничены.

john smith 05.08.2024 13:02

Только один последний вопрос, если кто-то захочет вместо увеличения по месяцам увеличивать по неделям, например, 10/7, 17/7, 24/7 и т. д. Как бы они это сделали, используя ваш ответ? Я не могу найти, как двигаться по неделям?

john smith 05.08.2024 13:08

@johnsmith Ты можешь .stride(by: .day, count: 7). Не забудьте также изменить параметр unit: в x: .value("Month", weight.date, unit: .day).

Sweeper 05.08.2024 13:14

А что бы вы сделали с AxisValueLabel, чтобы он отображал дд/мм по оси X так же, как месяцы?

john smith 05.08.2024 14:46

@johnsmith .dateTime.month(.twoDigits).day() Пожалуйста, прочитайте документацию.

Sweeper 05.08.2024 14:50

Другие вопросы по теме