Histogram o zmiennej szerokości

Użytkowanie arkusza kalkulacyjnego

Histogram o zmiennej szerokości

Postprzez pachnis » Cz maja 16, 2019 10:10 am

Witam, potrzebuję stworzyć histogram w którym szerokość kolumn jest zmienna. Ma to wyglądać mniej więcej tak jak na załączonym poniżej obrazku. Czy ktoś wie może czy i jak można to zrobić?
Załączniki
histogram zmienny.PNG
LibreOffice Wersja: 6.1.4.2 na Windows 10
pachnis
 
Posty: 2
Dołączył(a): Cz maja 16, 2019 10:07 am

Re: Histogram o zmiennej szerokości

Postprzez Jan_J » Cz maja 16, 2019 3:33 pm

Ha! to jest jeden z moich ulubionych przykładów. Na taki wykres nie ma gotowca w Excelu ani w Calcu. Pokazuję czasem takie problemy studentom dla zachęty do uczenia się Matlaba, Scilaba, R-a, Pythona, albo choćby Gnuplota.

Skrypt w Python/Matplotlib mogę odgrzebać dość łatwo. Integracja z Calcem nie będzie prosta, ale przygotowanie grafiki na podstawie danych z pliku ods już tak. Z tym, że nie z poziomu Calc, tylko przez odczyt pliku innym narzędziem.

Zgodnie z pow. obietnicą, podsyłam mój `firmowy` przykład generowania podobnych wykresów funkcją pyplot.bar w Python + Matplotlib.
Źródła danych (do wyboru):
woj.zip
baza SQLite (do rozpakowania)
(40.96 KiB) Nie pobierane
albo
woj.txt
plik TSV
(531 Bajtów) Pobrane 1 raz
Dane pochodzą -- już nie pamiętam -- albo z GUS-u, albo z statoids.com.

Kod skryptu
Kod: Zaznacz cały   Rozszerz widokZwiń widok
#!/usr/bin/env python3

"""
    tworzenie wykresu na podstawie danych z bazy SQLite
    przy użyciu pakietu Matplotlib/PyPlot
"""

import sqlite3
from matplotlib import pyplot
from matplotlib.font_manager import FontProperties


def z_bazy(rok):

    baza = './woj.db'

    # parametry zapytania
    q = '''
    select wojewodztwo as "Województwo",
        powierzchnia as "Powierzchnia",
        ludnosc as "Ludność"
    from wojewodztwa
        join wojpow using(klwoj)
        join wojlud using(klwoj)
    where rok = ?
    order by ludnosc / powierzchnia desc;
    '''

    # nawiązanie połączenia
    conn = sqlite3.connect(baza)
    cursor = conn.cursor()
    cursor.execute(q, (rok,))
    data = cursor.fetchall()
    conn.close()
    return data

def z_pliku(rok, sep = '\t'):
    nazwa = './woj.txt'
    with open(nazwa) as f:
      data = [ ]
      f.readline()
      for woj in f:
        woj = woj.split(sep)
        woj[1] = float(woj[1])
        woj[2] = float(woj[2])
        data.append(woj)
    return data

def przygotuj(dane):
    ludPL = 0
    powPL = 0.0
    powWoj = []
    ludWoj = []
    nazWoj = []
    midWoj = []
    poczWoj = [0.0]
    for woj in dane:
        powWoj.append(woj[1])
        poczWoj.append(powPL + woj[1])
        midWoj.append(powPL + 0.5*woj[1])
        ludWoj.append(woj[2]/woj[1])
        nazWoj.append(woj[0])
        powPL += woj[1]
        ludPL += woj[2]
    ludPL = ludPL/powPL
    poczWoj.pop(-1)
    return poczWoj, midWoj, powWoj, ludWoj, nazWoj, powPL, ludPL

def rysuj(dane, rok):

    # obróbka odpowiedzi
    poczWoj, midWoj, powWoj, ludWoj, nazWoj, powPL, ludPL = przygotuj(dane)

    # przygotowanie wykresu
    fontFace = 'DejaVu Sans'

    fopis = FontProperties()
    fopis.set_family(fontFace)
    fopis.set_size(8)

    fnaglowek = FontProperties()
    fnaglowek.set_family(fontFace)
    fnaglowek.set_size(12)

    kolory = ('#a0a0ff', '#ffa0a0')
    opisy = ('województwa %s' % rok, 'Polska %s' % rok )

    fig = pyplot.subplot(111)
    fig.set_xlim(0.0, powPL)
    fig.set_ylim(0.0, 500.0)
    fig.set_title('Zaludnienie województw Polski', fontproperties = fnaglowek)
    fig.set_xlabel('Powierzchnia', fontproperties = fnaglowek)
    fig.set_ylabel('Gęstość zaludnienia [os./km^2]', fontproperties = fnaglowek)
    pyplot.xticks(midWoj, nazWoj, fontproperties = fopis, rotation = 90)
    fig.grid(axis = 'y')

    # kreślenie serii danych
    fig.bar(poczWoj, ludWoj, width = powWoj, align = "edge", color = kolory[0], edgecolor = 'black', label = opisy[0])
    fig.bar((0.0), (ludPL), width=powPL, align = "edge", color = kolory[1], edgecolor = 'black', alpha = 0.2, label = opisy[1])

    # legenda
    fig.legend()
    ltext = pyplot.gca().get_legend().get_texts()
    pyplot.setp(ltext[0], fontproperties = fopis, color = kolory[0])
    pyplot.setp(ltext[1], fontproperties = fopis, color = kolory[1])

rok = 2007
dane = z_bazy(rok)
rysuj(dane, rok)
pyplot.tight_layout()
pyplot.show()
oraz otrzymany z niego obrazek PNG
plwoj.png


W razie potrzeby służę pomocą przy sczytaniu danych bezpośrednio z pliku Calca. Obrazki mogą powędrować do odrębnych plików graficznych; teoretycznie dałoby się je automatycznie osadzić w dokumencie, ale wymaga to grzebaniny. Gdyby obrazków było 200, zalecałbym podjęcie wysiłku; przy 20 raczej nie.
Możliwe jest też użycie podobnego skryptu jako makra w Calcu, choć wymaga to przekonfigurowania Pythona załączonego do LibreOffice (żeby doinstalować Matplotlib + zależności).

Ale zdaje mi się, że Twój wykres ma wadę konstrukcyjną. Histogram ma być graficznym przybliżeniem gęstości rozkładu, więc na osi liczbowej winna być zaznaczona intensywność. Jeśli jest to częstość bezwzględna podawana w dniach, to łączenie klas w szersze spowoduje wydłużanie słupków. A pożądane byłoby raczej ich uśrednianie.
JJ
LO (6.1|6.2) ∙ AOO 4.1.6 ∙ Python (3.7|2.7) ∙ Unicode 12 ∙ LATEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Fedora|CentOS|SUSE)
Jan_J
 
Posty: 3892
Dołączył(a): Pt maja 22, 2009 1:20 pm
Lokalizacja: Wrocław

Re: Histogram o zmiennej szerokości

Postprzez pachnis » So maja 18, 2019 6:34 pm

Dzięki wielkie, będę kombinował :D
LibreOffice Wersja: 6.1.4.2 na Windows 10
pachnis
 
Posty: 2
Dołączył(a): Cz maja 16, 2019 10:07 am


Powrót do Calc

Kto przegląda forum

Użytkownicy przeglądający ten dział: Google [Bot], Jermor i 9 gości