What happened is I followed this demo, I modified it to suit my needs had it working, changed it to use a function to draw two graphs but now it doesn't work at all using plt.show() or plt.savefig()
here's my code
import csv
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
# I converted excel to a csv file
data = [x for x in csv.reader(open('ASS1_Q1.csv'))]
question1 = {}
question1['males'] = []
question1['females'] = []
for x in data:
if x[0].lower() == "male":
question1["males"].append(float(x[1]))
elif x[0].lower() == "female":
question1['females'].append(float(x[1]))
else:
print "Not a valid dataline", x
def plot_graph(data, filename):
fig = plt.figure()
ax = fig.add_subplot(111)
n, bins, patches = ax.hist(np.array(data), bins=13, align='mid', facecolor='#888888')
ax.set_xlabel('Speed in kph')
ax.set_ylabel('Amount of Females')
ax.set_xlim(min(data, max(data)))
# plt.savefig(filename)
plt.show()
plot_graph(question1['males'], "ASS1Q1-males.eps")
#plot_graph(question1['females'], "ASSQ2-females.eps")
print summary(question1['males'])
print summary(question1['females'])
Can someone explain why this is happening? what am I doing wrong?
Try removing
import matplotlib
matplotlib.use('Agg')
The command
python -c 'import matplotlib; matplotlib.use("")'
will show you the valid string arguments that can be sent to matplotlib.use.
On my machine, 'Agg' is listed as valid, though I get no output when this is set. If you are curious, you could just keep trying various options until you find one that works.
When you find the one that your prefer, you may also find it more convenient to set something like
backend : GtkAgg
in your ~/.matplotlib/matplotlibrc instead of using matplotlib.use(...).
Related
I'm trying to suppress the output/plots run in the code below (because I plan on adjusting the plots later), but regardless of what I've tried, nothing seems to work.
I've tried all the following based on the referenced articles (littering my code, will need to clean up), but nothing seems to work.
add semi-colons
pass; statements
adjusting the notebook's environment conditions
using subprocess functions and modified suppress functions
Related SO:
Remove output of all subprocesses in Python without access to code
Silence the stdout of a function in Python without trashing sys.stdout and restoring each function call
Python: Suppress library output not using stdout
IPython, semicolon to suppress output does not work
https://github.com/ipython/ipython/issues/10794
Suppress output in matplotlib
dictionary_of_figures = OrderedDict()
dictionary_of_images = OrderedDict()
from contextlib import contextmanager
import sys, os
import subprocess
import inspect
import contextlib
import io
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import matplotlib.ticker as ticker
from collections import OrderedDict
def draw_year_close_plot(df, group_by_column_name, year):
reduced_range = df.loc[(df['Year'] == year)]
year_string = str(year)
# 0 - Setup
matplotlib.rc_file_defaults();
ax1 = sns.set_style("darkgrid"); #"style must be one of white, dark, whitegrid, darkgrid, ticks"
fig, ax1 = plt.subplots(figsize=(5,2));
# 1 - Create Closing Plot
lineplot = sns.lineplot(data = reduced_range['Close'], sort = False, ax=ax1);
pass;
ax1.xaxis.set_major_formatter(ticker.EngFormatter())
lineplot.set_title(company_name + str(" (")+ stock_ticker + str(") - ") + 'Historical Close & Volume - ' + year_string, fontdict= { 'fontsize': 8, 'fontweight':'bold'})
# 2 - Create Secondary Plot - Volume
ax2 = ax1.twinx();
ax2.grid(False);
sns.lineplot(data = reduced_range['Volume'], sort = False, ax=ax2, alpha=0.15);
pass;
return fig
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "last_expr"
##contextmanager
#def suppress_stdout():
# with open(os.devnull, "w") as devnull:
# old_stdout = sys.stdout
# sys.stdout = devnull
# try:
# yield
# finally:
# sys.stdout = old_stdout
##contextlib.contextmanager
#def nostdout():
# save_stdout = sys.stdout
# sys.stdout = io.BytesIO()
# yield
# sys.stdout = save_stdout
with contextlib.redirect_stdout(io.StringIO()):
for year in range(min_year,min_year+5):
dictionary_of_figures[year] = draw_year_close_plot(daily_df,'Year', year);
dictionary_of_images[year] = fig2img(dictionary_of_figures[year]);
Any ideas?
It looks like you are asking to suppress plots while in the Jupyter environment. The %matplotlib inline causes the plots to be rendered on the output. If you remove that line, you will not get the plot rendered and you'll get back the plot object (I tested this on your code).
You can't comment out %matplotlib inline once the kernel in Jupyter has run it - it persists within the kernel. You need to comment it out and restart the kernel, at which point I think you'll see the behavior you want.
Once you've modified the plots as you with, you can turn %matplotlib inline back on and render your updated plots.
If you need to turn %matplotlib inline on and off, you need to know a little about your Jupyter environment. Please see this answer
UPDATE:
I tried a few cases. It looks best if you explicitly set %matplotlib to an option other than inline. Here is minimal code to illustrate. I have kept all of your graphics-related code and made up data where your question does not provide values, and print the type for fig (which is your return value). I have also explicitly set %matplotlib notebook. Note that you should run %matplotlib --list to make sure that is one of your choices.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.ticker as ticker
df = pd.DataFrame({'Close': [1,2,3], 'Volume': [4,5,6]})
%matplotlib notebook
# matplotlib.rc_file_defaults() # We don't have your defaults file
ax1 = sns.set_style("darkgrid"); #"style must be one of white, dark, whitegrid, darkgrid, ticks"
fig, ax1 = plt.subplots(figsize=(5,2))
lineplot = sns.lineplot(data=df['Close'], sort = False, ax=ax1)
ax1.xaxis.set_major_formatter(ticker.EngFormatter())
lineplot.set_title("This is the Title")
ax2 = ax1.twinx()
ax2.grid(False)
sns.lineplot(data=df['Volume'], sort = False, ax=ax2, alpha=0.15)
print(type(fig))
I would like to:
pylab.figure()
pylab.plot(x)
pylab.figure()
pylab.plot(y)
# ...
for i, figure in enumerate(pylab.MagicFunctionReturnsListOfAllFigures()):
figure.savefig('figure%d.png' % i)
What is the magic function that returns a list of current figures in pylab?
Websearch didn't help...
Pyplot has get_fignums method that returns a list of figure numbers. This should do what you want:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(100)
y = -x
plt.figure()
plt.plot(x)
plt.figure()
plt.plot(y)
for i in plt.get_fignums():
plt.figure(i)
plt.savefig('figure%d.png' % i)
The following one-liner retrieves the list of existing figures:
import matplotlib.pyplot as plt
figs = list(map(plt.figure, plt.get_fignums()))
Edit: As Matti Pastell's solution shows, there is a much better way: use plt.get_fignums().
import numpy as np
import pylab
import matplotlib._pylab_helpers
x=np.random.random((10,10))
y=np.random.random((10,10))
pylab.figure()
pylab.plot(x)
pylab.figure()
pylab.plot(y)
figures=[manager.canvas.figure
for manager in matplotlib._pylab_helpers.Gcf.get_all_fig_managers()]
print(figures)
# [<matplotlib.figure.Figure object at 0xb788ac6c>, <matplotlib.figure.Figure object at 0xa143d0c>]
for i, figure in enumerate(figures):
figure.savefig('figure%d.png' % i)
This should help you (from the pylab.figure doc):
call signature::
figure(num=None, figsize=(8, 6),
dpi=80, facecolor='w', edgecolor='k')
Create a new figure and return a
:class:matplotlib.figure.Figure
instance. If num = None, the
figure number will be incremented and
a new figure will be created.** The
returned figure objects have a
number attribute holding this number.
If you want to recall your figures in a loop then a good aproach would be to store your figure instances in a list and to call them in the loop.
>> f = pylab.figure()
>> mylist.append(f)
etc...
>> for fig in mylist:
>> fig.savefig()
Assuming you haven't manually specified num in any of your figure constructors (so all of your figure numbers are consecutive) and all of the figures that you would like to save actually have things plotted on them...
import matplotlib.pyplot as plt
plot_some_stuff()
# find all figures
figures = []
for i in range(maximum_number_of_possible_figures):
fig = plt.figure(i)
if fig.axes:
figures.append(fig)
else:
break
Has the side effect of creating a new blank figure, but better if you don't want to rely on an unsupported interface
I tend to name my figures using strings rather than using the default (and non-descriptive) integer. Here is a way to retrieve that name and save your figures with a descriptive filename:
import matplotlib.pyplot as plt
figures = []
figures.append(plt.figure(num='map'))
# Make a bunch of figures ...
assert figures[0].get_label() == 'map'
for figure in figures:
figure.savefig('{0}.png'.format(figure.get_label()))
Using Python, I am trying to write tests that compare the current output with an expected output. The output is a matplotlib figure and I would like to do this without saving the figure to a file.
I had the idea to find the cryptographic hash of the object so that I would just need to compare one hash with another to confirm that the entire object is unchanged from what is expected.
This works fine for a numpy array as follows:
import numpy as np
import hashlib
np.random.seed(1)
A = np.random.rand(10,100)
actual_hash = hashlib.sha1(A).hexdigest()
expected_hash = '38f682cab1f0bfefb84cdd6b112b7d10cde6147f'
assert actual_hash == expected_hash
When I try this on a matplotlib object I get: TypeError: object supporting the buffer API required
import hashlib
import numpy as np
import matplotlib.pyplot as plt
X = np.linspace(0,100,1000)
Y = np.sin(0.5*X)
plt.plot(X,Y)
fig = plt.gcf()
actual_hash = hashlib.sha1(fig).hexdigest() #this raises the TypeError
Any ideas how I can use hashlib to find the cryptographic hash of a matplotlib object?
Thanks.
You can get the figure as a numpy array using buffer_rgba(). Before using it you must actually draw the figure:
draw must be called at least once before this function will work and
to update the renderer for any subsequent changes to the Figure.
import hashlib
import numpy as np
import matplotlib.pyplot as plt
X = np.linspace(0,100,1000)
Y = np.sin(0.5*X)
plt.plot(X,Y)
canvas = plt.gcf().canvas
canvas.draw()
actual_hash = hashlib.sha1(np.array(canvas.buffer_rgba())).hexdigest()
I am quite new to python so please bear with me.
My code is below:
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
df = pd.read_csv(r"/Users/aaronhuang/Desktop/ffp/exfileCLEAN2.csv", skiprows=[1])
magnitudes = df['Magnitude '].values
times = df['Time '].values
zscores = np.abs(stats.zscore(magnitudes, ddof=1))
outlier_indicies = np.argwhere(zscores > 3).flatten()
print(times[outlier_indicies])
window = 10
num = 1
x = times[outlier_indicies[num]-window:outlier_indicies[num]+window+1]
y = magnitudes[outlier_indicies[num]-window:outlier_indicies[num]+window+1]
plt.plot(x, y)
plt.xlabel('Time (units)')
plt.ylabel('Magnitude (units)')
plt.show()
fig = plt.figure()
fig.savefig("/Users/aaronhuang/Downloads")
Is there a way I can print all the graphs separately once?. Deleting num has not worked.
Thank you in advance.
You can put the plots inside a for loop, and repeat as many times as you like, with different variables for each step if needed. Most software will show the plots either in multiple plot windows, or output them in a long strip you can scroll through. If you use Spyder however, they will play back to back, with each plot being a frame.
Also, if you want to print multiple plots, you have to put the plt.show() inside the loop as well, putting it after the loop will show all the values on a single plot.
For example:
import matplotlib.pyplot as plt
x_values = [1,2,3,4,5,6,7]
for x in x_values:
y = x**2
plt.plot(x,y,"o")
plt.axis([0,50, 0,50])
plt.show()
I am trying to chart this data in matplotlib and I am getting the following error message:
raise TypeError('Unrecognized argument type %s to close'%type(arg))
TypeError: Unrecognized argument type <type 'list'> to close
The data I am sending to it is not a string, it is a float as you can see from the code below:
import os
import csv
import glob as g
import pprint as p
import matplotlib.pyplot as plt
os.chdir('F:\\')
def graphWriter():
for file in g.glob('*.TXT'):
for col in csv.DictReader(open(file,'rU')):
set_ = int(col[' Set'])
iriR = float(col[' IRI R e'])
iriL = float(col['IRI LWP '])
rutL = float(col[' RUT L e'])
rutR = float(col[' RUT R e'])
start = float(col['Start-Mi'])
end = float(col[' End-Mi'])
fig = plt.plot(iriR,iriL)
plt.show()
plt.close(fig)
graphWriter()
Though the window is coming up to chart the data and the units are correct, there is also no line in the chart, probably that's stemming from the apparent data issue. So the question is whats causing the error message, and whats causing there to be no data lines in the chart. But the two are most likely related. Here is some of the input data though I am only trying to graph the two datasets to the right side which would be iriR and iriL as show above:
(194.449, 194.549, 90.0, 77.9)
(194.549, 194.649, 84.6, 81.5)
(194.649, 194.749, 88.4, 84.1)
(194.749, 194.849, 69.5, 82.9)
(194.849, 194.949, 76.2, 71.0)
The problem is that the function plt.plot returns a list of lines (that were added to the plot), and not a Figure object --- while plt.close only accepts a Figure object. There are numerous ways to work around this,
First, get the figure object ("get current figure"):
fig = plt.gcf()
plt.close(fig)
Second, call close with no arguments: plt.close() --- this will automatically close the active figure.
Third, close all figures: plt.close('all').
All of these usages are covered in the matplotlib.pyplot.close documentation.
Edit:
The next issue is that you're not storing an array of values to your variables, instead you're just storing a single floating value. You can initialize a list, and store new elements to it.
os.chdir('F:\\')
iriR = [] # Initialize a list
def graphWriter():
for file in g.glob('*.TXT'):
for col in csv.DictReader(open(file,'rU')):
set_ = int(col[' Set'])
iriR.append(float(col[' IRI R e'])) # Append new entry
Do the same thing for the other variables that you want to plot.
Maybe this will work.
import pandas as pd
import matplotlib.pyplot as plt
import glob as g
def graphWriter():
data = {}
for file in g.glob('*.TXT'):
data[file] = pd.read_csv(file)
# Removes ')' and turn it into float
data[file][3] = data[file][3].apply(lambda x:x[:-1]).astype(float)
fig, ax = plt.subplots()
for d in data.itervalues():
ax.plot(d[:,2], d[:,3])
plt.show()
plt.close(fig)
graphWriter()
The function will obtain a list of files ended in .TXT then it will load them into a dictionary in which the keys are the names of the files. Later will plot them.
Update
Since the OP posted that pandas is unavailable, its is possible to use numpy.
import numpy as np
import matplotlib.pyplot as plt
import glob as g
def graphWriter():
data = {}
for file in g.glob('*.TXT'):
data[file] = np.fromregex(file, '\d*\.\d*',
dtype=[('1', float), ('2', float),
('3', float), ('4', float)])
fig, ax = plt.subplots()
for d in data.itervalues():
ax.plot(d['3'], d['4'])
plt.show()
plt.close(fig)
graphWriter()