Wykres w WinApi - ilość danych != szerokość okna

0

cześć,
Uczę się WinApi a przy okazji chcę stworzyć pewną aplikację, której zadaniem będzie m.in. narysowanie wykresu w polu roboczym okna.
Mam jednak następujący problem:
powiedzmy, że mam pole robocze do namalowania wykresu o wymiarach: wysokość 300 i szerokość 500 pikseli. Chciałbym w tym polu narysować wykres z pobranych danych, które trzymam w tablicy double* variables;.
Danych może być więcej niż 500 jak również może być ich mniej. Jeśli jest więcej to należy je "jakoś" przetworzyć tak, by było ich max 500 - bo tyle jest w okienku pikseli i więcej być nie może.
Pytanie: jak tego dokonać? Jeśli danych będzie 1000 to zadanie jest łatwe - wystarczy obliczyć średnią z 1000/500 sąsiadujących zmiennych i zapisać je do 2 razy mniejszej tablicy. A co jeśli będzie 553 dane? Jak je jakoś sensownie wyskalować? Jak z 553 danych zrobić 500 lub np. 250? Jak je wyskalować?

Podobny problem dotyczy, gdy danych będzie mniej, np. 320. Jeśli policzę 500/320to wyjdzie mi, że powinienem wstawiać daną co 1,56 piksela - a przecież to niemożliwe -.-. Jeśli wstawię jedynie 320 danych to będę miał prawie 2/5 niewykorzystanego wykresu, co będzie się niezbyt ładnie komponować. Pytanie więc jak mniejszą ilość danych wyskalować - tak, by ich łączna liczba była podzielna przez szerokość okna - np. 500, 250, 100 itp.

Z góry dziękuję za naprowadzenie mnie na rozwiązanie tego problemu.

0

Widzę, że moim tematem niewiele osób się zainteresowało, ale może chociaż jakaś podpowiedź ;-)
Ogólnie to mam jakąś wstępną koncepcję ze wspólnym mianownikiem, ale wydaje mi się, że da się to jakoś zrobić liniowo - operując na macierzach... Jednak nie wiem jeszcze jak :(

0

Najprostsze rozwiązanie. Danych jest n, okno ma 500 pikseli. Dla każdego 0 <= i < n, współrzędna x-owa w pikselach to 500*i/n. Współrzędna y-wa jest oczywista. Rysujesz odcinki od punktu i do punktu i+1 (i < n-1). Jeśli n jest większe niż 500, to niektóre odcinki będą pionowe - to nie przeszkadza.

0
bogdans napisał(a):

Najprostsze rozwiązanie. Danych jest n, okno ma 500 pikseli. Dla każdego 0 <= i < n, współrzędna x-owa w pikselach to 500*i/n. Współrzędna y-wa jest oczywista. Rysujesz odcinki od punktu i do punktu i+1 (i < n-1). Jeśli n jest większe niż 500, to niektóre odcinki będą pionowe - to nie przeszkadza.

Dzięki, ale powiem szczerze, że nie za bardzo rozumiem Twoją koncepcję.
500*i/n da mi w przybliżeniu wynik {1,2,3,...,500} - więc jest to raczej zbędne działanie.
Natomiast odnośnie tego ostatniego zdania to również nie za bardzo rozumiem - a co jeśli będę miał 100 000 danych? Nie mogę 500 wyświetlić a 99 500 opuścić...

0

500*i/n da mi w przybliżeniu wynik {1,2,3,...,500}
trochę inaczej, da Ci liczby 0,...,499 i takie ma dać. Dla każdego punktu z wykresu jego współrzędna x-owa ma wartość z przedziału [0,499].
W tym sposobie niczego nie odrzucasz, wszystko uwzględniasz. Inna sprawa, że rysunek będzie mało czytelny gdy danych jest 100 000, na zmianę liczby 0.0 i 1.0.

0

a co jeśli będę miał 100 000 danych? Nie mogę 500 wyświetlić a 99 500 opuścić...
Oczywiście że możesz.

Możesz wyświetlić 500 równo rozłożonych (wyświetlać co dwusetną daną, 500*200 = 100 000),
możesz wyświetlać średnią z 200 sąsiadujących,
możesz wyświetlić 500 a reszta po przewinięciu paska...

są różne możliwości, zależnie od potrzeb i charakteru danych.

Przecież nie wyświetlisz wszystkich stu tysięcy mając tylko 500 pikseli.

0

Dzięki @Azarien, ale czy nie ma jakiegoś algorytmu, który by zredukował mi ilość występujących w tablicy danych do zadanej liczby, tak by nowy wektor wyglądem był najbliższy temu oryginalnemu? Coś, co da się optymalizować... Nie chodzi mi o wyświetlenie wszystkich danych na 500 pikselach, bo to jest niemożliwe, ale o takie ich uśrednienie, by nowy wektor, który będzie wyświetlany wyglądem był najbliższy temu oryginałowi.

Z wyżej wymienionych przez Ciebie na pewno odpada przewijanie - bo danych może być zarówno bardzo mało jak również bardzo dużo, więc taki przewijany wykres dla dużej liczby zmiennych byłby nieczytelny.

Na chwilę obecną najbardziej pasuje mi średnia, ale w głowie coś mi świta możliwość wykorzystania macierzy... Niestety pewności co do tego nie mam ;-(.
Natomiast chodzi też o problem typu: szerokość okna ma 500 a danych jest 600 - i jak je uśrednić?... Dla dużej liczby danych wydaje się to mniej znaczące ale danych może być niedużo...

Myślałem o wykorzystaniu jakiegoś algorytmu do redukcji zmiennych w danych (np. PCA, sieć kohonena, k-means etc.), jednak problem jest taki, że te algorytmy służą do rozwiązywania nieco innych problemów - wymagających wielu zestawów danych, ale ogólnie wydaje mi się to analogiczne i możliwe do wykonania...

0

Mój algorytm oczywiście wypróbowałeś i wynik Cie nie zadowolił?
Okno ma szerokość 500 pikseli, tablica dane ma rozmiar 600 w pierwszym przypadku dane[i] = Math.random();, w drugim dane[i] = i*i/100.0;
user image user image

0
bogdans napisał(a):

Mój algorytm oczywiście wypróbowałeś i wynik Cie nie zadowolił?
Okno ma szerokość 500 pikseli, tablica dane ma rozmiar 600 w pierwszym przypadku dane[i] = Math.random();, w drugim dane[i] = i*i/100.0;

@bogdans, dziękuję Ci bardzo za dobre chęci, ale chyba nie zrozumiałeś do końca problemu.
Chodzi o to, by wyskalować wykres na osi OX tzn, by wyglądem był on podobny do oryginalnego wykresu ale na mniejszej ilości pikseli niż ilość wszystkich danych. Innymi słowy część danych trzeba usunąć a pozostałą albo zostawić albo jakoś przekształcić - np. uśrednić.

Niestety parabola nie jest tu zbyt pomocna.
Poza tym w poprzednim poście napisałeś:

Danych jest n, okno ma 500 pikseli. Dla każdego 0 <= i < n, współrzędna x-owa w pikselach to 500*i/n.

A jeśli n=500 to podany przez Ciebie wzór jest następujący: 500*i/500 = i = {0,1,2,...,499}

Jednym z rozwiązań jest zastosowanie średniej i chyba na niej zakończę poszukiwania. Zastosuję tylko średnią ważoną, która jest bardziej wrażliwa na zmiany.

0

Ja problem rozumiem, Ty natomiast nie rozumiesz algorytmu. A Twoje zastrzeżenia do tego że wzór 500*i/n daje dla n=500 i to jedno wielkie wtf. Tak właśnie musi być.
Podany przeze mnie algorytm skaluje rysunek. Dla tych samych danych, tego samego algorytmu ale dla paneli o szerokości 500 i 600 pikseli wykresy wyglądają tak:
user image user image

0

ale czy nie ma jakiegoś algorytmu, który by zredukował mi ilość występujących w tablicy danych do zadanej liczby, tak by nowy wektor wyglądem był najbliższy temu oryginalnemu?

dla każdego nowego X (tego ograniczonego, w zakresie 0..499) wyliczasz jaka byłaby jego pozycja w oryginalnej skali, czyli np. 0..99999.

const int M = 500; // tyle szerokości ma wykres
const int N = 100000; // tyle jest danych
for (int i=0; i<M; i++)
{
   int idx = (int)((double)i/M * N);
   // na pozycji `i` wykresu rysujesz daną z indeksem `idx`
}
0

@bogdans, rzeczywiście źle odczytałem Twój post. Teraz rozumiem o co Ci chodziło, ale ciągle coś mi nie gra...
Jeśli masz 600 danych to podstawiając iteracje pod Twój wzór mam następujące "współrzędne" dla X-a: {0, 0.83, 1.66, 2.5, ... , 499.16} - a jak wiadomo powinny być to liczby całkowite. I teraz pytanie czy Tobie o to chodziło, żeby zaokrąglać te liczby i wstawiać do wykresu tylko co n wartość?
Bo jeśli tak, to rzeczywiście jest to jedno z rozwiązań, które również rozważałem (na równi z liczeniem średniej), ale w Twoim wzorze jest mimo wszystko chyba błąd: - powinno być in/500 -> i600/500.

pozdrawiam

Pisaliśmy chyba w tym samym czasie @Azarien ;-) - tak, właśnie zauważyłem, że źle odczytałem post @bogdans -a. Więc przepraszam za wprowadzone zamieszanie.
Dziękuję Wam bardzo za pomoc!
Myślałem, że są do tego jakieś bardziej zaawansowane algorytmy, ale już odechciało mi się ich szukać ;-). To o czym wspomnieliście w zupełności mi wystarczy.

Jeszcze raz dziękuję i pozdrawiam!

0

Powinno być i*width/n, gdzie n jest ilością elementów w tablicy dane, a width szerokością wykresu (w programie miałem dobry wzór). Jakiego Ty używasz języka, że a/b jest zmiennoprzecinkowe dla a i b stałoprzecinkowych?

1 użytkowników online, w tym zalogowanych: 0, gości: 1