Download
124 lines 4.5 KiBPythonModified 2025-04-24 raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
import matplotlib.pyplot as plt
import numpy as np
from dataclasses import dataclass
from adjustText import adjust_text

@dataclass
class Language:
    name: str
    readability: float
    performance: float
    convenience: float
    safety: float
    color: str = "blue"

languages = [
    Language("C",           3,     9,     2,     1),
    Language("C++",         1,   9.1,     4,     2),
    Language("Java",        5,     7,     5,     7),
    Language("Lua",        10,     5,     6,     5),
    Language("Python",      9,     4,    10,     5),
    Language("Rust",        4,   9.1,     3,     9),
    Language("Go",        8.7,     8,     8,     8),
    Language("Javascript",  8,     5,     7,     2),
    Language("Tomo",        9,   8.2,     9,   8.5, color="red"),
]

# # Example languages with ratings (0-10 scale)
# languages = [
#     Language("Python", 9.0, 5.0, 6.0, 9.0),
#     Language("C++", 4.0, 9.0, 5.0, 3.0),
#     Language("Rust", 7.5, 8.5, 9.5, 5.0),
#     Language("Java", 6.0, 7.0, 7.5, 6.0),
#     Language("Go", 8.0, 8.0, 7.0, 8.5),
#     Language("JavaScript", 6.5, 6.0, 3.0, 6.0),
#     Language("Haskell", 7.0, 7.0, 8.0, 4.0),
#     Language("C", 3.0, 10.0, 2.0, 7.0),
#     Language("Swift", 8.0, 7.5, 8.0, 7.0),
#     Language("TypeScript", 8.0, 6.0, 7.0, 5.5)
# ]

# Extract attributes for comparison
attributes = ["readability", "performance", "convenience", "safety"]
n_attrs = len(attributes)

# Create a grid of plots
fig, axs = plt.subplots(3, 2, figsize=(12, 12))

# Populate the grid with scatter plots
n = 0
for i, attr1 in enumerate(attributes):
    for j in range(i+1, len(attributes)):
        ax = axs[n % 3, n // 3]
        n += 1
        attr2 = attributes[j]

        # if i == j:
        #     ax.set_visible(False)
        #     continue
        
        # Extract the values for the current attributes
        x = [getattr(lang, attr1) for lang in languages]
        y = [getattr(lang, attr2) for lang in languages]

        # Create scatter plot
        colors = [l.color for l in languages]
        ax.scatter(x, y, s=80, alpha=0.7, c=colors)

        coef = np.polyfit(x,y,1)
        poly1d_fn = np.poly1d(coef) 
        line_xs = [min(x)-0.5, max(x)+0.5]
        ax.plot(line_xs, poly1d_fn(line_xs), color='gray', linestyle='dashed')

        texts = []
        for k, lang in enumerate(languages):
            texts.append(ax.text(x[k], y[k], lang.name, 
                                fontsize=8, color='black',
                                ha='center', va='bottom'))
            
        # # Use adjust_text to avoid overlaps
        # adjust_text(texts, ax=ax, arrowprops=dict(arrowstyle='->', color='gray', lw=1),
        #             expand_points=(1.5,1.5),
        #             force_points=(0.1, 0.1), force_text=(0.5, 0.5))
        adjust_text(texts, 
           ax=ax,  # Specify the current axes
           expand_points=(1.5, 1.5),  # Expand area around points
           expand_text=(1.5, 1.5),    # Expand area around text
           #arrowprops=dict(arrowstyle='->', color='gray', lw=0.5),
           force_points=(0.5, 1.0),   # Stronger repulsion from points
           force_text=(0.5, 0.5),     # Moderate text-to-text repulsion
           only_move={'texts':'xy'},  # Allow movement in both directions
           autoalign=False,           # Don't try to align text
           avoid_self=True,           # Avoid self-collisions
           lim=5)                     # Limit iterations for faster processing
        # adjust_text(texts, ax=ax)

        # # Add language labels
        # for k, lang in enumerate(languages):
        #     ax.annotate(lang.name, (x[k], y[k]), fontsize=8, 
        #                xytext=(5, 5), textcoords='offset points')
        
        # Only add axis labels for the edge plots
        #if i == n_attrs-1:  # Bottom row
        ax.set_xlabel(attr1.replace('_', ' ').capitalize(), fontsize=10)
        #if j == 0:  # Leftmost column
        ax.set_ylabel(attr2.replace('_', ' ').capitalize(), fontsize=10)
            
        # Remove ticks and numbers
        ax.tick_params(axis='both', which='both', bottom=False, top=False, 
                      labelbottom=False, left=False, right=False, labelleft=False)
        
        # Set consistent axis limits
        ax.set_xlim(min(x)-0.5, max(x)+.5)
        ax.set_ylim(min(y)-0.5, max(y)+.5)
        
        # Clean look without grid lines or quadrants
        ax.set_frame_on(True)
        ax.grid(False)

# Adjust spacing between subplots
plt.tight_layout()

# Save the figure
plt.savefig('languages.png', dpi=100)
# plt.show()  # Uncomment to display in interactive environment