I am trying to generate a plot and using log to show relative comparison, the plot is correctly shown however, the saved figure doesn't have any plots, only axis.
import matplotlib.pyplot as plt
# Data
y_values = [4.385236951214598, 4.385249349505862, 4.38524255048674, 4.385237751115038, 4.385241350648787]
x_labels = ["Dota", "Youtube", "Exchange", "Fifa", "Uber"]
# Create the plot
fig, ax = plt.subplots(figsize=(10, 6))
ax.bar(x_labels, y_values, color=plt.cm.viridis(range(len(x_labels))))
# Set y-axis to log scale
ax.set_yscale('log')
# Add title and labels
ax.set_title("Contracts vs. Values (Log Scale)")
ax.set_xlabel("Contracts")
ax.set_ylabel("Values")
# Save the plot as a PDF file
fig.savefig('gas-burnt-per-contract.pdf', dpi=300, bbox_inches='tight', transparent=True, pad_inches=0)
# Display the plot
plt.show()
The culprit line is ax.set_yscale('log')
, if i remove this, the plot is shown correctly in the saved figure, but empty when i use it.
Any help would be appreciated.
I believe you've uncovered a matplotlib
bug.
The bug is possibly localised to the savefig
method. Here's what I've tried:
Code as-is
Running your code as-is, I get exactly the behaviour you describe. The following image is show
n...
BUT, as you report, the saved PDF shows no bars within the axes:
Using plt.yscale()
instead of ax.set_yscale()
Using plt.yscale()
(as suggested by this answer instead of ax.set_yscale()
as you have done, makes no difference.
Changing input values
If I change y_values from:
y_values = [
4.385236951214598,
4.385249349505862,
4.38524255048674,
4.385237751115038,
4.385241350648787,
to...
y_values = [
4.385236951214598,
5.385249349505862,
6.38524255048674,
7.385237751115038,
8.385241350648787,
Both the PDF and the "shown" image match up perfectly:
If I change just one of the numbers, by adding 1 to it, I still get matching - and valid - images:
The same is true if I add 0.01 to one of the numbers, but if I reduce the addition to just 0.001, the results go back to being screwy.
Using decimal.Decimal()
I tried converting all the y_values
to Decimal
, and this made no difference.
Checking if problem arises with SVG as with PDF
The fact that PNGs use a raster instead of a vector like PDFs, made me wonder whether it was a vector/raster thing.
But saving to an SVG works perfectly, with shown and saved images matching.
As SVGs are vectors like PDFs, this leads me to think it's not a vector/raster thing after all.
Setting transparent=False
Setting the transparent
kwarg to False
in fig.savefig()
makes no difference.
Increasing or decreasing dpi
Increasing or decreasing dpi when calling fig.savefig()
makes no difference.
Changing the figure's size
Making the figure bigger/smaller and changing its aspect ratio makes no difference.
Changing the bar colour
Changing the colours invoked when calling ax.bar()
makes no difference.
Conclusion
This very inconsistent behaviour leads me to think this is a matplotlib
bug of some kind.
The fact that the problem only seems to arise when the difference between the values shrinks to about 0.001 leads me to think that this may have to do with rounding, but I can't be sure...
My setup
I'm running your code in VSCode, using Python 3.11, matplotlib v3.9.0, on Windows 10.