Simple way to plot multi-color line in matplotlib

There are multiple ways of plotting a multi-color line in matplotlib. A special property of the plot command allowing plotting multiple datasets in columns of 2D arrays makes it possible to do this with a single plot command using the cycler for the colors. Here are a sample code segment for this.

Generate sample data

import numpy as np
import matplotlib.pyplot as plt
from cycler import cycler

x = np.linspace(-np.pi,np.pi,9)
y = np.sin(x)
rng = np.random.default_rng(123)
c = rng.uniform(size=(len(x),3))

plt.scatter(x,y,c=c)
plt.show()

Quick plotting with line colors

plt.gca().set_prop_cycle(cycler('color',c[:-1]))
plt.plot(np.c_[x[:-1],x[1:]].T,np.c_[y[:-1],y[1:]].T)
plt.show()

More careful plotting with point colors

y_ = (y[:-1]+y[1:])/2
x_ = (x[:-1]+x[1:])/2

plt.gca().set_prop_cycle(cycler('color',c[:-1]))
plt.plot(np.c_[x[:-1],x_].T,np.c_[y[:-1],y_].T)
plt.gca().set_prop_cycle(cycler('color',c[1:]))
plt.plot(np.c_[x_,x[1:]].T,np.c_[y_,y[1:]].T)
plt.show()

Walrus operator can inline a block of code into one-liner

Walrus operator, or assignment expression, was introduced into Python at version 3.8. This saves some additional line of assignment in storing-and-checking scenario following evaluations.

However, it also brings the containers data types, such as a list, a step closer to the Turing completeness. Following is a piece of real code:

[d:=get_scans(fn),b:=d[0],c:=d[1],c[np.isin(b,bs)][np.argsort(b)]][-1]

Or, in a more structured format:

[
    d:=get_scans(fn),
    b:=d[0],
    c:=d[1],
    c[np.isin(b,bs)][np.argsort(b)]
][-1]

This performs some additional processing from the result returned by get_scans(fn) and turn the whole thing into a value by extracting the last element of the list. One application of this kind of composite expressions is the possibility of replacing traditional loops with list comprehension. For example, without assignment expressions, we need a loop to collect the data:

r = []
for fn in fns:
    [b,c] = get_scans(fn)[:2]
    r.append(c[np.isin(b,bs)][np.argsort(b)])
r = np.array(r)

Using the walrus operator, we can do it in “one-line” (which is broken down to several lines for clarity):

r = np.array([[
    d:=get_scans(fn),b:=d[0],c:=d[1],
    c[np.isin(b,bs)][np.argsort(b)]
][-1] for fn in fns])

Some may consider this is an abuse of the container types of Python. But, as long as it is used with care, it can help to make elegant code without hindering readability.

Default values of GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER

From the documentation available at https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexParameter.xhtml, the default or initial values are:

GL_TEXTURE_MIN_FILTER = GL_NEAREST_MIPMAP_LINEAR
GL_TEXTURE_MAG_FILTER = GL_LINEAR

This makes glGenerateMipmap necessary after glTexImage2D. Otherwise, the texture rendering will not work properly.

Saving from pickle.dumps to h5py

Saving a chunk of pickled data to a h5py dataset with following code result in “ValueError: VLEN strings do not support embedded NULLs”.

a = [1,2,3,4,5]
with h5py.File('test.h5','a') as f:
	f['a'] = pickle.dumps(a)

This can be worked around with, e.g., “np.string_”:

a = [1,2,3,4,5]
with h5py.File('test.h5','a') as f:
	f['a'] = np.string_(pickle.dumps(a))

To load it back:

with h5py.File('test.h5','r') as f:
	a = pickle.loads(f['a'][()])

I am not aware if there is any problem with this approach.

Bash command line menu system

For trained users, command-line interface of shells, such as BASH, is very convenient for crafting up complex actions that are much more cumbersome to do in GUI. However, some action may require a long line of command that requires looking up documentation to construct. One would find themself using “history” to look up a past invocation for copying to the current line of command. It is thus useful to have a command menu system for these reusable command lines available. choice.sh is my solution to this need. The content of the script is as follows:

#!/bin/bash
# Read and list lines from "choice.cmd". Allowing user interaction
# through stderr to choose a line and pass it back to stdout so it
# can be "eval"ed by the BASH

mapfile -u 4 -t 4<${BASH_SOURCE[0]%\.sh}.cmd

echo Run command: >&2
for ((i=0;i<${#MAPFILE[@]};i++));do
	printf "%4s: %s\n" "$((i+1))" "${MAPFILE[$i]}" >&2
done
printf "Choice: " >&2
read i
re='^[1-9][0-9]*$'
if [[ $i =~ $re ]] && [[ $((i-1)) -lt ${#MAPFILE[@]} ]]; then
	echo ${MAPFILE[$((i-1))]}
else
	echo "echo Cancelled."
fi

One can place file in, say, ~/lib, and add an alias, alias c='eval `~/lib/choice.sh`' to the ~/.bashrc. The menu system can then be invoked by typing c, enter on the command line. It will read all lines from the file choice.cmd in the same directory as the script, list them to the terminal screen using stderr, allow the user to make a choice, and pass the line to stdout so it will be evaled by the shell. Example usage is as follows:

cjj@parakeet:~$ c
Run command:
   1: eval "$(/home/cjj/opt/miniconda3/bin/conda shell.bash hook)"
   2: xrandr --output HDMI-1 --mode 1024x768 --scale 1x1 --pos 0x312
   3: xrandr --output HDMI-1 --mode 1024x768 --scale-from 1920x1080 --same-as eDP-1
Choice: 1
(base) cjj@parakeet:~$

Permutation

The following spaghetti prints all permutations of a string (“abcd”). I wrote it as an example to show the benefit of structured programming in my class.

#include <iostream>
using namespace std;
int main()
{
        char c[] = "abcd\n";
        int size = sizeof(c) - 2;
        int n[size + 1];
        n[size] = 1;
        int idx = size;
        char t;
new_round:
        for (int i = 0; i < idx; i ++) n[i] = i + 1;
        cout << c;
start_shift:
        idx = 0;
        t = c[0];
shift_next:
        if (n[idx]) goto shift_done;
        idx ++;
        c[0] = c[idx];
        c[idx] = t;
        t = c[0];
        goto shift_next;
shift_done:
        n[idx] --;
        if (idx == size) return 0;
        if (n[idx] == 0) goto start_shift;
        goto new_round;
}

The structured version is as follows:

#include <iostream>
using namespace std;
int main()
{
        char c[] = "abcd\n";
        int size = sizeof(c) - 2;
        int n[size + 1];
        n[size] = 1;
        int idx = size;
        char t;
        do {
                if (n[idx]) {
                        for (int i = 0; i < idx; i ++) n[i] = i + 1;
                        cout << c;
                }
                idx = 0;
                t = c[0];
                while (n[idx] == 0) {
                        idx ++;
                        c[0] = c[idx];
                        c[idx] = t;
                        t = c[0];
                }
                n[idx] --;
        } while (idx < size);
        return 0;
}

The idea is to rotate a string by n times, where n is the length of the string. While, before each rotation, rotate the n-1 substring at the front n-1 times. And while, before each rotation, rotate the n-2 substring at the front n-2 times. And so on… We can see that this is more elegantly done recursively:

#include <iostream>
using namespace std;
char c[] = "abcd\n";
int size = sizeof(c) - 2;
void rotate(int l)
{
        char ch = c[l - 1];
        for (int i = l - 1; i; i --) c[i] = c[i - 1];
        c[0] = ch;
}
void perm(int l)
{
        if (l == 1) cout << c;
        else for (int i = 0; i < l; i ++) {
                perm(l - 1);
                rotate(l);
        }
}
int main()
{
        perm(size);
        return 0;
}

The above thinking counts on the string to have all distinct chars. When this isn’t the case, a different approach is to consider the lexical order of the permutations. From a given permutation, we simply need to figure out the next in the lexical order until the order is “maximized”. It turns out that this is in the C++ STL. My reimplementation is as follows:

#include <iostream>
using namespace std;
void swap(char & a, char & b)
{
        char c = a;
        a = b;
        b = c;
}
// increase the order of string
bool incr(char * str, size_t len)
{
        size_t i = 1;
        while (i < len && str[i - 1] >= str[i]) i ++;
        if (i == len) return false; // no kink
        // found a kink
        size_t j = i - 1;
        while (j > 0 && str[j - 1] < str[i]) j --; // size kink
        swap(str[i], str[j]); // shave kink
        // reverse rest
        for (i --, j = 0; j < i; i --, j ++) swap(str[i], str[j]);
        return true;
}
int main()
{
        char c[] = "aabbc\n";
        int size = sizeof(c) - 2;
        do cout << c; while (incr(c, size));
}