Αφού καθαρίσετε τα δεδομένα σας και τα φέρετε σε μορφή που μπορείτε να δουλέψετε — κάτι που καλύψαμε αναλυτικά στον οδηγό μας για τον καθαρισμό δεδομένων στην Python — και αφού αξιοποιήσετε τις νέες δυνατότητες του pandas 3.0 για αποδοτική διαχείριση, το επόμενο φυσικό βήμα είναι ένα: να δείτε τι κρύβουν τα δεδομένα σας. Γιατί η οπτικοποίηση δεν είναι απλώς ένα «ωραίο γράφημα» στο τέλος μιας ανάλυσης. Είναι ο τρόπος που ανακαλύπτουμε μοτίβα, εντοπίζουμε ανωμαλίες και επικοινωνούμε ευρήματα σε συνεργάτες, πελάτες ή αναγνώστες που — ας το παραδεχτούμε — δεν θέλουν να διαβάσουν πίνακες αριθμών.
Σε αυτόν τον οδηγό θα ξεκινήσουμε από τα θεμέλια — τη Matplotlib — και θα ανεβούμε σταδιακά στην κομψή στατιστική οπτικοποίηση του Seaborn. Θα δούμε τις νέες δυνατότητες της Matplotlib 3.10, θα μιλήσουμε για βέλτιστες πρακτικές που όντως κάνουν τη διαφορά, θα φτιάξουμε ένα πλήρες πρακτικό παράδειγμα από την αρχή μέχρι το τέλος, και θα ρίξουμε μια ματιά στις διαδραστικές βιβλιοθήκες που πηγαίνουν ένα βήμα παραπέρα.
Λοιπόν, ας μπούμε στο ψητό.
Ρύθμιση Περιβάλλοντος
Πρώτα απ' όλα, χρειαζόμαστε τα σωστά εργαλεία. Αν χρησιμοποιείτε ήδη pandas, πιθανότατα έχετε εγκατεστημένη τη Matplotlib. Ωστόσο, ας βεβαιωθούμε ότι έχουμε τα πάντα:
# Εγκατάσταση βιβλιοθηκών οπτικοποίησης
pip install matplotlib seaborn pandas numpy
# Προαιρετικά, για διαδραστικά γραφήματα
pip install plotly bokeh altair
Και τα βασικά imports που θα χρησιμοποιούμε σε ολόκληρο τον οδηγό:
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
import pandas as pd
import numpy as np
# Ρύθμιση για Jupyter notebooks (αν χρησιμοποιείτε)
%matplotlib inline
# Ρύθμιση ανάλυσης γραφημάτων σε Jupyter
%config InlineBackend.figure_format = 'retina'
# Επιβεβαίωση εκδόσεων
print(f"Matplotlib: {mpl.__version__}")
print(f"Seaborn: {sns.__version__}")
print(f"Pandas: {pd.__version__}")
Μια μικρή αλλά σημαντική λεπτομέρεια: αν δουλεύετε σε Jupyter notebook, η εντολή %config InlineBackend.figure_format = 'retina' κάνει τα γραφήματα πολύ πιο ευκρινή σε οθόνες υψηλής ανάλυσης. Μία γραμμή κώδικα, τεράστια αισθητική διαφορά — δοκιμάστε το και θα καταλάβετε αμέσως.
Matplotlib: Τα Θεμέλια της Οπτικοποίησης
Η Matplotlib είναι η «μητέρα» όλων των βιβλιοθηκών οπτικοποίησης στην Python. Σχεδόν κάθε άλλο εργαλείο — Seaborn, pandas plotting, ακόμα και μέρη του Plotly — βασίζεται σε αυτήν ή εμπνέεται από αυτήν.
Αν καταλάβετε τη Matplotlib, καταλαβαίνετε τη βάση.
Δύο Διεπαφές: pyplot vs OOP
Η Matplotlib προσφέρει δύο τρόπους δημιουργίας γραφημάτων. Ο πρώτος είναι η διεπαφή pyplot — γρήγορη, βολική για εξερεύνηση. Ο δεύτερος είναι η αντικειμενοστραφής διεπαφή (OOP) — πιο ρητή, κατάλληλη για παραγωγικό κώδικα.
# Τρόπος 1: pyplot (γρήγορα πρωτότυπα)
plt.plot([1, 2, 3, 4], [10, 20, 25, 30])
plt.title("Γρήγορο Γράφημα")
plt.xlabel("Χρόνος")
plt.ylabel("Τιμή")
plt.show()
# Τρόπος 2: OOP (προτεινόμενος για παραγωγή)
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot([1, 2, 3, 4], [10, 20, 25, 30])
ax.set_title("Γράφημα με OOP Interface")
ax.set_xlabel("Χρόνος")
ax.set_ylabel("Τιμή")
plt.tight_layout()
plt.show()
Η σύστασή μου; Μάθετε και τα δύο, αλλά χρησιμοποιήστε την OOP διεπαφή για οτιδήποτε πέρα από μια γρήγορη ματιά. Ειλικρινά, η ρητότητα του fig, ax = plt.subplots() μου έχει γλιτώσει αμέτρητα bugs σε πολύπλοκα layouts. Κάνει τον κώδικά σας πιο συντηρήσιμο και πιο εύκολο στο debugging.
Βασικοί Τύποι Γραφημάτων
Ας δούμε τους τέσσερις πιο θεμελιώδεις τύπους γραφημάτων, με πρακτικά παραδείγματα σε pandas DataFrames:
# Δημιουργία δεδομένων σε DataFrame
np.random.seed(42)
months = ['Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μαΐ', 'Ιουν',
'Ιουλ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ']
df = pd.DataFrame({
'Μήνας': months,
'Πωλήσεις_2024': np.random.randint(200, 500, 12),
'Πωλήσεις_2025': np.random.randint(250, 550, 12),
'Θερμοκρασία': [10, 11, 14, 18, 23, 28, 32, 31, 27, 21, 15, 11],
'Υγρασία': [75, 72, 65, 58, 48, 40, 35, 38, 50, 62, 70, 76]
})
# --- 1. Γράφημα γραμμής (Line Plot) ---
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(df['Μήνας'], df['Πωλήσεις_2024'], marker='o', label='2024')
ax.plot(df['Μήνας'], df['Πωλήσεις_2025'], marker='s', label='2025')
ax.set_title('Μηνιαίες Πωλήσεις')
ax.set_ylabel('Μονάδες')
ax.legend()
ax.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# --- 2. Γράφημα ράβδων (Bar Plot) ---
fig, ax = plt.subplots(figsize=(10, 5))
x = np.arange(len(months))
width = 0.35
ax.bar(x - width/2, df['Πωλήσεις_2024'], width, label='2024', color='steelblue')
ax.bar(x + width/2, df['Πωλήσεις_2025'], width, label='2025', color='coral')
ax.set_xticks(x)
ax.set_xticklabels(months, rotation=45)
ax.set_title('Σύγκριση Πωλήσεων ανά Μήνα')
ax.set_ylabel('Μονάδες')
ax.legend()
plt.tight_layout()
plt.show()
# --- 3. Γράφημα διασποράς (Scatter Plot) ---
fig, ax = plt.subplots(figsize=(8, 6))
scatter = ax.scatter(df['Θερμοκρασία'], df['Υγρασία'],
c=df['Πωλήσεις_2025'], cmap='viridis',
s=100, edgecolors='black', linewidth=0.5)
ax.set_xlabel('Θερμοκρασία (°C)')
ax.set_ylabel('Υγρασία (%)')
ax.set_title('Σχέση Θερμοκρασίας - Υγρασίας')
plt.colorbar(scatter, label='Πωλήσεις 2025')
plt.tight_layout()
plt.show()
# --- 4. Ιστόγραμμα (Histogram) ---
fig, ax = plt.subplots(figsize=(8, 5))
data_sample = np.random.normal(loc=50, scale=15, size=1000)
ax.hist(data_sample, bins=30, color='teal', edgecolor='white', alpha=0.8)
ax.set_xlabel('Τιμή')
ax.set_ylabel('Συχνότητα')
ax.set_title('Κατανομή Τιμών')
ax.axvline(np.mean(data_sample), color='red', linestyle='--',
label=f'Μέσος: {np.mean(data_sample):.1f}')
ax.legend()
plt.tight_layout()
plt.show()
Προσαρμογή Γραφημάτων
Εδώ βρίσκεται η πραγματική δύναμη της Matplotlib — η σχεδόν απεριόριστη δυνατότητα προσαρμογής. Χρώματα, γραμματοσειρές, επισημειώσεις, τα πάντα είναι ρυθμιζόμενα. Κι αυτό είναι ταυτόχρονα ευλογία και κατάρα (πολλές φορές χάνεσαι στις λεπτομέρειες).
# Προσαρμογή στυλ, χρωμάτων και επισημειώσεων
fig, ax = plt.subplots(figsize=(10, 6))
# Δεδομένα
categories = ['Τεχνολογία', 'Υγεία', 'Εκπαίδευση', 'Ενέργεια', 'Χρηματοοικονομικά']
values = [85, 72, 68, 91, 77]
colors = ['#2196F3', '#4CAF50', '#FF9800', '#F44336', '#9C27B0']
bars = ax.barh(categories, values, color=colors, edgecolor='white', height=0.6)
# Προσθήκη τιμών στις ράβδους
for bar, val in zip(bars, values):
ax.text(bar.get_width() + 1, bar.get_y() + bar.get_height()/2,
f'{val}%', va='center', fontweight='bold', fontsize=11)
ax.set_xlabel('Βαθμολογία (%)', fontsize=12)
ax.set_title('Αξιολόγηση Τομέων 2025', fontsize=14, fontweight='bold', pad=15)
ax.set_xlim(0, 105)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.grid(axis='x', alpha=0.3)
plt.tight_layout()
plt.show()
Subplots και Layouts με GridSpec
Σε πραγματικές αναλύσεις, σπάνια φτιάχνουμε ένα μόνο γράφημα. Η δημιουργία πολλαπλών υπο-γραφημάτων σε μια ενιαία εικόνα είναι κρίσιμη δεξιότητα — και η GridSpec μάς δίνει πλήρη έλεγχο στη διάταξη:
from matplotlib.gridspec import GridSpec
# Δημιουργία σύνθετης διάταξης
fig = plt.figure(figsize=(14, 8))
gs = GridSpec(2, 3, figure=fig, hspace=0.35, wspace=0.3)
# Μεγάλο γράφημα αριστερά (2 γραμμές, 2 στήλες)
ax_main = fig.add_subplot(gs[:, :2])
ax_main.plot(df['Μήνας'], df['Θερμοκρασία'], 'o-', color='tomato', linewidth=2)
ax_main.set_title('Ετήσια Θερμοκρασία', fontsize=13)
ax_main.set_ylabel('°C')
ax_main.fill_between(range(12), df['Θερμοκρασία'], alpha=0.2, color='tomato')
ax_main.set_xticks(range(12))
ax_main.set_xticklabels(months, rotation=45)
# Πάνω δεξιά: Ιστόγραμμα
ax_top = fig.add_subplot(gs[0, 2])
ax_top.hist(df['Πωλήσεις_2025'], bins=6, color='steelblue', edgecolor='white')
ax_top.set_title('Κατανομή Πωλήσεων', fontsize=11)
# Κάτω δεξιά: Πίτα
ax_bottom = fig.add_subplot(gs[1, 2])
top_3 = df.nlargest(3, 'Πωλήσεις_2025')
ax_bottom.pie(top_3['Πωλήσεις_2025'], labels=top_3['Μήνας'],
autopct='%1.0f%%', colors=['#5DA5DA', '#FAA43A', '#60BD68'])
ax_bottom.set_title('Top 3 Μήνες', fontsize=11)
plt.suptitle('Dashboard Πωλήσεων & Κλίματος', fontsize=15, fontweight='bold', y=1.02)
plt.tight_layout()
plt.show()
Παρατηρήστε πώς η GridSpec μάς επιτρέπει να δημιουργήσουμε μια ασύμμετρη διάταξη — ένα μεγάλο γράφημα που καταλαμβάνει δύο τρίτα του χώρου και δύο μικρότερα δεξιά. Αυτή η ευελιξία είναι ανεκτίμητη όταν φτιάχνετε αναφορές ή dashboards.
Seaborn: Στατιστική Οπτικοποίηση Υψηλού Επιπέδου
Αν η Matplotlib είναι τα θεμέλια, το Seaborn είναι ο κομψός τρόπος να χτίσετε πάνω τους. Κάνει τρία πράγματα εξαιρετικά καλά: ενσωματώνει στατιστικούς υπολογισμούς απευθείας στα γραφήματα, δουλεύει τέλεια με pandas DataFrames, και παράγει αισθητικά ωραία γραφήματα με ελάχιστο κώδικα.
Προσωπικά, είναι η βιβλιοθήκη στην οποία καταφεύγω πιο συχνά για εξερευνητική ανάλυση.
Γιατί Seaborn πάνω από τη Matplotlib
Δεν αντικαθιστά τη Matplotlib — τη συμπληρώνει. Σκεφτείτε το έτσι: αν θέλετε ένα γρήγορο boxplot κατά κατηγορία σε ένα DataFrame, με τη Matplotlib χρειάζεστε κάπου 15 γραμμές κώδικα. Με το Seaborn; Μία.
# Δημιουργία δεδομένων για τα παραδείγματα Seaborn
np.random.seed(42)
n = 300
df_tips = pd.DataFrame({
'Ποσό': np.random.exponential(scale=20, size=n) + 10,
'Φιλοδώρημα': np.random.exponential(scale=3, size=n) + 1,
'Ημέρα': np.random.choice(['Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ', 'Κυρ'], n),
'Γεύμα': np.random.choice(['Μεσημέρι', 'Βράδυ'], n, p=[0.4, 0.6]),
'Άτομα': np.random.choice([1, 2, 3, 4, 5, 6], n, p=[0.1, 0.35, 0.25, 0.15, 0.1, 0.05])
})
df_tips['Ποσοστό_Φιλοδ'] = (df_tips['Φιλοδώρημα'] / df_tips['Ποσό'] * 100).round(1)
# Ρύθμιση θέματος Seaborn
sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)
Γραφήματα Κατανομής
Η κατανόηση της κατανομής των δεδομένων σας είναι πάντα — πάντα — το πρώτο βήμα κάθε ανάλυσης. Το Seaborn σας δίνει πολλαπλούς τρόπους να το κάνετε:
# Σύνθετο γράφημα κατανομής
fig, axes = plt.subplots(1, 3, figsize=(16, 5))
# 1. Ιστόγραμμα με KDE
sns.histplot(data=df_tips, x='Ποσό', kde=True, bins=25,
color='steelblue', ax=axes[0])
axes[0].set_title('Κατανομή Ποσού (histplot + KDE)')
# 2. KDE plot με hue
sns.kdeplot(data=df_tips, x='Ποσό', hue='Γεύμα',
fill=True, alpha=0.4, ax=axes[1])
axes[1].set_title('Πυκνότητα ανά Γεύμα (kdeplot)')
# 3. Rug plot σε συνδυασμό με KDE
sns.kdeplot(data=df_tips, x='Φιλοδώρημα', color='coral', ax=axes[2])
sns.rugplot(data=df_tips, x='Φιλοδώρημα', color='coral',
alpha=0.3, ax=axes[2])
axes[2].set_title('KDE + Rug Plot Φιλοδωρήματος')
plt.tight_layout()
plt.show()
Κατηγορικά Γραφήματα
Η σύγκριση κατανομών μεταξύ κατηγοριών είναι εκεί που το Seaborn πραγματικά λάμπει. Δείτε τέσσερις διαφορετικές προσεγγίσεις:
# Τέσσερα κατηγορικά γραφήματα
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 1. Box Plot -- κλασική επιλογή
sns.boxplot(data=df_tips, x='Ημέρα', y='Ποσό',
order=['Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ', 'Κυρ'],
palette='Set2', ax=axes[0, 0])
axes[0, 0].set_title('Box Plot: Ποσό ανά Ημέρα')
# 2. Violin Plot -- δείχνει πλήρη κατανομή
sns.violinplot(data=df_tips, x='Γεύμα', y='Ποσοστό_Φιλοδ',
palette='pastel', inner='quartile', ax=axes[0, 1])
axes[0, 1].set_title('Violin Plot: Ποσοστό Φιλοδωρήματος')
# 3. Swarm Plot -- κάθε σημείο ξεχωριστά
sns.swarmplot(data=df_tips[df_tips['Άτομα'] <= 4],
x='Άτομα', y='Φιλοδώρημα',
hue='Γεύμα', palette='deep', size=4, ax=axes[1, 0])
axes[1, 0].set_title('Swarm Plot: Φιλοδώρημα ανά Άτομα')
# 4. Bar Plot με εκτίμηση μέσου και CI
sns.barplot(data=df_tips, x='Ημέρα', y='Φιλοδώρημα',
order=['Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ', 'Κυρ'],
palette='coolwarm', errorbar='ci', ax=axes[1, 1])
axes[1, 1].set_title('Bar Plot: Μέσο Φιλοδώρημα (95% CI)')
plt.tight_layout()
plt.show()
Κάτι που αξίζει να σημειωθεί: το barplot του Seaborn υπολογίζει αυτόματα τον μέσο όρο και εμφανίζει το 95% confidence interval. Με τη Matplotlib θα χρειαζόταν χειροκίνητος υπολογισμός — κάτι που πολλοί ξεχνούν ή αμελούν.
Γραφήματα Σχέσεων
Η εξερεύνηση σχέσεων μεταξύ μεταβλητών είναι ουσιαστικά ο πυρήνας της ανάλυσης δεδομένων. Ας δούμε πώς:
# Γραφήματα σχέσεων
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
# 1. Scatter plot με regression line
sns.regplot(data=df_tips, x='Ποσό', y='Φιλοδώρημα',
scatter_kws={'alpha': 0.4}, line_kws={'color': 'red'},
ax=axes[0])
axes[0].set_title('Σχέση Ποσού - Φιλοδωρήματος')
# 2. Line plot με confidence interval
daily_avg = df_tips.groupby('Ημέρα')['Ποσό'].agg(['mean', 'std']).reset_index()
daily_avg.columns = ['Ημέρα', 'Μέσος', 'Std']
order = ['Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ', 'Κυρ']
daily_avg['Ημέρα'] = pd.Categorical(daily_avg['Ημέρα'], categories=order, ordered=True)
daily_avg = daily_avg.sort_values('Ημέρα')
sns.lineplot(data=df_tips, x='Ημέρα', y='Ποσό',
estimator='mean', errorbar='sd',
marker='o', sort=False, ax=axes[1])
axes[1].set_title('Μέσο Ποσό ανά Ημέρα (±SD)')
axes[1].tick_params(axis='x', rotation=45)
# 3. Heatmap συσχετίσεων
numeric_cols = df_tips[['Ποσό', 'Φιλοδώρημα', 'Άτομα', 'Ποσοστό_Φιλοδ']]
corr_matrix = numeric_cols.corr()
sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='RdBu_r',
center=0, square=True, linewidths=1, ax=axes[2])
axes[2].set_title('Πίνακας Συσχετίσεων')
plt.tight_layout()
plt.show()
Ένα εξαιρετικά χρήσιμο εργαλείο εξερεύνησης είναι το pairplot. Δημιουργεί αυτόματα γραφήματα διασποράς για κάθε ζεύγος αριθμητικών μεταβλητών — ιδανικό για μια γρήγορη πρώτη ματιά σε ένα νέο dataset:
# Pair plot -- γρήγορη εξερεύνηση πολλών μεταβλητών
sns.pairplot(df_tips[['Ποσό', 'Φιλοδώρημα', 'Άτομα', 'Γεύμα']],
hue='Γεύμα', palette='husl', diag_kind='kde',
plot_kws={'alpha': 0.5, 's': 30})
plt.suptitle('Pair Plot: Εξερεύνηση Σχέσεων', y=1.02, fontsize=14)
plt.show()
Η Διεπαφή Objects (so.Plot)
Από την έκδοση 0.12, το Seaborn εισήγαγε μια νέα δηλωτική διεπαφή βασισμένη στη λογική «γραμματική γραφημάτων» (Grammar of Graphics). Αν έχετε δουλέψει με ggplot2 στην R ή με το Altair, θα σας φανεί αρκετά οικεία:
import seaborn.objects as so
# Δημιουργία γραφήματος με τη νέα objects διεπαφή
(
so.Plot(df_tips, x='Ποσό', y='Φιλοδώρημα', color='Γεύμα')
.add(so.Dot(alpha=0.5))
.add(so.Line(), so.PolyFit(order=1))
.label(title='Σχέση Ποσού & Φιλοδωρήματος',
x='Ποσό Λογαριασμού (€)',
y='Φιλοδώρημα (€)')
.theme({**sns.axes_style("whitegrid")})
.show()
)
# Faceted plot -- ένα γράφημα ανά κατηγορία
(
so.Plot(df_tips, x='Ποσό', y='Φιλοδώρημα', color='Γεύμα')
.add(so.Dot(alpha=0.4))
.facet(col='Γεύμα')
.label(title='Σχέση ανά Τύπο Γεύματος')
.share(y=True)
.show()
)
Η so.Plot διεπαφή είναι ακόμα σε εξέλιξη, αλλά αντιπροσωπεύει το μέλλον του Seaborn. Αξίζει να την παρακολουθείτε — η δηλωτική σύνταξη κάνει τον κώδικα πιο αναγνώσιμο και πιο εύκολο στη σύνθεση πολύπλοκων γραφημάτων.
Θέματα και Ενσωματωμένα Στυλ
Το Seaborn προσφέρει πέντε ενσωματωμένα στυλ και αρκετές χρωματικές παλέτες. Ρίξτε μια ματιά:
# Τα πέντε θέματα του Seaborn
styles = ['white', 'whitegrid', 'dark', 'darkgrid', 'ticks']
fig, axes = plt.subplots(1, 5, figsize=(20, 3))
for ax, style in zip(axes, styles):
with sns.axes_style(style):
ax.plot([0, 1, 2, 3], [0, 1, 4, 9])
ax.set_title(style, fontsize=10)
plt.tight_layout()
plt.show()
# Χρωματικές παλέτες
palettes = ['deep', 'muted', 'pastel', 'bright', 'dark', 'colorblind']
fig, axes = plt.subplots(1, 6, figsize=(18, 2))
for ax, pal in zip(axes, palettes):
colors = sns.color_palette(pal)
ax.bar(range(len(colors)), [1]*len(colors), color=colors)
ax.set_title(pal, fontsize=9)
ax.set_xticks([])
ax.set_yticks([])
plt.tight_layout()
plt.show()
Μια σημαντική συμβουλή: η παλέτα colorblind είναι σχεδιασμένη ώστε τα χρώματα να διακρίνονται από άτομα με αχρωματοψία. Αν φτιάχνετε γραφήματα για δημόσια παρουσίαση ή δημοσίευση, χρησιμοποιήστε τη. Σοβαρά.
Νέες Δυνατότητες Matplotlib 3.10
Η έκδοση 3.10 της Matplotlib (κυκλοφόρησε τον Δεκέμβριο 2024) φέρνει αρκετές σημαντικές βελτιώσεις που αξίζει να γνωρίζετε. Ας τις δούμε μία-μία.
Ο Νέος Κύκλος Χρωμάτων 'petroff10'
Η πιο ορατή αλλαγή είναι ο νέος κύκλος χρωμάτων petroff10, σχεδιασμένος με γνώμονα την προσβασιμότητα. Τα χρώματα είναι βελτιστοποιημένα ώστε να διακρίνονται τόσο σε κανονική όραση όσο και σε περιπτώσεις αχρωματοψίας:
# Χρήση του νέου κύκλου χρωμάτων petroff10
plt.rcParams['axes.prop_cycle'] = plt.cycler(
color=plt.cm.colors.PETROFF10.colors
)
fig, ax = plt.subplots(figsize=(10, 6))
for i in range(10):
ax.plot(range(10), np.random.randn(10).cumsum() + i*2,
linewidth=2, label=f'Σειρά {i+1}')
ax.set_title("Κύκλος Χρωμάτων 'petroff10' — Φιλικός προς Αχρωματοψία")
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
Νέοι Αποκλίνοντες Χρωματικοί Χάρτες
Τρεις νέοι diverging colormaps — berlin, managua και vanimo — είναι πλέον διαθέσιμοι. Είναι αντιληπτικά ομοιόμορφοι (perceptually uniform), που σημαίνει ότι ίσες διαφορές στα δεδομένα αντιστοιχούν σε ίσες οπτικές διαφορές. Αυτό ακούγεται θεωρητικό, αλλά στην πράξη κάνει μεγάλη διαφορά στην ακρίβεια ερμηνείας.
# Σύγκριση νέων diverging colormaps
data = np.random.randn(15, 15)
fig, axes = plt.subplots(1, 3, figsize=(16, 4))
cmaps = ['berlin', 'managua', 'vanimo']
for ax, cmap in zip(axes, cmaps):
im = ax.imshow(data, cmap=cmap, aspect='auto')
ax.set_title(f"cmap='{cmap}'", fontsize=12)
plt.colorbar(im, ax=ax, shrink=0.8)
ax.set_xticks([])
ax.set_yticks([])
plt.suptitle('Νέοι Diverging Colormaps στη Matplotlib 3.10',
fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()
Υποστήριξη DataFrame στο ax.table()
Αυτό είναι μια πολύ πρακτική προσθήκη: πλέον μπορείτε να περάσετε ένα pandas DataFrame απευθείας στη μέθοδο ax.table() χωρίς χειροκίνητη μετατροπή. Μικρό αλλά πολύ ευπρόσδεκτο.
# Δημιουργία πίνακα απευθείας από DataFrame
summary_df = pd.DataFrame({
'Μέτρηση': ['Μέσος', 'Διάμεσος', 'Τυπική Απόκλιση', 'Ελάχιστο', 'Μέγιστο'],
'Ποσό': [32.5, 28.1, 12.3, 10.0, 85.4],
'Φιλοδώρημα': [4.2, 3.5, 2.1, 1.0, 15.2]
})
fig, ax = plt.subplots(figsize=(8, 3))
ax.axis('off')
table = ax.table(cellText=summary_df.values,
colLabels=summary_df.columns,
cellLoc='center',
loc='center')
table.auto_set_font_size(False)
table.set_fontsize(11)
table.scale(1.2, 1.5)
ax.set_title('Στατιστικά Στοιχεία', fontsize=13,
fontweight='bold', pad=20)
plt.tight_layout()
plt.show()
Vectorized Παράμετροι Ιστογράμματος
Στη Matplotlib 3.10, μπορείτε πλέον να ορίσετε διαφορετικό στυλ για κάθε κάδο (bin) ενός ιστογράμματος — χρώμα, διαφάνεια, γραμμή περιγράμματος. Αυτό ανοίγει πολλές δημιουργικές δυνατότητες:
# Vectorized στυλ σε ιστογράμματα
np.random.seed(42)
data = np.random.normal(50, 15, 500)
fig, ax = plt.subplots(figsize=(10, 5))
n, bins, patches = ax.hist(data, bins=20, edgecolor='white')
# Χρωματισμός κάθε ράβδου ξεχωριστά βάσει ύψους
norm = plt.Normalize(n.min(), n.max())
cmap = plt.cm.viridis
for count, patch in zip(n, patches):
patch.set_facecolor(cmap(norm(count)))
ax.set_title('Ιστόγραμμα με Vectorized Χρωματισμό')
ax.set_xlabel('Τιμή')
ax.set_ylabel('Συχνότητα')
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
plt.colorbar(sm, ax=ax, label='Πλήθος')
plt.tight_layout()
plt.show()
Βελτιώσεις 3D: fill_between και Arcball Rotation
Οι βελτιώσεις στα τρισδιάστατα γραφήματα περιλαμβάνουν τη νέα μέθοδο fill_between για 3D axes και τη δυνατότητα arcball rotation, που κάνει την περιστροφή πολύ πιο φυσική (κι επιτέλους πιο εύχρηστη):
# Τρισδιάστατο γράφημα με fill_between
fig = plt.figure(figsize=(10, 7))
ax = fig.add_subplot(111, projection='3d')
# Δεδομένα
t = np.linspace(0, 4 * np.pi, 200)
x = np.cos(t)
y = np.sin(t)
z = t / (4 * np.pi)
ax.plot(x, y, z, color='steelblue', linewidth=2)
ax.set_title('Τρισδιάστατη Σπειροειδής Καμπύλη')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.tight_layout()
plt.show()
Ταχύτερη Δημιουργία Axes
Πέρα από τα ορατά χαρακτηριστικά, η Matplotlib 3.10 φέρνει 20-25% ταχύτερη δημιουργία axes. Αν δημιουργείτε δεκάδες ή εκατοντάδες υπο-γραφήματα (κάτι σύνηθες σε εξερευνητική ανάλυση), θα δείτε αισθητή βελτίωση. Το καλύτερο; Δεν χρειάζεται να αλλάξετε τίποτα στον κώδικά σας — η βελτιστοποίηση είναι εσωτερική.
Βέλτιστες Πρακτικές Οπτικοποίησης
Η τεχνική γνώση δεν αρκεί — χρειάζεται και σωστή κρίση. Ένα «λανθασμένο» γράφημα μπορεί να παραπλανήσει, ακόμα κι αν τα δεδομένα πίσω από αυτό είναι σωστά.
Ας δούμε τις πρακτικές που κάνουν πραγματικά τη διαφορά.
Επιλογή Σωστού Τύπου Γραφήματος
Κάθε τύπος γραφήματος εξυπηρετεί διαφορετικό σκοπό. Η λανθασμένη επιλογή μπορεί να αποκρύψει ή να παραμορφώσει τα δεδομένα:
- Σύγκριση κατηγοριών: Γραφήματα ράβδων (bar charts) — ξεκάθαρα και κατανοητά από όλους.
- Τάσεις στον χρόνο: Γραφήματα γραμμής (line charts) — ο ανθρώπινος εγκέφαλος αντιλαμβάνεται τη ροή φυσικά.
- Κατανομές: Ιστογράμματα, KDE plots, box plots — αποκαλύπτουν τη μορφή των δεδομένων.
- Σχέσεις μεταξύ μεταβλητών: Scatter plots — αποκαλύπτουν συσχετίσεις και clusters.
- Αναλογίες μέρους-συνόλου: Stacked bar charts — σπάνια pie charts (μόνο αν υπάρχουν 2-4 κατηγορίες, αλλιώς μην μπαίνετε καν στον κόπο).
- Πίνακες συσχετίσεων: Heatmaps — αποδοτική οπτικοποίηση πολλών μεταβλητών ταυτόχρονα.
Προσβασιμότητα Χρωμάτων
Περίπου 8% των ανδρών και 0,5% των γυναικών έχουν κάποια μορφή αχρωματοψίας. Αν τα γραφήματά σας βασίζονται μόνο σε χρώμα για τη μετάδοση πληροφοριών, αποκλείετε σημαντικό μέρος του κοινού σας. Κι αυτό είναι κάτι που πολλοί παραβλέπουν.
# Φιλική προς αχρωματοψία παλέτα
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# ΛΑΝΘΑΣΜΕΝΟ: Κόκκινο-πράσινο (πρόβλημα για deuteranopia)
colors_bad = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00']
axes[0].bar(['Α', 'Β', 'Γ', 'Δ'], [25, 40, 30, 35], color=colors_bad)
axes[0].set_title('Αποφύγετε: Κόκκινο-Πράσινο', color='red')
# ΣΩΣΤΟ: Χρήση colorblind-safe παλέτας
colors_good = sns.color_palette("colorblind", 4)
axes[1].bar(['Α', 'Β', 'Γ', 'Δ'], [25, 40, 30, 35], color=colors_good)
axes[1].set_title('Προτιμήστε: Colorblind-Safe Παλέτα', color='green')
plt.tight_layout()
plt.show()
Πέρα από τα χρώματα, χρησιμοποιήστε πρόσθετες οπτικές ενδείξεις: διαφορετικά σύμβολα (markers), μοτίβα γεμίσματος (hatching), και ετικέτες κειμένου. Έτσι τα γραφήματα γίνονται αναγνώσιμα ακόμα και σε ασπρόμαυρη εκτύπωση.
Αντιληπτικά Ομοιόμορφοι Χρωματικοί Χάρτες
Η επιλογή colormap έχει μεγαλύτερη σημασία απ' ό,τι φαντάζεστε. Ο κλασικός jet (rainbow) colormap είναι αντιληπτικά ανομοιόμορφος — δημιουργεί ψεύτικα «σύνορα» εκεί που δεν υπάρχουν στα δεδομένα. Αντί γι' αυτόν, χρησιμοποιήστε τους σύγχρονους colormaps:
- viridis (προεπιλογή): Εξαιρετική γενική επιλογή — ομοιόμορφη, φιλική σε αχρωματοψία, λειτουργεί σε ασπρόμαυρο.
- plasma, inferno, magma: Εναλλακτικές με διαφορετική αισθητική, εξίσου ομοιόμορφες.
- cividis: Βελτιστοποιημένη ειδικά για deuteranopia.
- berlin, managua, vanimo (νέοι στη 3.10): Κατάλληλοι για δεδομένα με κεντρικό σημείο αναφοράς (π.χ. θετικές/αρνητικές αποκλίσεις).
# Σύγκριση colormaps: jet vs viridis
data = np.random.randn(20, 20)
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# Κακή επιλογή: jet
im1 = axes[0].imshow(data, cmap='jet')
axes[0].set_title("cmap='jet' — Αποφύγετε!", color='red')
plt.colorbar(im1, ax=axes[0])
# Καλή επιλογή: viridis
im2 = axes[1].imshow(data, cmap='viridis')
axes[1].set_title("cmap='viridis' — Προτιμήστε!", color='green')
plt.colorbar(im2, ax=axes[1])
plt.tight_layout()
plt.show()
Ετικέτες, Επισημειώσεις και Αφήγηση
Ένα γράφημα χωρίς πλαίσιο είναι απλώς μια εικόνα. Για να γίνει πληροφοριακό, χρειάζεται:
- Τίτλος: Περιγράφει τι δείχνει το γράφημα — σύντομα, ξεκάθαρα.
- Ετικέτες αξόνων: Πάντα με μονάδες μέτρησης (€, °C, %, κλπ.).
- Υπόμνημα (legend): Μόνο αν υπάρχουν πολλαπλές σειρές δεδομένων.
- Επισημειώσεις (annotations): Για να τραβήξετε την προσοχή σε σημαντικά σημεία.
# Παράδειγμα αφηγηματικού γραφήματος
fig, ax = plt.subplots(figsize=(10, 6))
months_num = range(1, 13)
revenue = [45, 42, 48, 55, 62, 58, 71, 85, 78, 69, 73, 92]
ax.plot(months_num, revenue, 'o-', color='#2196F3', linewidth=2.5,
markersize=8, markerfacecolor='white', markeredgewidth=2)
# Επισήμανση μέγιστου σημείου
max_idx = np.argmax(revenue)
ax.annotate(f'Μέγιστο: {revenue[max_idx]}K€',
xy=(months_num[max_idx], revenue[max_idx]),
xytext=(months_num[max_idx]-2, revenue[max_idx]+8),
fontsize=11, fontweight='bold',
arrowprops=dict(arrowstyle='->', color='red', lw=2),
color='red')
# Γραμμή στόχου
ax.axhline(y=65, color='gray', linestyle='--', alpha=0.7)
ax.text(12.3, 65, 'Στόχος\n65K€', fontsize=9, va='center', color='gray')
# Χρωματισμός περιοχών
ax.fill_between(months_num, revenue, 65,
where=[r >= 65 for r in revenue],
alpha=0.15, color='green', label='Πάνω από στόχο')
ax.fill_between(months_num, revenue, 65,
where=[r < 65 for r in revenue],
alpha=0.15, color='red', label='Κάτω από στόχο')
ax.set_xlabel('Μήνας', fontsize=12)
ax.set_ylabel('Έσοδα (K€)', fontsize=12)
ax.set_title('Μηνιαία Έσοδα 2025 vs Στόχος', fontsize=14, fontweight='bold')
ax.set_xticks(months_num)
ax.set_xticklabels(['Ι', 'Φ', 'Μ', 'Α', 'Μ', 'Ι', 'Ι', 'Α', 'Σ', 'Ο', 'Ν', 'Δ'])
ax.legend(loc='upper left')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.show()
Συνήθη Λάθη που Πρέπει να Αποφεύγετε
Μετά από αρκετά χρόνια δουλειάς με δεδομένα, αυτά είναι τα λάθη που βλέπω πιο συχνά (και παραδέχομαι ότι κάποια τα έχω κάνει κι εγώ):
- 3D γραφήματα όταν αρκεί 2D: Φαίνονται εντυπωσιακά, αλλά συχνά δυσκολεύουν την ανάγνωση τιμών. Χρησιμοποιήστε 3D μόνο αν η τρίτη διάσταση προσθέτει πραγματική πληροφορία.
- Pie charts για πολλές κατηγορίες: Ο ανθρώπινος εγκέφαλος δεν συγκρίνει γωνίες καλά. Πάνω από 4-5 κατηγορίες; Bar chart, πάντα.
- Rainbow colormaps (jet): Δημιουργούν ψεύτικα μοτίβα. Χρησιμοποιήστε viridis ή άλλες αντιληπτικά ομοιόμορφες εναλλακτικές.
- Υπερβολικό clutter: Πάρα πολλές σειρές, πάρα πολλά χρώματα, πάρα πολλές ετικέτες. Το «λιγότερο είναι περισσότερο» ισχύει πάντα στα γραφήματα.
- Παραπλανητικοί άξονες: Κομμένοι άξονες Y που μεγεθύνουν μικρές διαφορές, ή διπλοί άξονες Y με ασυσχέτιστες κλίμακες.
- Απουσία πλαισίου: Γράφημα χωρίς τίτλο, ετικέτες αξόνων, ή μονάδες μέτρησης — είναι σαν πρόταση χωρίς ρήμα.
Πρακτικό Παράδειγμα: Ανάλυση & Οπτικοποίηση Dataset
Ωραία, ώρα να δέσουμε όλα τα παραπάνω σε ένα πλήρες παράδειγμα. Θα φορτώσουμε ένα dataset, θα δημιουργήσουμε πολλαπλά γραφήματα που λένε μια ιστορία, και θα τα αποθηκεύσουμε σε αρχεία. Χρησιμοποιούμε τα ενσωματωμένα datasets του Seaborn για να μπορείτε να αναπαράγετε τα αποτελέσματα εύκολα.
# === ΠΛΗΡΕΣ ΠΑΡΑΔΕΙΓΜΑ: Ανάλυση Αεροπορικών Πτήσεων ===
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import seaborn as sns
import pandas as pd
import numpy as np
# Φόρτωση δεδομένων
flights = sns.load_dataset('flights')
print(flights.head())
print(f"\nΜέγεθος: {flights.shape}")
print(f"Στήλες: {flights.columns.tolist()}")
print(f"Χρονική περίοδος: {flights['year'].min()} - {flights['year'].max()}")
# Προετοιμασία δεδομένων
# Δημιουργία pivot table για heatmap
flights_pivot = flights.pivot(index='month', columns='year',
values='passengers')
# Υπολογισμός ετήσιων στατιστικών
yearly_stats = flights.groupby('year')['passengers'].agg(
['mean', 'std', 'min', 'max']
).reset_index()
yearly_stats.columns = ['Έτος', 'Μέσος', 'Τυπ_Απόκλιση', 'Ελάχιστο', 'Μέγιστο']
# Υπολογισμός ετήσιας ποσοστιαίας μεταβολής
yearly_stats['Μεταβολή_%'] = yearly_stats['Μέσος'].pct_change() * 100
print(yearly_stats)
# === ΔΗΜΙΟΥΡΓΙΑ DASHBOARD ===
fig = plt.figure(figsize=(18, 14))
gs = GridSpec(3, 3, figure=fig, hspace=0.35, wspace=0.3)
# Κεντρικό θέμα
fig.suptitle('Ανάλυση Αεροπορικών Επιβατών (1949-1960)',
fontsize=18, fontweight='bold', y=0.98)
# --- 1. Γράφημα Τάσης (πάνω αριστερά, 2 στήλες) ---
ax1 = fig.add_subplot(gs[0, :2])
for year in flights['year'].unique():
subset = flights[flights['year'] == year]
alpha = 0.3 + 0.7 * (year - 1949) / 11 # Πιο σκοτεινό = πιο πρόσφατο
ax1.plot(subset['month'], subset['passengers'],
alpha=alpha, linewidth=1.5, color='steelblue')
# Επισήμανση πρώτου και τελευταίου έτους
first_year = flights[flights['year'] == 1949]
last_year = flights[flights['year'] == 1960]
ax1.plot(first_year['month'], first_year['passengers'],
'o-', color='#FF6B6B', linewidth=2.5, label='1949', markersize=5)
ax1.plot(last_year['month'], last_year['passengers'],
's-', color='#2196F3', linewidth=2.5, label='1960', markersize=5)
ax1.set_title('Εποχικότητα Επιβατών ανά Έτος', fontsize=13)
ax1.set_ylabel('Επιβάτες (χιλ.)')
ax1.legend(loc='upper left')
ax1.grid(True, alpha=0.2)
# --- 2. Ετήσια Μέση Τιμή (πάνω δεξιά) ---
ax2 = fig.add_subplot(gs[0, 2])
colors = ['#4CAF50' if x > 0 else '#F44336'
for x in yearly_stats['Μεταβολή_%'].fillna(0)]
ax2.bar(yearly_stats['Έτος'], yearly_stats['Μέσος'],
color='steelblue', edgecolor='white', alpha=0.8)
ax2.set_title('Μέσος Αριθμός Επιβατών/Μήνα', fontsize=13)
ax2.set_ylabel('Επιβάτες')
ax2.tick_params(axis='x', rotation=45)
# --- 3. Heatmap (μεσαία σειρά, πλήρες πλάτος) ---
ax3 = fig.add_subplot(gs[1, :])
sns.heatmap(flights_pivot, cmap='YlOrRd', annot=True, fmt='d',
linewidths=0.5, ax=ax3,
cbar_kws={'label': 'Αριθμός Επιβατών (χιλ.)'})
ax3.set_title('Heatmap: Επιβάτες ανά Μήνα & Έτος', fontsize=13)
ax3.set_ylabel('Μήνας')
ax3.set_xlabel('Έτος')
# --- 4. Box Plot εποχικότητας (κάτω αριστερά) ---
ax4 = fig.add_subplot(gs[2, 0])
sns.boxplot(data=flights, x='month', y='passengers',
palette='coolwarm', ax=ax4)
ax4.set_title('Κατανομή ανά Μήνα', fontsize=13)
ax4.set_xlabel('')
ax4.tick_params(axis='x', rotation=90)
# --- 5. Ετήσια αύξηση (κάτω κέντρο) ---
ax5 = fig.add_subplot(gs[2, 1])
valid_change = yearly_stats.dropna(subset=['Μεταβολή_%'])
colors_bar = ['#4CAF50' if x > 0 else '#F44336'
for x in valid_change['Μεταβολή_%']]
ax5.bar(valid_change['Έτος'], valid_change['Μεταβολή_%'],
color=colors_bar, edgecolor='white')
ax5.set_title('Ετήσια Ποσοστιαία Μεταβολή', fontsize=13)
ax5.set_ylabel('Μεταβολή (%)')
ax5.axhline(y=0, color='black', linewidth=0.8)
ax5.tick_params(axis='x', rotation=45)
# --- 6. KDE Κατανομή (κάτω δεξιά) ---
ax6 = fig.add_subplot(gs[2, 2])
for year in [1949, 1954, 1960]:
subset = flights[flights['year'] == year]
sns.kdeplot(subset['passengers'], label=str(year),
fill=True, alpha=0.3, ax=ax6)
ax6.set_title('Εξέλιξη Κατανομής', fontsize=13)
ax6.set_xlabel('Επιβάτες')
ax6.legend()
plt.tight_layout()
plt.show()
# === ΑΠΟΘΗΚΕΥΣΗ ΓΡΑΦΗΜΑΤΩΝ ===
# Αποθήκευση σε πολλαπλές μορφές
fig.savefig('flights_dashboard.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
fig.savefig('flights_dashboard.pdf', bbox_inches='tight')
fig.savefig('flights_dashboard.svg', bbox_inches='tight')
print("Τα γραφήματα αποθηκεύτηκαν σε PNG, PDF και SVG.")
# Αποθήκευση μεμονωμένου γραφήματος σε υψηλή ανάλυση
fig_single, ax_single = plt.subplots(figsize=(10, 6))
sns.heatmap(flights_pivot, cmap='YlOrRd', annot=True, fmt='d',
linewidths=0.5, ax=ax_single)
ax_single.set_title('Heatmap Πτήσεων', fontsize=14)
fig_single.savefig('flights_heatmap.png', dpi=300, bbox_inches='tight')
plt.close(fig_single) # Κλείσιμο χωρίς εμφάνιση
print("Ολοκληρώθηκε η αποθήκευση.")
Αυτό το dashboard δείχνει πώς μπορούμε να συνδυάσουμε Matplotlib και Seaborn σε μια ενιαία, συνεκτική παρουσίαση. Κάθε υπο-γράφημα απαντά σε μια διαφορετική ερώτηση: το γράφημα γραμμών αποκαλύπτει την εποχικότητα, το heatmap δείχνει μοτίβα στον χρόνο, τα box plots φωτίζουν τη μεταβλητότητα ανά μήνα, και τα KDE plots δείχνουν πώς μετατοπίζεται η κατανομή μέσα σε μια δεκαετία.
Δύο πρακτικές λεπτομέρειες που αξίζει να θυμάστε: χρησιμοποιούμε bbox_inches='tight' κατά την αποθήκευση, ώστε να μην κόβονται ετικέτες ή τίτλοι. Και η παράμετρος dpi=300 εξασφαλίζει αρκετή ανάλυση για εκτύπωση ή παρουσίαση.
Διαδραστική Οπτικοποίηση: Πέρα από τη Matplotlib
Η Matplotlib και το Seaborn δημιουργούν στατικά γραφήματα — εξαιρετικά για αναφορές, δημοσιεύσεις και dashboards σε PDF. Αλλά τι γίνεται όταν χρειάζεστε διαδραστικότητα; Εδώ μπαίνουν στο παιχνίδι τρεις εναλλακτικές βιβλιοθήκες.
Plotly: Διαδραστικά Γραφήματα με Ελάχιστο Κώδικα
Το Plotly είναι ίσως η πιο δημοφιλής επιλογή για διαδραστικά γραφήματα στην Python. Zoom, pan, tooltips — όλα «out of the box». Λειτουργεί τέλεια σε Jupyter notebooks, web εφαρμογές (μέσω Dash), και εξάγεται απευθείας σε HTML:
import plotly.express as px
# Διαδραστικό scatter plot
fig = px.scatter(flights, x='year', y='passengers',
color='month', size='passengers',
title='Αεροπορικοί Επιβάτες (1949-1960)',
labels={'year': 'Έτος', 'passengers': 'Επιβάτες',
'month': 'Μήνας'},
template='plotly_white')
fig.show()
# Διαδραστικό animated bar chart
fig_anim = px.bar(flights, x='month', y='passengers',
animation_frame='year',
color='passengers',
color_continuous_scale='Viridis',
title='Εξέλιξη Επιβατών ανά Μήνα')
fig_anim.update_layout(yaxis_range=[0, 700])
fig_anim.show()
# Εξαγωγή σε HTML
fig.write_html('flights_interactive.html')
Bokeh: Web Dashboards και Server Applications
Το Bokeh ξεχωρίζει στη δημιουργία web-based dashboards με Python backend. Αν χρειάζεστε ένα dashboard που ανανεώνεται σε πραγματικό χρόνο ή αντιδρά σε εισόδους χρήστη, το Bokeh (σε συνδυασμό με τον Bokeh Server) αξίζει σοβαρά να το εξετάσετε:
from bokeh.plotting import figure, show, output_notebook
from bokeh.models import HoverTool
output_notebook() # Για εμφάνιση σε Jupyter
# Δημιουργία γραφήματος Bokeh
p = figure(title="Αεροπορικοί Επιβάτες 1960",
x_axis_label='Μήνας', y_axis_label='Επιβάτες',
width=700, height=400)
data_1960 = flights[flights['year'] == 1960]
p.line(range(len(data_1960)), data_1960['passengers'].values,
line_width=2, color='steelblue')
p.circle(range(len(data_1960)), data_1960['passengers'].values,
size=8, color='steelblue', alpha=0.7)
# Προσθήκη hover tooltip
hover = HoverTool(tooltips=[("Μήνας", "@x"), ("Επιβάτες", "@y")])
p.add_tools(hover)
show(p)
Altair: Δηλωτική Γραμματική Γραφημάτων
Το Altair ακολουθεί τη φιλοσοφία του Vega-Lite: περιγράφετε τι θέλετε να δείτε, όχι πώς να το σχεδιάσετε. Είναι ιδανικό για γρήγορη εξερεύνηση δεδομένων — κι ειλικρινά, η σύνταξή του είναι πολύ κομψή:
import altair as alt
# Δηλωτική δημιουργία γραφήματος
chart = alt.Chart(flights).mark_rect().encode(
x='year:O',
y='month:O',
color=alt.Color('passengers:Q', scale=alt.Scale(scheme='yelloworangered')),
tooltip=['year', 'month', 'passengers']
).properties(
title='Heatmap Αεροπορικών Επιβατών',
width=500,
height=300
)
chart.show()
# Σύνθετο γράφημα με επιλογή
brush = alt.selection_interval()
points = alt.Chart(flights).mark_circle().encode(
x='year:O',
y='passengers:Q',
color=alt.condition(brush, 'month:N', alt.value('lightgray'))
).add_params(brush)
bars = alt.Chart(flights).mark_bar().encode(
x='mean(passengers):Q',
y='month:N',
color='month:N'
).transform_filter(brush)
points | bars # Σύνθεση δύο γραφημάτων
Πότε να Χρησιμοποιήσετε Τι
Η επιλογή εξαρτάται αποκλειστικά από τη χρήση:
- Matplotlib + Seaborn: Στατικά γραφήματα για αναφορές, δημοσιεύσεις, εκτυπώσεις. Η πιο ώριμη και πλήρης λύση. Εξαιρετική για PDF/SVG.
- Plotly: Διαδραστικά γραφήματα σε notebooks ή web εφαρμογές. Εύκολο στη χρήση, πλούσια tooltips, εξαγωγή σε HTML. Ιδανικό για Dash dashboards.
- Bokeh: Server-side dashboards με real-time ενημέρωση. Καλύτερη ενσωμάτωση με Python backend. Κατάλληλο για streaming δεδομένων.
- Altair: Γρήγορη εξερεύνηση και δηλωτική σύνταξη. Εξαιρετικό αν θέλετε γρήγορα αποτελέσματα χωρίς πολύ boilerplate.
Η δική μου πρόταση; Ξεκινήστε με Matplotlib και Seaborn — είναι τα θεμέλια. Μόλις νιώσετε άνετα, δοκιμάστε και Plotly για διαδραστικότητα. Η γνώση Matplotlib θα σας βοηθήσει σε κάθε άλλη βιβλιοθήκη, γιατί οι βασικές αρχές παραμένουν ίδιες.
Ενσωμάτωση με Pandas
Κάτι που αξίζει να αναφέρουμε: τα pandas DataFrames έχουν ενσωματωμένες δυνατότητες οπτικοποίησης μέσω της μεθόδου .plot(), η οποία χρησιμοποιεί εσωτερικά τη Matplotlib. Αυτό σημαίνει ότι μπορείτε να δημιουργήσετε γρήγορα γραφήματα χωρίς να εισάγετε καν τη Matplotlib ρητά.
Πολύ βολικό για γρήγορες ματιές στα δεδομένα.
# Pandas ενσωματωμένα γραφήματα
df_sales = pd.DataFrame({
'Μήνας': pd.date_range('2025-01', periods=12, freq='ME'),
'Πωλήσεις': [120, 135, 148, 162, 175, 158, 190, 205, 195, 180, 210, 245],
'Κόστος': [80, 85, 92, 98, 105, 100, 115, 125, 118, 110, 128, 148],
'Κέρδος': [40, 50, 56, 64, 70, 58, 75, 80, 77, 70, 82, 97]
})
df_sales = df_sales.set_index('Μήνας')
# Γράφημα γραμμής απευθείας από DataFrame
ax = df_sales.plot(figsize=(10, 5), marker='o',
title='Οικονομικά Αποτελέσματα 2025')
ax.set_ylabel('Ποσό (K€)')
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# Stacked bar chart
df_sales[['Κόστος', 'Κέρδος']].plot(kind='bar', stacked=True,
figsize=(10, 5),
color=['#FF7043', '#66BB6A'])
plt.title('Ανάλυση Εσόδων: Κόστος vs Κέρδος')
plt.ylabel('Ποσό (K€)')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# Ιστόγραμμα
df_sales['Πωλήσεις'].plot(kind='hist', bins=8, figsize=(8, 4),
color='steelblue', edgecolor='white',
title='Κατανομή Μηνιαίων Πωλήσεων')
plt.xlabel('Πωλήσεις (K€)')
plt.tight_layout()
plt.show()
Η μέθοδος .plot() υποστηρίζει kind='line', 'bar', 'barh', 'hist', 'box', 'kde', 'area', 'scatter', 'hexbin', και 'pie'. Σε συνδυασμό με το pandas 3.0 (που φέρνει βελτιωμένη απόδοση και νέα σύνταξη), η ενσωματωμένη οπτικοποίηση είναι ιδανική για γρήγορη εξερεύνηση κατά τον καθαρισμό δεδομένων — ακριβώς πριν περάσετε σε πιο σύνθετα γραφήματα με Seaborn.
# Χρήσιμο μοτίβο: Γρήγορη εξερεύνηση κατά τον καθαρισμό δεδομένων
def quick_explore(df, numeric_col, cat_col=None):
"""Γρήγορη οπτικοποίηση μιας μεταβλητής κατά τον καθαρισμό."""
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# 1. Κατανομή
df[numeric_col].plot(kind='hist', bins=20, ax=axes[0],
color='steelblue', edgecolor='white')
axes[0].set_title(f'Κατανομή: {numeric_col}')
axes[0].axvline(df[numeric_col].mean(), color='red',
linestyle='--', label='Μέσος')
axes[0].legend()
# 2. Box plot (ανίχνευση outliers)
df[numeric_col].plot(kind='box', ax=axes[1])
axes[1].set_title(f'Box Plot: {numeric_col}')
# 3. Ανά κατηγορία (αν υπάρχει)
if cat_col and cat_col in df.columns:
df.groupby(cat_col)[numeric_col].mean().plot(
kind='barh', ax=axes[2], color='teal')
axes[2].set_title(f'Μέσος {numeric_col} ανά {cat_col}')
else:
df[numeric_col].plot(ax=axes[2])
axes[2].set_title(f'Τιμές: {numeric_col}')
plt.tight_layout()
plt.show()
# Χρήση
# quick_explore(df, 'salary', 'department')
Συμπέρασμα
Η οπτικοποίηση δεδομένων στην Python είναι ένα ευρύ πεδίο, αλλά η βασική φιλοσοφία είναι απλή: κάθε γράφημα πρέπει να απαντά σε μια ερώτηση. Δεν φτιάχνουμε γραφήματα για να εντυπωσιάσουμε — τα φτιάχνουμε για να κατανοήσουμε.
Ας ανακεφαλαιώσουμε τα βασικά σημεία:
- Matplotlib είναι τα θεμέλια. Η OOP διεπαφή (
fig, ax = plt.subplots()) είναι προτιμότερη για παραγωγικό κώδικα. ΗGridSpecδίνει πλήρη έλεγχο στη διάταξη. - Seaborn προσθέτει στατιστική νοημοσύνη και κομψότητα. Δουλεύει τέλεια με pandas DataFrames. Η νέα
so.Plotδιεπαφή αντιπροσωπεύει το μέλλον της δηλωτικής οπτικοποίησης. - Matplotlib 3.10 φέρνει προσβάσιμα χρώματα (
petroff10), νέους colormaps, και σημαντικές βελτιώσεις απόδοσης. - Βέλτιστες πρακτικές: Επιλέξτε τον σωστό τύπο γραφήματος, χρησιμοποιήστε αντιληπτικά ομοιόμορφους colormaps, φροντίστε την προσβασιμότητα, και πάντα βάζετε ετικέτες και πλαίσιο.
- Διαδραστικές βιβλιοθήκες: Plotly, Bokeh και Altair συμπληρώνουν τη Matplotlib για web εφαρμογές και εξερεύνηση δεδομένων.
Η πορεία από τα ακατέργαστα δεδομένα στη γνώση ακολουθεί πάντα το ίδιο μονοπάτι: καθαρισμός (που καλύψαμε στον οδηγό μας για τον καθαρισμό δεδομένων), διαχείριση (με τις νέες δυνατότητες του pandas 3.0), και οπτικοποίηση (αυτός ο οδηγός). Τώρα έχετε και τα τρία εργαλεία.
Ξεκινήστε με κάτι απλό — ένα ιστόγραμμα, ένα scatter plot — και σταδιακά χτίστε πιο σύνθετα γραφήματα καθώς εξοικειώνεστε. Η σταθερή πρακτική είναι πάντα πιο αποτελεσματική από τη θεωρητική κατανόηση. Πιάστε ένα dataset, ανοίξτε ένα notebook, και αρχίστε να πειραματίζεστε. Τα δεδομένα σας περιμένουν να τα δείτε.