I want to plot a beautiful bar plot using the data mentioned in the script. Additionally, the x-axis should be logarithmic and there must be gaps between the bars.
I tried the script as below:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
fig = plt.figure()
x = [0.000001,0.00001,0.0001,0.001,0.01,0.1,1.0]
height = [5.3,1.8,8.24,5.8,2.8,3.3,4.2]
width = 0.000001
plt.bar(x, height, width, color='b' )
plt.xscale("log")
plt.savefig('SimpleBar.png')
plt.show()
However, the x-axis values are not plotted as expected.
CodePudding user response:
With a log scale x-axis, you can't set constant widths for the bars. E.g. the first bar would go between 0
and 0.000002
, (0 is at minus infinity on a log scale).
You could use the x-positions for the left edge of the bars, and the next x-position for the right edge:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
x = [0.000001, 0.00001, 0.0001, 0.001, 0.01, 0.1, 1.0]
height = [5.3, 1.8, 8.24, 5.8, 2.8, 3.3, 4.2]
plt.xscale("log")
widths = np.diff(x [x[-1] * 10])
plt.bar(x, height, widths, align='edge', facecolor='dodgerblue', edgecolor='white', lw=2)
plt.show()
If you want to "center" the bars around the original x-values, you need to calculate the start and end positions of each bar in log space. The easiest way to get more spacing between the bars, is to set a thicker white border.
import matplotlib.pyplot as plt
import numpy as np
x = [0.000001, 0.00001, 0.0001, 0.001, 0.01, 0.1, 1.0]
height = [5.3, 1.8, 8.24, 5.8, 2.8, 3.3, 4.2]
plt.xscale("log")
padded_x = [x[0] / 10] x [x[-1] * 10]
centers = [np.sqrt(x0 * x1) for x0, x1 in zip(padded_x[:-1], padded_x[1:])]
widths = np.diff(centers)
plt.bar(centers[:-1], height, widths, align='edge', facecolor='dodgerblue', edgecolor='white', lw=4)
plt.margins(x=0.01)
plt.show()
You can also have a configurable width if you calculate the new left and right positions for each bar:
import matplotlib.pyplot as plt
import numpy as np
x = [0.000001, 0.00001, 0.0001, 0.001, 0.01, 0.1, 1.0]
height = [5.3, 1.8, 8.24, 5.8, 2.8, 3.3, 4.2]
plt.xscale("log")
padded_x = [x[0] / 10] x [x[-1] * 10]
width = 0.3 # 1 for full width, closer to 0 for thinner bars
lefts = [x1 ** (1 - width / 2) * x0 ** (width / 2) for x0, x1 in zip(padded_x[:-2], padded_x[1:-1])]
rights = [x0 ** (1 - width / 2) * x1 ** (width / 2) for x0, x1 in zip(padded_x[1:-1], padded_x[2:])]
widths = [r - l for l, r in zip(lefts, rights)]
plt.bar(lefts, height, widths, align='edge', facecolor='dodgerblue', lw=0)
plt.show()