I noticed in doing some line plots that Matplotlib exhibits strange behaviour (using Python 3.7 and the default TKAgg backend). I've created a program plotting lines of various widths to show the problem. The program creates a bunch of financial looking data and then runs through a loop showing line plots of various linewidths. At the beginning of each loop it asks the user to input the linewidth they would like to see. Just enter 0 to end the program.
import numpy as np
import matplotlib as mpl
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
# Initialize prices and arrays
initial_price = 35.24
quart_hour_prices = np.empty(32) # 32 15 min periods per days
day_prices = np.empty([100,2]) # 100 days [high,low]
quart_hour_prices[0] = initial_price
# Create Data
for day in range(100):
for t in range(1, 32):
quart_hour_prices[t] = quart_hour_prices[t-1] + np.random.normal(0, .2) # 0.2 stand dev in 15 min
day_prices[day,0] = quart_hour_prices.max()
day_prices[day,1] = quart_hour_prices.min()
quart_hour_prices[0] = quart_hour_prices[31]
# Setup Plot
fig, ax = plt.subplots()
# Loop through plots of various linewidths
while True:
lw = float(input("Enter linewidth:")) # input linewidth
if lw == 0: # enter 0 to exit program
exit()
plt.cla() # clear plot before adding new lines
plt.title("Linewidth is: " + str(round(lw,2)) + " points")
# loop through data to create lines on plot
for d in range(100):
high = day_prices[d,1]
low = day_prices[d,0]
hl_bar = Line2D(xdata=(d, d), ydata=(high, low), color='k', linewidth=lw, antialiased=False)
ax.add_line(hl_bar)
ax.autoscale_view()
plt.show(block=False)
Matplotlib defines linewidths in points and its default is to have 72ppi. It also uses a default of 100dpi. So this means each point of linewidth takes up .72 dots or pixels. Thus I would expect to see linewidths less than 0.72 to be one pixel wide, those from 0.72 - 1.44 to be two pixels wide, and so on. But this is not what was observed.
A 0.72 linewidth did indeed give me a line that was one pixel wide. And then when the linewidth is increased to 0.73 the line gets thicker as expected. But it is now three pixels wide, instead of the two I expected.


For linewidths less than 0.72 the plot remains the same all the way down to 0.36. But then when I enter a linewidth of 0.35 or less, the line suddenly gets thicker (2 pixels wide), as shown by the graph below. How can the line get thicker if I reduce the linewidth? This was very unexpected.


Continuing the same testing process for greater linewidths, the plot of the 0.73 linewidth remains the same all the way up until a width of 1.07. But then at 1.08 the linewidth mysteriously gets thinner (2 pixels wide) being the same as the 0.35 and below plots. How can the line get thinner if I increase the linewidth? This was also very unexpected.


This strange behavior continues with greater linewidths. Feel free to use the above code to try it for yourself. Here is a table to summarize the results :
Points Linewidth in pixels 0.01 - 0.35 2 0.36 - 0.72 1 0.73 - 1.07 3 1.08 - 1.44 2 1.45 - 1.79 4 1.80 - 2.16 3 2.17 - 2.51 5 2.52 - 2.88 4
The pattern is something like 1 step back, 2 steps forward. Does anyone know why Matplotlib produces these results?
The practical purpose behind this question is that I am trying to produce an algorithm to vary the linewidth depending upon the density of the data in the plot. But this is very difficult to do when the line thicknesses are jumping around in such a strange fashion.