<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2025-07-25T11:30:19+00:00</updated><id>/feed.xml</id><title type="html">Eetun jutut</title><subtitle>Eetun jutut is a blog about my life, my work, and my hobbies. It is a place where I share my thoughts, ideas, and experiences with the world. I hope you find something interesting here!</subtitle><entry><title type="html">Python koha testi</title><link href="/2025/07/24/Python_koha.html" rel="alternate" type="text/html" title="Python koha testi" /><published>2025-07-24T12:00:00+00:00</published><updated>2025-07-24T12:00:00+00:00</updated><id>/2025/07/24/Python_koha</id><content type="html" xml:base="/2025/07/24/Python_koha.html"><![CDATA[<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<script>hljs.highlightAll();</script>

<div class="container">
    <p>Tässä on koodi kirjastoaikani python3-koodille,
        joka hakee varauslistasta generoidusta excel-tiedostosta,
        haettavat varaukset ja käsittelee näiden dataa alla olevien
        koodien perusteella. Lopulta matplotlib sitten tekee frekvenssi-kuvaajat,
        joka näytetään Flask palvelimella.
    </p>
    <pre><code class="language-python">import numpy as np
from io import BytesIO
from matplotlib.figure import Figure
import base64
from collections import Counter
# Luodaan erilaisia kuvaajia ja dataa ladatuista varaustiedoista.
# Datat:
# Nideluokka (kirja, cd, paikka (aikuiset nuoret), varauspaikka

def create_bar_chart(data, title, xlabel, ylabel):
    fig = Figure(figsize=(6,3))
    ax = fig.subplots()
    items = list(data.items())
    labels, values = zip(*items)
    ax.bar(labels, values, width=0.4)
    ax.set_title(title)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    ax.tick_params(axis='x', rotation=45)
    fig.tight_layout()
    buffer = BytesIO()
    with BytesIO() as buffer:
        fig.savefig(buffer, format="png", dpi=600)
        buffer.seek(0)
        img_base64 = base64.b64encode(buffer.read()).decode("utf-8")
    return img_base64
def calc_unique_count(excel_data):
    reservations_total = len(excel_data)
    # Counter on kätevä - laskee jokaisen uniikin arvon määrän mitä siihen tungetaan!
    reservations_by_lib = Counter(row["res"] for row in excel_data)
    reservations_by_type = Counter(row["type"] for row in excel_data)
    reservations_by_loc = Counter(row["loc"] for row in excel_data)
    reservations_by_signum = Counter(str(row["signum"]) for row in excel_data)
    graphs = {
        "reservations_by_lib": create_bar_chart(dict(reservations_by_lib),"Varaukset kirjastoittain", "Kirjasto", "Määrä"),
        "reservations_by_type": create_bar_chart(dict(reservations_by_type), "Varaukset nideluokittain", "Nideluokka", "Määrä"),
        "reservations_by_loc": create_bar_chart(dict(reservations_by_loc), "Varaukset sijainnittain", "Sijainti", "Määrä"),
        "reservations_by_signum": create_bar_chart(dict(reservations_by_signum), "Varaukset signumeittain", "Signum", "Määrä")
    }
    return {
        "total": reservations_total,
        "reservations_by_lib": dict(reservations_by_lib),
        "reservations_by_type": dict(reservations_by_type),
        "reservations_by_loc": dict(reservations_by_loc),
        "reservations_by_signum": dict(reservations_by_signum),
        "graphs": graphs
    }
</code></pre>
    <a href="/downloads/python/koha_calc.py" download>Lataa calc.py</a>
    <p>Yllä oleva calc.py koodi laskeskelee tarvittavat arvot. Seuraavaksi koodi joka
        käsittelee Excel-tiedoston sisältämän datan Pandas-kirjaston avulla:
    </p>
    <pre><code class="language-python">import conf # config-tiedosto
import pandas as pd
filters = conf.filters
home = conf.settings["HOME"]
signum_id = conf.settings["signum_id"]
available_index = conf.settings["available_index"]
reservation_index = conf.settings["reservation_index"]
signum_index = conf.settings["signum_index"]
name_index = conf.settings["name_index"]
type_index = conf.settings["type_index"]
loc_index = conf.settings["loc_index"]
class ConfigurationError(Exception):
    def __init__(self, message):
        super().__init__(message)
def parse_signum(parsable_data: str):
    #if conf.settings["parse_signum"].lower() == "true":
    #    return parsable_data
    print(parsable_data)
    indexes = []
    temp = []
    pairs = []
    track = False
    if parsable_data[-1] != " ":
        parsable_data = parsable_data + " "
        
    if parsable_data[0] != " ":
        parsable_data = " " + parsable_data
    for i, char in enumerate(parsable_data):
        if char == " ":
            indexes.append(i)
    for i in range(0,len(indexes)-1):
        element = parsable_data[indexes[i]:indexes[i+1]]
        temp.append(element.replace(" ", ""))
    for k in range(0, len(temp)-1):
        if temp[k] == signum_id or temp[k+1] == signum_id:
            if temp[k].isnumeric():
                return temp[k]
            else: return temp[k+1]
    return parsable_data # Jos paria ei löydy, tulostetaan kaikki.

def process_excel(file_path: str):
    pickup_rows = []
    df = pd.read_excel(file_path, keep_default_na=False, na_values=['jokuarvo123'])
    # pandas-kirjasto luulee että luokka NA (nuoret aikuiset) on nan-datatyyppi.
    for index, row in df.iterrows():
        delete = None 
        available = row.iloc[available_index]
        reservation = row.iloc[reservation_index]
        if reservation == home:
            delete = False
        elif reservation in available:
            delete = False
        else:
            if reservation in filters and len(filters[reservation]) > 0:
                for k in filters[reservation]:
                    if k in available:
                        delete = True
                        break
        if not delete:
            pickup_rows.append({
                "res": reservation,
                "signum": parse_signum(row.iloc[signum_index]),
                "type": row.iloc[type_index],
                "name": row.iloc[name_index],
                "loc": row.iloc[loc_index]
            })
    return pickup_rows</code></pre>
     <a href="/downloads/python/koha_excel.py" download>Lataa excel.py</a>
    <p>Ja vielä conf.py tiedoston lähdekoodi:</p>
    <pre><code class="language-python">import json, os

filters_path = os.path.join(os.path.dirname(__file__), 'settings', 'filters.json')
settings_path = os.path.join(os.path.dirname(__file__), 'settings', 'settings.json')
filters = None
settings = None
# Haetaan tiedot tiedostoista yms.

with open(filters_path, "r", encoding="utf-8") as file:
    filters = json.load(file)
with open(settings_path, "r", encoding="utf-8") as file:
    settings = json.load(file)
# Poistaa oman filtterin
filters.pop(settings["HOME"])</code></pre>
     <a href="/downloads/python/koha_config.py" download>Lataa conf.py</a>
    <p>conf.py hakee settings kansiosta tarvittavat filtterit, joita käyttämällä
        Excel-tiedosto pystytään käsittelemään ja haettua noudettavat
        varaukset yms.
    </p>
    <p>Tällä sivulla annettuja koodipätkiä saa hyödyntää :)</p>
</div>]]></content><author><name></name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Python sekoilua 1</title><link href="/2025/07/24/Python_seko1.html" rel="alternate" type="text/html" title="Python sekoilua 1" /><published>2025-07-24T12:00:00+00:00</published><updated>2025-07-24T12:00:00+00:00</updated><id>/2025/07/24/Python_seko1</id><content type="html" xml:base="/2025/07/24/Python_seko1.html"><![CDATA[<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
<div class="container">
        <p>
            Tällä sivulla tutustutaan Python 3 -ohjelmointikielen perussyntaksiin ja rakenteisiin esimerkkien avulla.
            Opit mm. ehtolauseiden ja koodin rakenteen perusteet käytännön esimerkeillä.
        </p>

<h3>If-lause</h3>
<pre><code class="language-python"># Nimetään muuttuja
totuus = True
if totuus:
    print("Se on tosi!")

else:
    print("Se on epätosi!")
# Tuloste: Se on tosi!

# If-lauseita voidaan pistää sisäkkäin:
a = True
b = True

if a:
    if b:
        print("a ja b tosia!")
# Voidaan ilmaista toisinkin:
if a and b:
    print("a ja b!")

</code></pre>
<a href="/downloads/python/syntax2.py" download>syntax2.py</a>
<a href="/downloads/python/syntax1.py" download>syntax1.py</a>
<p>If-lauseella voidaan ehkä monta eri ehtoa. Jos
    ensimmäinen ehto on epätosi, totuustarkastelu siirtyy
    seuraavalle ehdolle. Jos mikään annetuista ehdoista ei ole tosi,
    koodissa aktivoituu else "blokki".
</p>
<pre><code class="language-python"># Monta eri ehtoa:
a = False
b = True
if a:
    print("a")
elif b:
    print("b")
else:
    print(False)</code></pre>

</div>]]></content><author><name></name></author><summary type="html"><![CDATA[Tällä sivulla tutustutaan Python 3 -ohjelmointikielen perussyntaksiin ja rakenteisiin esimerkkien avulla. Opit mm. ehtolauseiden ja koodin rakenteen perusteet käytännön esimerkeillä.]]></summary></entry><entry><title type="html">Tervetuloa!</title><link href="/2025/07/24/Tervetuloa.html" rel="alternate" type="text/html" title="Tervetuloa!" /><published>2025-07-24T12:00:00+00:00</published><updated>2025-07-24T12:00:00+00:00</updated><id>/2025/07/24/Tervetuloa</id><content type="html" xml:base="/2025/07/24/Tervetuloa.html"><![CDATA[<h1>Tervetuloa verkkosivulleni!</h1>]]></content><author><name></name></author><summary type="html"><![CDATA[Tervetuloa verkkosivulleni!]]></summary></entry><entry><title type="html">Testi</title><link href="/news/2025/07/24/testi.html" rel="alternate" type="text/html" title="Testi" /><published>2025-07-24T12:00:00+00:00</published><updated>2025-07-24T12:00:00+00:00</updated><id>/news/2025/07/24/testi</id><content type="html" xml:base="/news/2025/07/24/testi.html"><![CDATA[Moro]]></content><author><name></name></author><category term="news" /><summary type="html"><![CDATA[Moro]]></summary></entry></feed>