Is there any way I can save the plot as .jpg [duplicate] - python-3.x

I am using matplotlib (within pylab) to display figures. And I want to save them in .jpg format. When I simply use the savefig command with jpg extension this returns :
ValueError: Format "jpg" is not supported.
Supported formats: emf, eps, pdf, png, ps, raw, rgba, svg, svgz.
Is there a way to perform this ?

You can save an image as 'png' and use the python imaging library (PIL) to convert this file to 'jpg':
import Image
import matplotlib.pyplot as plt
plt.plot(range(10))
plt.savefig('testplot.png')
Image.open('testplot.png').save('testplot.jpg','JPEG')
The original:
The JPEG image:

To clarify and update #neo useful answer and the original question. A clean solution consists of installing Pillow, which is an updated version of the Python Imaging Library (PIL). This is done using
pip install pillow
Once Pillow is installed, the standard Matplotlib commands
import matplotlib.pyplot as plt
plt.plot([1, 2])
plt.savefig('image.jpg')
will save the figure into a JPEG file and will not generate a ValueError any more.
Contrary to #amillerrhodes answer, as of Matplotlib 3.1, JPEG files are still not supported. If I remove the Pillow package I still receive a ValueError about an unsupported file type.

Just install pillow with pip install pillow and it will work.

I just updated matplotlib to 1.1.0 on my system and it now allows me to save to jpg with savefig.
To upgrade to matplotlib 1.1.0 with pip, use this command:
pip install -U 'http://sourceforge.net/projects/matplotlib/files/matplotlib/matplotlib-1.1.0/matplotlib-1.1.0.tar.gz/download'
EDIT (to respond to comment):
pylab is simply an aggregation of the matplotlib.pyplot and numpy namespaces (as well as a few others) jinto a single namespace.
On my system, pylab is just this:
from matplotlib.pylab import *
import matplotlib.pylab
__doc__ = matplotlib.pylab.__doc__
You can see that pylab is just another namespace in your matplotlib installation. Therefore, it doesn't matter whether or not you import it with pylab or with matplotlib.pyplot.
If you are still running into problem, then I'm guessing the macosx backend doesn't support saving plots to jpg. You could try using a different backend. See here for more information.

Matplotlib can handle directly and transparently jpg if you have installed PIL. You don't need to call it, it will do it by itself. If Python cannot find PIL, it will raise an error.

I'm not sure about all versions of Matplotlib, but in the official documentation for v3.5.0 savfig allows you to pass settings through to the underlying Pillow library which anyway does the image saving. So if you want a jpg with specific compression settings for example:
import matplotlib.pyplot as plt
plt.plot(...) # Plot stuff
plt.savefig('filename.jpg', pil_kwargs={
'quality': 20,
'subsampling': 10
})
This should give you a highly compressed jpg as the output.

Just for completeness, if you also want to control the quality (i.e. compression level) of the saved result, it seems to get a bit more complicated, as directly passing plt.savefig(..., quality=5) does not seem to have an effect on the output size and quality. So, on the one hand, one could either go the way of saving the result as a png first, then reloading it with PIL, then saving it again as a jpeg, using PIL's quality parameter – similar to what is suggested in Yann's answer.
On the other hand, one can avoid this deviation of loading and saving, by using BytesIO (following the answer to this question):
from io import BytesIO
import matplotlib.pyplot as plt
from PIL import Image
buf = BytesIO()
plt.plot(...) # Plot something here
plt.savefig(buf)
Image.open(buf).convert("RGB").save("testplot.jpg", quality=5)

Related

backtesting.py ploting function not working

I'm trying to learn backtesting.py, when I run the following sample code, it pops up these errors, anyone could help? I tried to uninstall the Bokeh package and reinstall an older version, but it doen't work.
BokehDeprecationWarning: Passing lists of formats for DatetimeTickFormatter scales was deprecated in Bokeh 3.0. Configure a single string format for each scale
C:\Users\paul_\AppData\Local\Programs\Python\Python310\lib\site-packages\bokeh\models\formatters.py:399: UserWarning: DatetimeFormatter scales now only accept a single format. Using the first prodvided: '%d %b'
warnings.warn(f"DatetimeFormatter scales now only accept a single format. Using the first prodvided: {fmt[0]!r} ")
BokehDeprecationWarning: Passing lists of formats for DatetimeTickFormatter scales was deprecated in Bokeh 3.0. Configure a single string format for each scale
C:\Users\paul_\AppData\Local\Programs\Python\Python310\lib\site-packages\bokeh\models\formatters.py:399: UserWarning: DatetimeFormatter scales now only accept a single format. Using the first prodvided: '%m/%Y'
warnings.warn(f"DatetimeFormatter scales now only accept a single format. Using the first prodvided: {fmt[0]!r} ")
GridPlot(id='p11925', ...)
import bokeh
import datetime
import pandas_ta as ta
import pandas as pd
from backtesting import Backtest
from backtesting import Strategy
from backtesting.lib import crossover
from backtesting.test import GOOG
class RsiOscillator(Strategy):
upper_bound = 70
lower_bound = 30
rsi_window = 14
# Do as much initial computation as possible
def init(self):
self.rsi = self.I(ta.rsi, pd.Series(self.data.Close), self.rsi_window)
# Step through bars one by one
# Note that multiple buys are a thing here
def next(self):
if crossover(self.rsi, self.upper_bound):
self.position.close()
elif crossover(self.lower_bound, self.rsi):
self.buy()
bt = Backtest(GOOG, RsiOscillator, cash=10_000, commission=.002)
stats = bt.run()
bt.plot()
An issue was opened for this in the GitHub repo:
https://github.com/kernc/backtesting.py/issues/803
A comment in the issue suggests to downgrade bokeh to 2.4.3:
python3 -m pip install bokeh==2.4.3
This worked for me.
I had a similar issue, using Spyder IDE.
Found out I need to call the below for the plot to show for Spyder.
backtesting.set_bokeh_output(notebook=False)
I have update Python to version 3.11 & downgrade bokeh to 2.4.3
This worked for me.
Downgrading Bokeh didn't work for me.
But, after importing backtesting in Jupyter, I needed to do:
backtesting.set_bokeh_output(notebook=False)
The expected plot was then generated in a new interactive browser tab.

Importing sympy and matplotlib.pyplot causes a deprecation warning

This runs fine without any warnings or errors,
from matplotlib import pyplot as plt
plt.plot(range(10))
This,
from matplotlib import pyplot as plt
import sympy
plt.plot(range(10))
Produces,
/home/username/.local/lib/python3.8/site-packages/matplotlib/backends/backend_gtk3.py:327:
DeprecationWarning: Gtk.Window.set_wmclass is deprecated
self.window.set_wmclass("matplotlib", "Matplotlib")
Note that if you import them both but don't call the plot function, you don't get the deprecation warning.
I have no idea what is going on. Googling that warning does not quite find anything related to Sympy. Python is at 3.8.5, Sympy at 1.8 and Matplotlib at 3.4.0.
The message you received is a warning and not an error. The difference being that your code has been executed normally, the message provides extra information that in some point in the future Gtk.Window.set_wmclass will not be available, it's a note to programmers (in this case the matplotlib devs) that they should change their code to use the new way of doing something. If you use a combination of old/new packages you should expect to see these warnings.
You can either ignore/suppress this warning message, or update your packages.
It's recommended that you use a virtual environment to isolate the Python that you use to from the Python that your system uses. It will allow you to use up-to-date versions of packages and you will no longer risk accidentally breaking system utilities. There are many options and since Python ~3.6 there's the venv module included in the standard library.

plt.show() not working in pycharm

I am using pycharm after upgrading my python to python 3.5.
I re-run a standard code that i had in place and had a problem with plt.show()
example:
import matplotlib
import matplotlib.pyplot as plt
plt.plot([1,2,3,4])
plt.show()
The suggestion by DavidG made things worked fine. But this time when I do
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
plt.plot([1,2,3,4])
plt.show()
i get an error saying
/apps/qtrinst/install/python/anaconda/envs/sx_anaconda/lib/python3.5/site-packages/matplotlib/__init__.py:1401: UserWarning: This call to matplotlib.use() has no effect
because the backend has already been chosen;
matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
or matplotlib.backends is imported for the first time.
It didnt get this error before-not sure what happened there.
I think the problem is with your "backend". The documentation has a section entitled "What is a backend?" which will be helpful.
I'm not familiar with WebAgg but I don't think you want to be using it. A more conventional one might be TkAgg which requires Tkinger or Qt4Agg which requires PyQt4. You can switch backends using
import matplotlib
matplotlib.use("TkAgg") # Do this before importing pyplot!
import matplotlib.pyplot as plt
Try using a different Backend. It worked for me when I used QtAgg
PyQt
you will need to install some version of PyQt. At the moment:
pip install PyQt6
Specify the GUI backend
import matplotlib
matplotlib.use("QtAgg")
Try plt.show()
from matplotlib import pyplot as plt
# some code here
plt.show()
This worked flawlessly for me. Hope It worked for you too.

networkx draw graph deprecated message

I am trying to draw a graph networkx using python 3.6 with Jupyter notebook and the network package with anaconda. But the graph is not drawing per the documentation, I am just getting a deprecated message.
CODE:
import networkx as nx
import csv
import matplotlib as plt
G = nx.read_pajek('Hi-tech.net')
nx.draw(G)
MESSAGE:
MatplotlibDeprecationWarning: pyplot.hold is deprecated.
Future behavior will be consistent with the long-time default:
plot commands add elements without first clearing the
Axes and/or Figure.
b = plt.ishold()
Future behavior will be consistent with the long-time default:
plot commands add elements without first clearing the
Axes and/or Figure.
plt.hold(b)
warnings.warn("axes.hold is deprecated, will be removed in 3.0")
To avoid this warning, I just simply replace
nx.draw(G)
by
nx.draw_networkx(G)
My Python is 3.4, Jupyter '1.0.0' and networkx '1.11'.
I was able to get rid of the message by going into the networkx library and simply placing # in front of the lines which produced the error.
I would infer the .hold() function is no longer necessary, nor does it need ot be replaced
I could get nx.draw(G) to work by adding the following line of command:
%matplotlib inline
As error suggest ... I change nx_pylab.py at 611
# if cb.is_numlike(alpha):
if isinstance(alpha,numbers.Number):
I just commented out the line 365 of file __init__.py in Lib\site-packages\matplotlib\cbook which reads
#deprecated('3.0', 'isinstance(..., numbers.Number)')

Graphviz.Source not rendering in Jupyter Notebook

After exporting a .dot file using scikit-learn's handy export_graphviz function.
I am trying to render the dot file using Graphviz into a cell in my Jupyter Notebook:
import graphviz
from IPython.display import display
with open("tree_1.dot") as f:
dot_graph = f.read()
display(graphviz.Source(dot_graph))
However the out[ ] is just an empty cell.
I am using graphviz 0.5 (pip then conda installed), iPython 5.1, and Python 3.5
The dot file looks correct here are the first characters:
digraph Tree {\nnode [shape=box, style="filled", color=
iPython display seems to work for other objects including Matplotlib plots and Pandas dataframes.
I should note the example on Graphviz' site also doesn't work.
It's possible that since you posted this, changes were made so you might want to update your libraries if that's possible.
The versions of relevance here I used are:
Python 2.7.10
IPython 5.1.0
graphviz 0.7.1
If you have a well formed .dot file, you can display it to the jupyter out[.] cell by the following:
import graphviz
with open("tree_1.dot") as f:
dot_graph = f.read()
# remove the display(...)
graphviz.Source(dot_graph)
this solution allows you to insert DOT text directly (without saving it to file first)
# convert a DOT source into graph directly
import graphviz
from IPython.display import display
source= '''\
digraph sample {
A[label="AL"]
B[label="BL"]
C[label="CL"]
A->B
B->C
B->D
D->C
C->A
}
'''
print (source)
gvz=graphviz.Source(source)
# produce PDF
#gvz.view()
print (gvz.source)
display(gvz)
Try to use pydotplus.
import pydotplus
by (1.1) Importing the .dot from outside
pydot_graph = pydotplus.graph_from_dot_file("clf.dot")
or (1.2) Directly using the .export_graphviz output
dt = tree.DecisionTreeClassifier()
dt = clf.fit(x,y)
dt_graphviz = tree.export_graphviz(dt, out_file = None)
pydot_graph = pydotplus.graph_from_dot_data(dt_graphviz)
(2.) and than display the pyplot graph using
from IPython.display import Image
Image(pydot_graph.create_png())
try to reinstall graphviz
conda remove graphviz
conda install python-graphviz
graphviz.Source(dot_graph).view()
graphviz.Source(dot_graph).view()

Resources