Получение значения Y в серии диаграмм .NET из значения X

используя C # с диаграммой .NET.

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

|      at xValue 12    |                                     |
|      _ = 3           |                                     |
|      * = 2           |                                * *  |
|              ________|______________________________*_____ |
|             /        |                             *       |
| __________*/*********|*****************************        |
|        *             |                                     |
|       *              |                                     |
|______________________|_____________________________________|

Вроде как эта диаграмма выше. Ниже представлена ​​версия моего кода:

void chart1_MouseMove(object sender, MouseEventArgs e)
        {
            var pos = e.Location;
            _point.X = e.Location.X;
            _point.Y = e.Location.Y;

            try
            {
                if ((chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X) >= 0) && (chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X) <= max))
                {
                    //Crossair
                    chart1.ChartAreas[0].CursorX.SetCursorPixelPosition(_point, true);

                    //Tooltips
                    double xValue = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X);
                    double yValue = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Y);
                    string all_Data_Values = "";

                    foreach (var series in chart1.Series)
                    {
                        all_Data_Values = all_Data_Values + Environment.NewLine + series.Name + ": " + yValue;
                    }

                    tooltip.Show("At " + Math.Truncate(xValue * 1000) / 1000 + all_Data_Values, this.chart1, pos.X - 40, pos.Y - 20);
                }
            }
            catch (Exception exception)
            {
               //
            }
        }

Это то, что у меня есть, и сейчас он отображает только значение Y для местоположения моего курсора мыши. Я пробовал другие коды, пытаясь каким-то образом отобразить значения x в chart1.Series [], но это тоже не сработало.


person hansioux    schedule 22.03.2013    source источник
comment
Подумайте об использовании ZedGraph, это неплохо.   -  person David    schedule 22.03.2013
comment
Вы пробовали пройтись по коду с помощью отладчика, чтобы увидеть, что не так?   -  person Pieter Geerkens    schedule 22.03.2013
comment
На мой взгляд, похоже - у меня похожий код (за исключением того, что я получил значение X, я ищу его в серии, чтобы получить ближайшее фактическое значение). Есть ли у вас исключения? Что такое max?   -  person Matthew Watson    schedule 22.03.2013
comment
Я думаю, что это скорее тот случай, когда я не знаю, какая часть структуры диаграммы может предоставить мне возможность поиска Yvalue. Единственная ошибка в том, что я не знаю, чем заменить chart1.ChartAreas [0] .AxisY.PixelPositionToValue (e.Y); с участием. Я видел что-то вроде foreach (var series в chart1.Series) {all_Data_Values ​​= all_Data_Values ​​+ Environment.NewLine + series.Name +: + series.Points [somepoint] .YValues ​​[0]; } Но у меня тоже не получилось заставить его работать, я не знаю, что используется для индексации очков.   -  person hansioux    schedule 22.03.2013
comment
@MatthewWatson привет, как вы нашли ближайшее фактическое значение, я думаю, это то, что я хочу спросить.   -  person hansioux    schedule 22.03.2013


Ответы (1)


(Это ответ на запрос кода для поиска ближайшего значения с учетом координаты пикселя.)

Я делаю это немного иначе, чем вы, потому что на самом деле я устанавливаю "курсор" диаграммы, когда пользователь перемещает мышь, но, надеюсь, это даст вам достаточно информации, чтобы вы могли адаптировать ее к своим потребностям ...

Вот как я рассчитываю координату оси X для координаты X клиента:

private double calcCursorGraphX(int clientX)
{
    var xAxis = _chart.ChartAreas[CHART_INDEX].AxisX;
    int xRight = (int) xAxis.ValueToPixelPosition(xAxis.Maximum) - 1;
    int xLeft = (int) xAxis.ValueToPixelPosition(xAxis.Minimum);

    if (clientX > xRight)
    {
        return xAxis.Maximum;
    }
    else if (clientX < xLeft)
    {
        return xAxis.Minimum;
    }
    else
    {
        return xAxis.PixelPositionToValue(clientX);
    }
}

Учитывая значение X, возвращаемое вышеуказанным методом, мы можем найти ближайшее предыдущее значение:

private int nearestPreceedingValue(double x)
{
    var bpData  = _chart.Series[SERIES_INDEX].Points;
    int bpIndex = bpData.BinarySearch(x, (xVal, point) => Math.Sign(x - point.XValue));

    if (bpIndex < 0)
    {
        bpIndex = ~bpIndex;                // BinarySearch() returns the index of the next element LARGER than the target.
        bpIndex = Math.Max(0, bpIndex-1);  // We want the value of the previous element, so we must decrement the returned index.
    }                                      // If this is before the start of the graph, use the first valid data point.

    return bpIndex;
}

Тогда у вас есть индекс, который вы можете использовать для поиска значения из _chart.Series[SERIES_INDEX].Points

Я не уверен, согласуется ли это с тем, как ваши данные хранятся в диаграммах, но я это делаю именно так.

[EDIT] Вот отсутствующий метод расширения BinarySearch. Добавьте его в какой-нибудь доступный статический класс. Замените «Контракты» своей собственной обработкой ошибок, если вы не используете кодовые контракты.

/// <summary>
/// Searches the entire sorted IList{T} for an element using the specified comparer 
/// and returns the zero-based index of the element.
/// </summary>
/// <typeparam name="TItem">The type of the item.</typeparam>
/// <typeparam name="TSearch">The type of the searched item.</typeparam>
/// <param name="list">The list to be searched.</param>
/// <param name="value">The value to search for.</param>
/// <param name="comparer">The comparer that is used to compare the value with the list items.</param>
/// <returns>
/// The zero-based index of item in the sorted IList{T}, if item is found; 
/// otherwise, a negative number that is the bitwise complement of the index of the next element that is larger than item,
/// or - if there is no larger element - the bitwise complement of Count.
/// </returns>

public static int BinarySearch<TItem, TSearch>(this IList<TItem> list, TSearch value, Func<TSearch, TItem, int> comparer)
{
    Contract.Requires(list != null);
    Contract.Requires(comparer != null);

    int lower = 0;
    int upper = list.Count - 1;

    while (lower <= upper)
    {
        int middle = lower + (upper - lower) / 2;
        int comparisonResult = comparer(value, list[middle]);

        if (comparisonResult < 0)
        {
            upper = middle - 1;
        }
        else if (comparisonResult > 0)
        {
            lower = middle + 1;
        }
        else
        {
            return middle;
        }
    }

    return ~lower;
}
person Matthew Watson    schedule 22.03.2013
comment
Вастон Спасибо за быстрый ответ. Я пытаюсь реализовать ваш метод, но не могу использовать BinarySearch на своем графике chart.Series [ex] .Point. Он говорит мне, что BinarySearch не определен в System.Windows.Forms.DataVisualization.Charting.DataPointCollection. Не уверен, что я упускаю использование или что-то в этом роде. Я могу использовать BinarySearch для своих списков. - person hansioux; 22.03.2013
comment
Ой, извините, я забыл, что у меня есть метод расширения для двоичного поиска IList. Секундочку, добавлю. - person Matthew Watson; 22.03.2013