Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zigzag or wavy lines in matplotlib

Is there an easy way to draw a zigzag or wavy line in matplotlib?

I'm aware of the different line styles (http://matplotlib.org/examples/lines_bars_and_markers/line_styles_reference.html), and I'm of course aware that instead of plotting

plt.figure(); plt.plot(n.linspace(0.7,1.42,100),[0.7]*100)

I could plot

plt.figure(); plt.plot(n.linspace(0.7,1.42,100),[0.69,0.71]*50)

for a zigzag-line, but I was wondering whether there was a more straightforward way?

like image 748
mzzx Avatar asked Nov 14 '15 09:11

mzzx


People also ask

Is PLT show () blocking?

show() and plt. draw() are unnecessary and / or blocking in one way or the other.


2 Answers

Yes there is, but it comes with a little bit of fallout. The easiest way is to use the xkcd mode in matplotlib.

import numpy as np
import matplotlib.pyplot as plt

plt.xkcd()
plt.figure()
plt.plot(np.linspace(0.7,1.42,100),[0.7]*100)
plt.show()

Which gives you the following: enter image description here

If you take a look at the code used to achieve this you will find that the xkcd function makes some changes to the rcParams dictionary. Most notably the entry rcParams['path.sketch'] = (scale, length, randomness) which is a path effect that is able to simulate a hand drawn look. The default parameters used by xkcd style are:

# explanation from the docstring of the xkcd function
scale = 1  # amplitude of the wiggle
length = 100  # length of the wiggle along the line
randomness = 2  # scale factor for shrinking and expanding the length

You can change the entries in the rcParams dictionary if you import it from the matplotlib package. In the following example I increased the randomness value from 2 to 100:

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

rcParams['path.sketch'] = (1, 100, 100)
plt.plot(np.linspace(0.7,1.42,100),[0.7]*100)
plt.show()

Which will result in the following plot:

enter image description here

As you can see, more jiggling and the font used for the ticks is still 'normal'. However, the style is also used to draw the axes and so far I have not found a way around that. Two workarounds could be:

  1. Work without drawn borders/ spines.
  2. Plot spines and line independently (hard and annoying to automize).
  3. Dig through the documentation of matplotlib and path styles and find out if there is a way to set path styles only for a subset of drawn lines.

Option 1 can be achieved like this:

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

rcParams['path.sketch'] = (10, 10, 100)
fig = plt.plot(np.linspace(0.7,1.42,100),[0.7]*100)

for pos, spine in fig[0].axes.spines.items():
    spine.set_visible(False)
plt.show()

enter image description here

Which, in my opinion look quite ok. borders around plots are highly overrated anyways.

Edit: Less Chaos

To get an evenly waved line, set the randomness parameter to 1 and pick small values for amplitude and length:

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

rcParams['path.sketch'] = (3, 10, 1)
fig = plt.plot(np.linspace(0.7,1.42,100),[0.7]*100)

for pos, spine in fig[0].axes.spines.items():
    spine.set_visible(False)
plt.show()

enter image description here

Bonus image: More Chaos

rcParams['path.sketch'] = (100, 1, 100)

enter image description here

like image 132
m00am Avatar answered Nov 10 '22 16:11

m00am


You can apply the change in rcParams['path.sketch'] dictionary only to selected curves using with.

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# prepare some fancy data
x = np.linspace(0,5,200)
y_0 = 10*x**0.2-x**1.5
y_1 = 20*np.sin(x)
y_2 = x**2

# prepare figure and axis
fig, ax = plt.subplots(nrows=1, ncols = 1, figsize = (5,3), dpi = 128)

# plot with some normal style
ax.plot(x, y_0, color = 'gray', ls='-.', lw = 2, label = 'normal style')

# now plot the wavy-like style!!!!
with mpl.rc_context({'path.sketch': (5, 15, 1)}):
    ax.plot(x, y_1, color = 'blue', label = 'wavy style!')

# again plot with some different normal style
ax.plot(x, y_2, color = 'orange', ls = '-', lw = 3, label = 'again normal style')

ax.legend(loc='best') # turn on legend with automatic best location
plt.show()

Matplotlib wavy zigzag style to selected curve

like image 1
Aleksander_B Avatar answered Nov 10 '22 15:11

Aleksander_B