Skip to content

Instantly share code, notes, and snippets.

@dronir
Last active April 9, 2019 16:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dronir/20ca091ffcd62e78df7016f10b55c99b to your computer and use it in GitHub Desktop.
Save dronir/20ca091ffcd62e78df7016f10b55c99b to your computer and use it in GitHub Desktop.
Sliced histogram plots
import numpy as np
def JDplot(data, ax, N, resolution=None, white=False, alpha=1.0, stagger=0.0, fill_color=None, fg_color=None):
"""Make a sliced histogram plot in the style of Joy Division's album cover.
- `data`, a 1D numpy array containing values.
- `ax`, the matplotlib Axes to draw onto.
- `N`, the number of histogram slices.
- `resolution`, the number of bins. Defaults to `N`.
- `white`, boolean. Sets black-on-white colour scheme instead default.
- `alpha`, controls transparency of filled region
- `stagger`, shift each histogram in the X direction by this amount
- `fill_color`, set the fill color. Defaults to black or white.
- `fg_color`, set the line color. Defaults to white or black.
"""
window = int(len(data) / N)
if resolution is None:
resolution = N
bins = np.linspace(data.min(), data.max(), resolution+1)
X = []
Y = []
for n in range(N):
subdata = data[n*window : (n+1)*window]
y,x = np.histogram(subdata, bins=bins)
X.append(x)
Y.append(y)
vshift = np.median([y.max() for y in Y]) / 6
bg_color = "white" if white else "black"
if fg_color is None:
fg_color = "black" if white else "white"
if fill_color is None:
fill_color = bg_color
thickness = 0.75 if white else 1.5
ax.set_facecolor(bg_color)
for i, (x,y) in enumerate(zip(X, Y)):
delta = x[1] - x[0]
x = x[:-1] + delta/2
ax.plot(x + i*stagger, y + vshift*i, color=fg_color, zorder=N-i, linewidth=thickness)
ax.fill_between(x + i*stagger, vshift*i, y + vshift*i, color=fill_color, alpha=alpha, zorder=N-i)
return ax
# Make some example plots
import matplotlib.pyplot as plt
import numpy as np
from JDplot import JDplot
# Create some data from a normal distribution with changing width
N = 50000
P = 100000
data = np.zeros(N)
for n in range(N):
scale = 1.0 + 0.5 * np.cos(2*np.pi*n/P)
data[n] = np.random.normal(0.0, scale)
# Plot histograms
figA = plt.figure(figsize=(10,6))
axA = figA.add_subplot(211)
JDplot(data, axA, 40, white=False, alpha=0.6)
# For Synthwave look:
# JDplot(data, axA, 40, white=False, alpha=0.4, fill_color="C4", fg_color="C9", stagger=0.25)
# Plot raw data
axB = figA.add_subplot(212)
axB.set_facecolor("black")
axB.scatter(np.arange(len(data)), data, 1, color="white", alpha=0.75)
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment