Skip to content

Instantly share code, notes, and snippets.

@FRidh
Last active January 17, 2022 15:42
Show Gist options
  • Save FRidh/17fd13f47c8d03e1055b7ef142311429 to your computer and use it in GitHub Desktop.
Save FRidh/17fd13f47c8d03e1055b7ef142311429 to your computer and use it in GitHub Desktop.
# # Python package set in Nixpkgs over time
#
# This gist is a Nix expression and generates a figure showing the size
# of the Python package set from September 2015 until now.
#
# To build the figure:
#
# nix-build
let
nixpkgs = (import (fetchTarball "channel:nixos-19.03") {});
inherit (nixpkgs) lib;
# Channels for which we compute the size of the Python package set.
channels = [
"channel:nixos-15.09"
"channel:nixos-16.03"
"channel:nixos-16.09"
"channel:nixos-17.03"
"channel:nixos-17.09"
"channel:nixos-18.03"
"channel:nixos-18.09"
"channel:nixos-19.03"
"channel:nixos-19.09"
"channel:nixos-20.03"
"channel:nixos-20.09"
"channel:nixos-21.05"
"channel:nixos-21.11"
# "channel:nixos-unstable"
];
# Package sets we're interested in.
attrNames = [
"python2Packages"
"python3Packages"
];
# Merge a list of keys and a list of values into a set.
zipListsToAttrs = keys: values: lib.listToAttrs (lib.zipListsWith (name: value: { inherit name value; }) keys values);
# Map a function to a list of values producing a set where the keys are the input values.
mapListToAttrs = f: values: zipListsToAttrs values (map f values);
# Collect data per channel.
collectForChannel = channel: let
pkgs = import (fetchTarball channel) {};
in mapListToAttrs (collectForAttrName pkgs) attrNames;
# Per channel and package set, compute the amount of packages and record what
# version of the interpreter is used.
collectForAttrName = pkgs: attr: {
packages = npackages pkgs.${attr};
version = pkgs.${attr}.python.pythonVersion;
};
# Compute amount of packages in a set. We have to check whether the attributes
# indeed are derivations.
npackages = set: let
filter = key: value: let
result = builtins.tryEval (lib.isDerivation value);
in result.success && result.value != false;
pkgs = lib.attrNames (lib.filterAttrs filter set);
in lib.length pkgs;
# Resulting data set
result = mapListToAttrs collectForChannel channels;
# Write to JSON file
data = builtins.toFile "data.json" (builtins.toJSON result);
# Script to generate a plot using pandas and matplotlib
script = nixpkgs.writers.writePython3 "script" {
libraries = with nixpkgs.python3.pkgs; [ pandas matplotlib ];
} ''
import json
import pandas as pd
import os
import matplotlib.pyplot as plt
with open("${data}") as fin:
result = json.load(fin)
python2 = pd.Series({channel: value["python2Packages"]["packages"] for channel, value in result.items()})
python3 = pd.Series({channel: value["python3Packages"]["packages"] for channel, value in result.items()})
data = pd.DataFrame({"python2": python2, "python3": python3})
ax = data.plot.bar()
fig = ax.get_figure()
fig.tight_layout()
fig.savefig(os.environ["out"])
'';
in derivation {
name = "figure.png";
system = builtins.currentSystem;
builder = script;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment