Wykresy: Różnice pomiędzy wersjami
m (1 wersja) |
|||
Linia 223: | Linia 223: | ||
− | [[LibreOffice Calc – makra | <b>LibreOffice Calc – makra</b>]] [[Henryk Dąbrowski | <b>Strona główna</b>]] | + | [[LibreOffice Calc – makra – przykłady | <b>LibreOffice Calc – makra – przykłady</b>]] [[Henryk Dąbrowski | <b>Strona główna</b>]] |
Aktualna wersja na dzień 15:26, 24 maj 2024
Wprowadzenie
Napisanie kodu, który sporządzi wymagany wykres, jest zwykle nieopłacalne. Zajmuje dużo czasu, a efekt może ciągle wymagać poprawek. Znacznie prostsze i bardziej efektywne jest sporządzenie wykresu przy pomocy gotowych narzędzi dostępnych w LibreOffice. Zatem dlaczego warto poświęcić chwilę czasu, aby poznać podstawy kodowania wykresu? Zauważmy, że gdy już sporządzimy wykres (a często może to być kilka wykresów, które prezentują te same dane w różnym ujęciu), to musimy aktualizować te wykresy w miarę napływania nowych danych – te czynności (często wykonywane codziennie) zbierają dużo czasu i są uciążliwe. Właśnie w takich sytuacjach dobre makro wybawi nas z kłopotu.
Zaczniemy od prostej procedury, która przygotowuje arkusz i dane w tym arkuszu w taki sposób, aby można było je prezentować na wykresie. Dla przykładu wybraliśmy rzeczywiste dane ukazujące liczbę ludności świata, Europy i Afryki w latach 1950 - 2010. Takie dane mogą przydać się nie tylko do prezentowania wykresów, ale również do innych testów oprogramowania. Zauważmy, że kolumny B i D celowo nie zawierają interesujących nas danych. Uczyniliśmy tak dlatego, aby dostęp do danych był utrudniony: zamiast jednego zakresu komórek mamy trzy zakresy komórek wypełnione danymi.
Sub DaneDoWykresu(NazwaArkusza as String)
Dim oSht as Object
Dim A()
If NOT ThisComponent.getSheets().hasByName( NazwaArkusza ) Then 'sprawdza czy arkusz o podanej nazwie już istnieje
ThisComponent.getSheets().insertNewByName( NazwaArkusza, 0 ) 'wstawia nowy arkusz na pozycję 1 (z indeksem 0)
End If
oSht = ThisComponent.getSheets().getByName( NazwaArkusza ) 'uchwyt do arkusza przez nazwę
ThisComponent.CurrentController.setActiveSheet( oSht ) 'uaktywnienie arkusza
A = Array( Array( "Year", "", "World", "", "Africa", "Europe" ), _
Array( 1950, "", 2525, "", 229, 549 ), _
Array( 1960, "", 3018, "", 285, 606 ), _
Array( 1970, "", 3682, "", 366, 657 ), _
Array( 1980, "", 4440, "", 478, 694 ), _
Array( 1990, "", 5310, "", 632, 721 ), _
Array( 2000, "", 6127, "", 814, 726 ), _
Array( 2010, "", 6930, "", 1044, 735 ) )
oSht.getCellRangeByName( "A1:F8" ).setDataArray( A ) 'wpisujemy przygotowane dane do arkusza
End Sub
Prosty wykres kolumnowy
Przedstawiamy niżej prostą procedurę, która wygeneruje wykres kolumnowy. Uwaga: przy ponownej próbie uruchomienia procedury w ostatniej linii wystąpi błąd, gdy wykres o takiej samej nazwie już istnieje w skoroszycie. Czytelnik może skasować cały arkusz lub co najmniej skasować wygenerowany w tym arkuszu wykres.
Zauważmy też, że musieliśmy wprowadzić trzy różne zakresy komórek, aby uzyskać wykres. Ta liczba jest istotna, gdybyśmy w przyszłości potrzebowali powiększyć obszar wykresu – musimy wtedy powiększyć każdy zakres komórek osobno. Oczywiście uczyniliśmy tak jedynie dla celów demonstracji problemu. Po usunięciu kolumn B i D wszystkie dane byłyby w jednym zakresie komórek.
Dla lepszego zrozumienia działania metody addNewByName Czytelnik powinien w ostatniej linii procedury zmienić ostatni parametr na False:
oCharts.addNewByName( NazwaWykresu, oRect, oAdr(), True, False )
Taki przykład pokaże, że dane X (kategorie) zostaną potraktowane jak dane Y, a oś X zostanie ponumerowana kolejnymi liczbami całkowitymi większymi od zera.
Sub Wykresy1()
Dim NazwaArkusza as String, NazwaWykresu as String
Dim oSht as Object, oCharts as Object
Dim oRect as New com.sun.star.awt.Rectangle
Dim oAdr(2) as New com.sun.star.table.CellRangeAddress
NazwaArkusza = "Chart1"
NazwaWykresu = "MyChart1"
Call DaneDoWykresu( NazwaArkusza ) 'dodaje arkusz (w przypadku braku) i wypełnia danymi do wykresu
oSht = ThisComponent.getSheets().getByName( NazwaArkusza ) 'uchwyt do arkusza przez nazwę
ThisComponent.CurrentController.setActiveSheet( oSht ) 'uaktywnienie arkusza
oAdr(0) = oSht.getCellRangeByName( "A1:A8" ).getRangeAddress() 'dane X (lata)
oAdr(1) = oSht.getCellRangeByName( "C1:C8" ).getRangeAddress() 'dane Y1 (świat)
oAdr(2) = oSht.getCellRangeByName( "E1:F8" ).getRangeAddress() 'dane Y2 i Y3 (Afryka i Europa)
oRect.X = 15000 'pozycja X lewego górnego rogu okna wykresu w setnych milimetra (LINK)
oRect.Y = 1000 'pozycja Y lewego górnego roku okna wykresu w setnych milimetra
oRect.Width = 10000 'szerokość okna wykresu
oRect.Height = 7000 'wysokość okna wykresu
oCharts = oSht.getCharts() 'uchwyt do wszystkich wykresów w danym arkuszu
' przedostatni parametr wskazuje czy nagłówki kolumn są etykietami danych Y
' ostatni parametr wskazuje czy pierwsza kolumna danych stanowi kategorie (dane X)
oCharts.addNewByName( NazwaWykresu, oRect, oAdr(), True, True ) 'dodajemy nowy wykres
End Sub
Modyfikowanie wykresu
Uzyskany wyżej wykres jest bardzo ubogi, a prezentacja danych w kolumnach nie każdemu może odpowiadać. Łatwo możemy uczynić go bardziej czytelnym. Aby uniknąć błędu pojawiającego się, gdy wykres o takiej samej nazwie już istnieje, wprowadziliśmy prostą modyfikację i przed utworzeniem nowego wykresu sprawdzamy, czy przypadkiem wykres o takiej samej nazwie już nie został dodany.
Sub Wykresy2()
Dim NazwaArkusza as String, NazwaWykresu as String
Dim oSht as Object
Dim oCharts as Object, oCrtEmb as Object
Dim oRect as New com.sun.star.awt.Rectangle
Dim oAdr(2) as New com.sun.star.table.CellRangeAddress
NazwaArkusza = "Chart2"
NazwaWykresu = "MyChart2"
Call DaneDoWykresu( NazwaArkusza ) 'dodaje arkusz (w przypadku braku) i wypełnia danymi do wykresu
oSht = ThisComponent.getSheets().getByName( NazwaArkusza ) 'uchwyt do arkusza przez nazwę
ThisComponent.CurrentController.setActiveSheet( oSht ) 'uaktywnienie arkusza
oAdr(0) = oSht.getCellRangeByName( "A1:A8" ).getRangeAddress() 'dane X (lata)
oAdr(1) = oSht.getCellRangeByName( "C1:C8" ).getRangeAddress() 'dane Y1 (świat)
oAdr(2) = oSht.getCellRangeByName( "E1:F8" ).getRangeAddress() 'dane Y2 i Y3 (Afryka i Europa)
oRect.X = 15000 'pozycja X lewego górnego rogu okna wykresu w setnych milimetra (LINK)
oRect.Y = 1000 'pozycja Y lewego górnego roku okna wykresu w setnych milimetra
oRect.Width = 10000 'szerokość okna wykresu
oRect.Height = 7000 'wysokość okna wykresu
oCharts = oSht.getCharts() 'uchwyt do wszystkich wykresów w danym arkuszu
If NOT oCharts.hasByName( NazwaWykresu ) Then
' przedostatni parametr wskazuje czy nagłówki kolumn są nazwami danych Y
' ostatni parametr wskazuje czy pierwsza kolumna danych stanowi dane X (kategorie)
oCharts.addNewByName( NazwaWykresu, oRect, oAdr(), True, True )
End If
oCrtEmb = oCharts.getByName( NazwaWykresu ).EmbeddedObject 'uchwyt do wszystkich objektów osadzonych w oknie wykresu
oCrtEmb.HasMainTitle = True
oCrtEmb.Title.String = "Ludność świata, Afryki i Europy" 'tytuł główny (tekst)
oCrtEmb.HasSubTitle = True
oCrtEmb.Subtitle.String = "w milionach" 'podtytuł (tekst)
oCrtEmb.HasLegend = True 'legenda (widoczność)
oCrtEmb.Legend.Alignment = com.sun.star.chart.ChartLegendPosition.RIGHT 'NONE, LEFT, TOP, RIGHT, BOTTOM (LINK)
oCrtEmb.Legend.FillStyle = com.sun.star.drawing.FillStyle.SOLID 'NONE, SOLID, GRADIENT, HATCH, BITMAP (LINK)
oCrtEmb.Legend.FillColor = RGB(221, 221, 221) 'kolor tła okienka legendy
oCrtEmb.Legend.CharHeight = 8 'wysokość czcionki użytej w okienku legendy
oCrtEmb.Diagram = oCrtEmb.createInstance("com.sun.star.chart.LineDiagram") 'wykres kolumnowy zamieniamy na liniowy
oCrtEmb.Diagram.Wall.FillColor = RGB(255, 255, 255) 'kolor tła wykresu
End Sub
Wartości parametrów (w przedostatniej linii procedury) i rodzaj generowanego wykresu:
AreaDiagram 'wykres obszarowy (zwykły)
BarDiagram 'wykres kolumnowy (zwykły)
BubbleDiagram 'wykres dymkowy
DonutDiagram 'wykres kołowy (pierścieniowy)
FilledNetDiagram 'wykres siatkowy (wypełniony)
LineDiagram 'wykres liniowy (tylko linie)
NetDiagram 'wykres siatkowy (punkty i linie)
PieDiagram 'wykres kołowy (zwykły)
StockDiagram 'wykres giełdowy (1)
XYDiagram 'wykres punktowy XY (punkty i linie)
Nazwa okna wykresu (wewnętrzna)
Okno wykresu (Chart) ma swoją wewnętrzną nazwę nadaną przez system / procedurę w chwili tworzenia. Możemy też przypisać każdemu z tych okien własną nazwę w polu, do którego dostęp uzyskujemy następująco:
- lewy klik na oknie wykresu -> prawy klik -> Nazwij...
Pole to można wykorzystać i jeśli poznamy nazwę wewnętrzną nadaną przez system (zawsze postaci Object 1, Object 2 itd.) lub procedurę (w naszym przypadku mieliśmy: MyChart1, MyChart2), to możemy wpisać do tego pola numer obiektu i uzyskać łatwy i trwały dostęp do nazwy okna wykresu. Jeżeli nie nazwaliśmy w powyższy sposób okna wykresu, to dostęp do nazwy wewnętrznej jest możliwy poprzez opcję:
- Widok -> Nawigator -> Obiekty OLE
Nawigator jest też dostępny pod klawiszem F5. Klikając dwukrotnie lewym przyciskiem myszy, zostaniemy przeniesieni do odpowiedniego arkusza, na którym obiekt o wybranej nazwie zostanie uaktywniony.
Gdyby Czytelnik miał problemy z ustaleniem nazw wewnętrznych okien wykresu, to poniższa procedura przegląda wszystkie arkusze skoroszytu i dla każdego arkusza wpisuje nazwę wewnętrzną okien wykresu jako podtytuł tych okien. Oczywiście należy najpierw sporządzić roboczą kopię pliku i uruchomić procedurę będąc w roboczej kopii pliku. Dzięki temu będziemy mieli łatwy, czytelny i trwały dostęp do nazwy każdego okna wykresu.
Sub NamesOfCharts()
'wpisuje wewnętrzne nazwy wykresów jako podtytuł wykresu
Dim oSht as Object, oCrt as Object, oCrtEmb as Object
Dim i as Long, k as Long
For i = 0 To ThisComponent.getSheets().getCount() - 1 'przeglądamy wszystkie arkusze
oSht = ThisComponent.getSheets().getByIndex(i) 'uchwyt do arkusza o indeksie i
For k = 0 To oSht.getCharts().getCount() - 1 'przeglądamy wszystkie wykresy w danym arkuszu
oCrt = oSht.getCharts().getByIndex(k) 'uchwyt do wykresu o indeksie k
oCrtEmb = oCrt.EmbeddedObject 'uchwyt do wszystkich objektów osadzonych w oknie wykresu
oCrtEmb.HasSubTitle = True
oCrtEmb.Subtitle.String = oCrt.getName() 'podtytuł (tekst)
Next k
Next i
End Sub
Powiększanie zakresu danych pokazywanych na wykresie
Zamieszczona niżej procedura powiększa zakres / zakresy komórek, które stanowią dane wejściowe pokazywane na wykresie. Następuje powiększenie każdego z zakresów komórek o kolejny wiersz (od dołu).
Należy zwrócić uwagę na to, że nie w każdej sytuacji poniższa procedura będzie działała prawidłowo. Rozważmy następujący przypadek: niech będą dane zakresy komórek A1:A10 i C1:C10, gdzie w kolumnie A są dane X, w kolumnie C dane Y, a nagłówki kolumn są etykietami. W tym momencie program widzi dwa zakresy danych C1:C10 (dane Y) i A2:A10 (dane X). Jeżeli teraz będziemy chcieli zaprezentować na wykresie jedynie część danych, powiedzmy od piątego wiersza, to będziemy mieli trzy zakresy danych: C5:C10 (dane Y), A5:A10 (dane X) i C1 (etykieta danych Y). Teraz niżej zamieszczona procedura powiększy trzy zakresy, co zakończy się błędem (etykieta nie może być w dwóch komórkach). Dlatego należy używać jej rozważnie, a najlepiej ustalić i dobrze określić, które elementy z tablicy Zakresy() mają być modyfikowane.
W pewnych sytuacjach zmiana zakresu danych powoduje zmianę formatowania osi X. Zazwyczaj pomaga przywrócenie pierwotnie wybranego formatowania osi X i stąd obecność ostatniej linii w tej funkcji (oznaczonej jako komentarz).
Sub ZwiekszObszarWykresu(NazwaArkusza as String, NazwaWykresu as String)
'dla wykresu "NazwaWykresu" w arkuszu "NazwaArkusza" powiększa zakres danych
'dodając kolejny wiersz do wyjściowego zakresu komórek
Dim oSht as Object, oCrt as Object, Zakresy as Object
Dim k as Long
oSht = ThisComponent.getSheets().getByName( NazwaArkusza ) 'uchwyt do arkusza przez nazwę
oCrt = oSht.getCharts().getByName( NazwaWykresu )
Zakresy = oCrt.getRanges()
For k = LBound(Zakresy) To UBound(Zakresy)
Zakresy(k).EndRow = Zakresy(k).EndRow + 1
Next k
oCrt.setRanges( Zakresy )
'oCrt.EmbeddedObject.Diagram.XAxis.AxisType = com.sun.star.chart.ChartAxisType.DATE 'AUTOMATIC, CATEGORY, DATE (LINK)
End Sub
Przykładowe wywołanie:
Sub ZmienZakresy()
Call ZwiekszObszarWykresu( "Arkusz1", "Object 1")
End Sub
Polecane strony internetowe
Apache OpenOffice – Interface XTableCharts
Apache OpenOffice – Module chart
LibreOffice Calc – makra – przykłady Strona główna