Saving Python SymPy figures with a specific resolution/pixel density - python

I am wondering if there is a way to change the pixel density/resolution of sympy plots. For example, let's consider the simple code snippet below:
import sympy as syp
x = syp.Symbol('x')
miles_to_km = x * 1.609344
miles_to_km.evalf()
graph = syp.plot(miles_to_km, show=False)
graph.save('./figures/miles_to_km.png')
graph.show()
Notes:
When I tried using graph.savefig, I got an AttributeError: 'Plot' object has no attribute 'saveimage' I stumbled upon the saveimage method in some online resource, and it sounded like that this was the common approach -- I guess the API changed?
graph.save('./figures/miles_to_km.png', dpi=300) produces a type error: TypeError: save() got an unexpected keyword argument 'dpi'
Using the dpi attribute in plot does not throw any error but doesn't affect the image quality either: graph = syp.plot(miles_to_km, dpi=300, show=False)
I also tried using the matplotlib backend:
plt.figure()
graph = syp.plot(miles_to_km, show=False)
#graph.save('./figures/miles_to_km.png')
plt.savefig('./figures/miles_to_km.png')
graph.show()
where plt = matplotlib.pyplot. However, the canvas is blank. Also relevant info may be that I am running it in an IPython notebook with %matplotlib inline enabled.
I am using SymPy v. 0.7.6
the backend workaround below shows the plot in the IPython notebook, but it also produces a white canvas (as png)
graph = syp.plot(miles_to_km, show=False)
backend = graph.backend(graph)
backend.fig.savefig('ch01_2.png', dpi=300)
backend.show()
EDIT and Solution:
Thanks to Cody Piersall's answer the issue is now resolved. I updated to IPython 4.0 (Jupyter notebook) and plotted it as follows
graph = syp.plot(miles_to_km, show=False)
backend = graph.backend(graph)
backend.process_series()
backend.fig.savefig('miles_to_km.png', dpi=300)
backend.show()

This problem has been fixed, you can now simply use this:
graph = sympy.plot(f, show = False)
graph.save('fig.png')
Unfortunately, it doesn't seem to allow for the selection of a dpi.

Assuming you are using the matplotlib backend, which is the default if you have matplotlib installed, you just have to import matplotlib.pyplot and use pyplot.savefig.
This works because sympy uses matplotlib to do its plotting, and since matplotlib is stateful, it knows which plot you're working with.
Here is your example, but using savefig to save to a png.
import sympy as syp
x = syp.Symbol('x')
miles_to_km = x * 1.609344
miles_to_km.evalf()
graph = syp.plot(miles_to_km, show=False)
# Does not work in IPython Notebook, but works in a script.
import matplotlib.pyplot as plt
plt.savefig('./figures/miles_to_km.png', dpi=300)
If you are in an IPython notebook, the above will not work, but you can still save them with a specified dpi. You just have to be a little tricky about it.
# works in IPython Notebook
backend = graph.backend(graph)
ackend.fig.savefig('300.png', dpi=300)
backend.fig.savefig('20.png', dpi=20)

Related

TwoSlopeNorm in Matplotlib not working as expected

I am trying to create a plot with a diverging colour map which is not symmetric around zero
In this example, the DivergingNorm function is used and produces what I want...
I am using a later version of Matplotlib however (3.5.1) and when I use the suggested code in the link above, I get the following image...
import numpy as np
import matplotlib.pyplot as plt
data = np.random.random((10,10))
data = 10 * (data - 0.8)
fig, ax = plt.subplots()
im = ax.imshow(data, norm=matplotlib.colors.TwoSlopeNorm(0), cmap=plt.cm.seismic, interpolation='none')
fig.colorbar(im)
plt.show()
... which is clearly not right.
Does anyone know how I can reproduce this behaviour from DivergingNorm from older Matplotlib verions? I can't find a solution to this anywhere even though the older behaviour of 'DivergingNorm' is exactly what I want.
I get the same wrong behaviour using this example ---> https://stackoverflow.com/a/69707735/6288682
I should get this...
... but actually get...
Thanks!

Plots not showing in Jupyter notebook

I am trying to create a 2x2 plots for Anscombe data-set
Loading Data-set and separating each class in data-set
import seaborn as sns
import matplotlib.pyplot as plt
anscombe = sns.load_dataset('anscombe')
dataset_1 = anscombe[anscombe['dataset'] == 'I']
dataset_2 = anscombe[anscombe['dataset'] == 'II']
dataset_3 = anscombe[anscombe['dataset'] == 'III']
dataset_4 = anscombe[anscombe['dataset'] == 'IV']
Creating a figure and dividing into 4 parts
fig = plt.figure()
axes_1 = fig.add_subplot(2,2,1)
axes_2 = fig.add_subplot(2,2,2)
axes_3 = fig.add_subplot(2,2,3)
axes_4 = fig.add_subplot(2,2,4)
axes_1.plot(dataset_1['x'], dataset_1['y'], 'o')
axes_2.plot(dataset_2['x'], dataset_2['y'], 'o')
axes_3.plot(dataset_3['x'], dataset_3['y'], 'o')
axes_4.plot(dataset_4['x'], dataset_4['y'], 'o')
axes_1.set_title('dataset_1')
axes_2.set_title('dataset_2')
axes_3.set_title('dataset_3')
axes_4.set_title('dataset_4')
fig.suptitle('Anscombe Data')
fig.tight_layout()
The only output which i'm getting at each plot is
[<matplotlib.lines.Line2D at 0x24592c94bc8>]
What am I doing wrong?
If you are working with a Jupyter Notebook then you can add the following line to the top cell where you call all your imports. The following command will render your graph
%matplotlib inline
Add%matplotlib inline or use matplotlib.pyplot.ion()
after you imported matplotlib.
From plotting docs:
Starting with IPython 5.0 and matplotlib 2.0 you can avoid the use of
IPython’s specific magic and use
matplotlib.pyplot.ion()/matplotlib.pyplot.ioff() which have the
advantages of working outside of IPython as well.
I've tried all of the above, eventually I've found out there is a conflict between matplotlib and a library called dtale. When I removed the import dtale command and restarted the kernel all was working prefectly good.
%matplot plt
Executing this after plt.show() displayed the plots for me.
Found this here: How do I make matplotlib work in AWS EMR Jupyter notebook?

R Markdown: How can I make RStudio display Python plots inline instead of in new window?

So, I've been using R Markdown extensively lastly, and I'm pretty satisfied with what it can do.
However, I'm having a problem with python plots. I have a chunk of python code where I plot multiple figures in python.
When I do that with R, RStudio will display all the plots generated in this chunk side by side inline.
Unfortunately, when doing the same with a chunk of python code, RStudio opens a new Window where it displays the plot, then the code execution is halted until I close that window, then it plots the next figure, I have to close it again, etc etc.
Is there a possibility to force RStudio to put the figures inline, and then continue code execution?
Thanks for your help in advance!
To expand on my earlier comment, I will elaborate with a complete answer. When using matplotlib, the plots are rendered using Qt, which is why you are getting popup windows.
If we use fig.savefig instead of pyplot.show and then pyplot.close we can avoid the popup windows. Here is a minimal example:
---
output: html_document
---
## Python *pyplot*
```{python pyplot, echo=FALSE}
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)
fig, ax = plt.subplots()
ax.plot(t, s)
ax.set(xlabel='time (s)', ylabel='voltage (mV)',
title='About as simple as it gets, folks')
ax.grid()
fig.savefig("pyplot.png")
plt.close(fig)
```
```{r, echo=FALSE}
knitr::include_graphics("pyplot.png")
```
Which produces the following without any process interruption:
Source: matplotlib.org
N.B. According the the release notes for RStudio v1.2.679-1 Preview, this version will show matplotlib plots emitted by Python chunks.
Update
Using the latest preview release mentioned above, updating the chunk to use pyplot.show will now display inline as desired.
```{python pyplot, echo=FALSE}
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)
fig, ax = plt.subplots()
ax.plot(t, s)
ax.set(xlabel='time (s)', ylabel='voltage (mV)',
title='About as simple as it gets, folks')
ax.grid()
plt.show()
```
For Anaconda users
If you use Anaconda as your python distribution, you may experience a problem where Qt is not found from RStudio due to problem with missing path/environment variable.
The error will appear similar to:
This application failed to start because it could not find or load the Qt platform plugin "windows" in "", Reinstalling the application may fix this problem.
A quick fix is to add the following to a python chunk to setup an environment variable.
import os
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = '/path/to/Anaconda3/Library/plugins/platforms'
Replacing /path/to with the relevant location to your Anaconda distribution.

When I use matplotlib in jupyter notebook,it always raise " matplotlib is currently using a non-GUI backend" error?

import matplotlib.pyplot as pl
%matplot inline
def learning_curves(X_train, y_train, X_test, y_test):
""" Calculates the performance of several models with varying sizes of training data.
The learning and testing error rates for each model are then plotted. """
print ("Creating learning curve graphs for max_depths of 1, 3, 6, and 10. . .")
# Create the figure window
fig = pl.figure(figsize=(10,8))
# We will vary the training set size so that we have 50 different sizes
sizes = np.rint(np.linspace(1, len(X_train), 50)).astype(int)
train_err = np.zeros(len(sizes))
test_err = np.zeros(len(sizes))
# Create four different models based on max_depth
for k, depth in enumerate([1,3,6,10]):
for i, s in enumerate(sizes):
# Setup a decision tree regressor so that it learns a tree with max_depth = depth
regressor = DecisionTreeRegressor(max_depth = depth)
# Fit the learner to the training data
regressor.fit(X_train[:s], y_train[:s])
# Find the performance on the training set
train_err[i] = performance_metric(y_train[:s], regressor.predict(X_train[:s]))
# Find the performance on the testing set
test_err[i] = performance_metric(y_test, regressor.predict(X_test))
# Subplot the learning curve graph
ax = fig.add_subplot(2, 2, k+1)
ax.plot(sizes, test_err, lw = 2, label = 'Testing Error')
ax.plot(sizes, train_err, lw = 2, label = 'Training Error')
ax.legend()
ax.set_title('max_depth = %s'%(depth))
ax.set_xlabel('Number of Data Points in Training Set')
ax.set_ylabel('Total Error')
ax.set_xlim([0, len(X_train)])
# Visual aesthetics
fig.suptitle('Decision Tree Regressor Learning Performances', fontsize=18, y=1.03)
fig.tight_layout()
fig.show()
when I run the learning_curves() function, it shows:
UserWarning:C:\Users\Administrator\Anaconda3\lib\site-packages\matplotlib\figure.py:397: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure
You don't need the line of fig.show(). Just remove it. Then there will be no warning message.
adding %matplotlib inline while importing helps for smooth plots in notebook
%matplotlib inline
import matplotlib.pyplot as plt
%matplotlib inline sets the backend of matplotlib to the 'inline' backend:
With this backend, the output of plotting commands is displayed inline within frontends like the Jupyter notebook, directly below the code cell that produced it. The resulting plots will then also be stored in the notebook document.
You can change the backend used by matplotlib by including:
import matplotlib
matplotlib.use('TkAgg')
before your line 1 import matplotlib.pyplot as pl, as it must be set first. See this answer for more information.
(There are other backend options, but changing backend to TkAgg worked for me when I had a similar problem)
Testing with https://matplotlib.org/examples/animation/dynamic_image.html I just add
%matplotlib notebook
which seems to work but is a little bumpy. I had to stop the kernal now and then :-(
Just type fig instead of fig.show()
You can still save the figure by fig.savefig()
If you want to view it on the web page, you can try
from IPython.display import display
display(fig)
I was trying to make 3d clustering similar to Towards Data Science Tutorial. I first thought fig.show() might be correct, but got the same warning...
Briefly viewed Matplot3d.. but then I tried plt.show() and it displayed my 3d model exactly as anticipated. I guess it makes sense too.
This would be equivalent to your pl.show()
Using python 3.5 and Jupyter Notebook
The error "matplotlib is currently using a non-GUI backend” also occurred when I was trying to display a plot using the command fig.show(). I found that in a Jupyter Notebook, the command fig, ax = plt.subplots() and a plot command need to be in the same cell in order for the plot to be rendered.
For example, the following code will successfully show a bar plot in Out[5]:
In [3]:
import matplotlib.pyplot as plt
%matplotlib inline
In [4]:
x = 'A B C D E F G H'.split()
y = range(1, 9)
In [5]:
fig, ax = plt.subplots()
ax.bar(x, y)
Out[5]: (Container object of 8 artists)
A successful bar plot output
On the other hand, the following code will not show the plot,
In [5]:
fig, ax = plt.subplots()
Out[5]:
An empty plot with only a frame
In [6]:
ax.bar(x, y)
Out[6]: (Container object of 8 artists)
In Out[6] there is only a statement of "Container object of 8 artists" but no bar plot is shown.
I had the same error. Then I used
import matplotlib
matplotlib.use('WebAgg')
it works fine.(You have to install tornado to view in web, (pip install tornado))
Python version: 3.7
matplotlib version: 3.1.1
If you are using any profiling libraries like pandas_profiling, try commenting out them and execute the code. In my case I was using pandas_profiling to generate a report for a sample train data. commenting out import pandas_profiling helped me solve my issue.
%matplotlib notebook worked for me.
But the takes time to load and but it is clear.
You imported matplotlib.pyplot as pl. In the end type pl.show() instead of fig.show()

How do I set the aspect ratio for a plot in Python with Spyder?

I'm brand new to Python, I just switched from Matlab. The distro is Anaconda 2.1.0 and I'm using the Spyder IDE that came with it.
I'm trying to make a scatter plot with equal ratios on the x and y axes, so that this code prints a square figure with the vertices of a regular hexagon plotted inside.
import numpy
import cmath
import matplotlib
coeff = [1,0,0,0,0,0,-1]
x = numpy.roots(coeff)
zeroplot = plot(real(x),imag(x), 'ro')
plt.gca(aspect='equal')
plt.show()
But plt.gca(aspect='equal') returns a blank figure with axes [0,1,0,1], and plt.show() returns nothing.
I think the main problem is that plt.gca(aspect='equal') doesn't just grab the current axis and set its aspect ratio. From the documentation, (help(plt.gca)) it appears to create a new axis if the current one doesn't have the correct aspect ratio, so the immediate fix for this should be to replace plt.gca(aspect='equal') with:
ax = plt.gca()
ax.set_aspect('equal')
I should also mention that I had a little bit of trouble getting your code running because you're using pylab to automatically load numpy and matplotlib functions: I had to change my version to:
import numpy
import cmath
from matplotlib import pyplot as plt
coeff = [1,0,0,0,0,0,-1]
x = numpy.roots(coeff)
zeroplot = plt.plot(numpy.real(x), numpy.imag(x), 'ro')
ax = plt.gca()
ax.set_aspect('equal')
plt.show()
People who are already comfortable with Python don't generally use Pylab, from my experience. In future you might find it hard to get help on things if people don't realise that you're using Pylab or aren't familiar with how it works. I'd recommend disabling it and trying to get used to accessing the functions you need through their respective modules (e.g. using numpy.real instead of just real)

Categories

Resources