I know this question is probably asked frequently but I've been unable to find an answer. I have created a plot by using the following code:
matplotlib.pyplot.loglog(a,b, basex = 2, label = 'mergesort')
matplotlib.pyplot.ylabel('Time Taken')
matplotlib.pyplot.title('Time vs 2^i')
matplotlib.pyplot.legend()
This has created a graph in a new window with a suitable plot. I am now looking to create an entirely different plot which will pop up in a seperate window for another set of data. I have tried writing this code:
newfig = matplotlib.pyplot.loglog(e,f, basex = 2, label = "Timsort")
However when I try this, it just adds another label onto the previous graph. Can anyone help me figure out how to avoid this?
This is what "matplotlib.pyplot.show()" is for.
from matplotlib import pyplot as plt
import numpy as np
if __name__ == "__main__":
a = np.random.rand(100,1)
b = np.random.rand(100,1)
e = np.random.rand(100,1)
f = np.random.rand(100,1)
plt.loglog(a,b, basex = 2, label = 'mergesort')
plt.ylabel('Time Taken')
plt.title('Time vs 2^i')
plt.legend()
plt.show()
plt.loglog(e,f, basex = 2, label = "Timsort")
plt.show()
This will generate 2 separate figures/plots
You can use something like this:
fig,ax = plt.subplots(1,2)
and when plotting you can call them by their index. In this case:
ax[0].plot(your_data)
ax[1].plot(your_data_2)
The first argument of plt.subplots specifies the number of rows and second argument specifies the number of columns
Related
I'm currently trying to make a nested doughnut chart with four layers and I have come across some problems with it.
There is one dependency in my data. I look into the changes done with a specific method and divide them into agronomical and academic traits. I then create a fourth ring which shows basically the amount of academic and each agronomical trait. I don't know how to automatically align both doughnut rings so they match.
I looked into the matplotlib documentation, but I don't understand the addressing of the colormaps. I took over the example code, but in the end its not really understandable how this is addressing the colors of it.
I need to make a legend for the chart. However, due to the long names of some of the subgroups, I can not show them in the pie chart but they should appear in the legend. When I draw the legend via the ax.legend function, it adds only the groups to the legend which I addressed in the ax.pie function with labels=, if I use fig.legend for drawing the legend, the colors are not matching at all. I tried to use the handles= function I stumbled across some posts here on StackOverflow. But they just give me an error
AttributeError: 'tuple' object has no attribute 'legend'
I would like to add the pct and number of occurrences to my legend, but I guess there is no "easy" way for that?
´´´
import numpy as np
import pandas
import pandas as pd
import matplotlib.pyplot as plt
import openpyxl
df = pandas.read_excel("savedrecs.xlsx", sheet_name="test")
#print(df.head())
size = 0.3
fig, ax = plt.subplots(figsize=(12,8))
#Colors----
cmap1 = plt.get_cmap("tab20c")
cmap2 = plt.get_cmap("tab10")
outer_colors = cmap1(np.arange(20))
inner_colors = cmap1(np.arange(12))
sr_colors = cmap1(np.arange(5,6))
#Data----
third_ring = df[df["Group"].str.contains("group")]
fourth_ring = df[df["Group"].str.contains("Target trait")]
second_ring = df[df["Group"].str.contains("Cultivar")]
first_ring = df[df["Group"].str.contains("Mutation")]
#----
#---Testautopct---
def make_autopct(values):
def my_autopct(pct):
total = sum(values)
val = int(round(pct*total/100.0))
return '{p:.2f}%\n({v:d})'.format(p=pct,v=val)
return my_autopct
#-----
#Piechart----
ir = ax.pie(first_ring["Occurence"], radius=1-size, labels=first_ring["Name"], textprops={"fontsize":8},labeldistance=0,
colors=sr_colors, wedgeprops=dict(edgecolor="w"))
sr = ax.pie(second_ring["Occurence"],
autopct=make_autopct(second_ring["Occurence"]),pctdistance=0.83,textprops={"fontsize":8},
radius=1,wedgeprops=dict(width=size, edgecolor="w"),startangle=90,colors=inner_colors)
tr = ax.pie(third_ring["Occurence"],
autopct=make_autopct(third_ring["Occurence"]),labels=third_ring["Name"],pctdistance=0.83,textprops={"fontsize":8},
radius=1+size,wedgeprops=dict(width=size, edgecolor="w"),startangle=90,colors=outer_colors)
fr = ax.pie(fourth_ring["Occurence"],
autopct=make_autopct(fourth_ring["Occurence"]),labels=fourth_ring["Name"],pctdistance=0.83,textprops={"fontsize":8},
radius=1+size*2,wedgeprops=dict(width=size, edgecolor="w"),startangle=90,colors=outer_colors)
#---Legend & Title----
ax.legend( bbox_to_anchor=(1.04, 0.5), loc="center left", borderaxespad=10 ,fancybox=True, shadow=False, ncol=1, title="This will be a fancy legend title")
fig.suptitle("This will be a fancy title, which I don't know yet!")
#----
plt.tight_layout()
plt.show()
´´´
The output of this code is then as follows:
I am following the statsmodels documentation here:
https://www.statsmodels.org/stable/vector_ar.html
I get to the part at the middle of the page that says:
irf.plot(orth=False)
which produces the following graph for my data:
I need to modify the elements of the graph. E.g., I need to apply tight_layout and also decrease the y-tick sizes so that they don't get into the graphs to their left.
The documentation talks about passing "subplot plotting funcions" in to the subplot argument of irf.plot(). But when I try something like:
irf.plot(subplot_params = {'fontsize': 8, 'figsize' : (100, 100), 'tight_layout': True})
only the fontsize parameter works. I also tried passing these parameters to the 'plot_params' argument but of no avail.
So, my question is how can I access other parameters of this irf.plot, especially the figsize and ytick sizes? I also need to force it to print a grid, as well as all values on the x axis (1, 2, 3, 4, ..., 10)
Is there any way I can create a blank plot using the fig, ax = plt.subplots() way and then create the irf.plot on that figure?
Looks like the function returns a matplotlib.figure:
Try doing this:
fig = irf.plot(orth=False,..)
fig.tight_layout()
fig.set_figheight(100)
fig.set_figwidth(100)
If I run it with this example, it works:
import numpy as np
import pandas
import statsmodels.api as sm
from statsmodels.tsa.api import VAR
mdata = sm.datasets.macrodata.load_pandas().data
dates = mdata[['year', 'quarter']].astype(int).astype(str)
quarterly = dates["year"] + "Q" + dates["quarter"]
from statsmodels.tsa.base.datetools import dates_from_str
quarterly = dates_from_str(quarterly)
mdata = mdata[['realgdp','realcons','realinv']]
mdata.index = pandas.DatetimeIndex(quarterly)
data = np.log(mdata).diff().dropna()
model = VAR(data)
results = model.fit(maxlags=15, ic='aic')
irf = results.irf(10)
fig = irf.plot(orth=False)
fig.tight_layout()
fig.set_figheight(30)
fig.set_figwidth(30)
I am making an application where the users inputs data and the results are displayed on a chart. I want the plot to update each time new data is input, but updating the plot is not happening.
The plot is produce using the matlib plot library and the interface is created using the tkinter package. The way it is done is uses a function to create the plot as I want to call this several times. What I think could be the problem is the way the function returns the variable, but I can't put my finger on what or why this is wrong.
I have looked on here for solutions and none of the ones I have read seem to work. I have tried to update my axes, used patlibplot.figure instead of matlibplot.plot , adding canvas.daw() to the end and even tried to get a new way of producing the plot.
This is the function that creates the plot:
import matplotlib.pyplot as plt
def PlotConsumption(fuelEntry, plotConfig):
'''
Produce a line plot of the consumption
:params object fuelEntry: all of the fuel entry information
:params object plotConfig: the config object for the plot
'''
# create a data frame for plotting
df = pd.DataFrame(fuelEntry)
df = df.sort_values(["sort"]) # ensure the order is correct
df["dateTime"] = pd.to_datetime(df["date"], format="%d/%m/%Y") # create a date-time version of the date string
if plotConfig.xName == "date": # change the indexing for dates
ax = df.plot(x = "dateTime", y = plotConfig.yName, marker = '.', rot = 90, title = plotConfig.title)
else:
ax = df.plot(x = plotConfig.xName, y = plotConfig.yName, marker = '.', title = plotConfig.title)
# calculate the moving average if applicable
if plotConfig.moveCalc == True and plotConfig.move > 1 and len(df) > plotConfig.move:
newName = plotConfig.yName + "_ma"
df[newName] = df[plotConfig.yName].rolling(window = plotConfig.move).mean()
if plotConfig.xName == "date":
df.plot(x = "dateTime", y = newName, marker = "*", ax = ax)
else:
df.plot(x = plotConfig.xName, y = newName, marker = "*", ax = ax)
# tidy up the plot
ax.set(xlabel = plotConfig.xLabel, ylabel = plotConfig.yLabel)
plt.setp(ax.xaxis.get_majorticklabels(), rotation=90)
L=plt.legend()
L.get_texts()[0].set_text(plotConfig.yLegend)
if len(L.get_texts()) == 2: # only process if there is a moving average plot
L.get_texts()[1].set_text(plotConfig.moveLegend)
return plt # also tried with returning ax
And this is where it is used:
self.plot = displayCharts.PlotConsumption(self.data.carEntry["fuelEntry"], self.plotConfig)
#fig = plt.figure(1) # also tried creating fig this way
fig = self.plot.figure(1)
self.plotCanvas = FigureCanvasTkAgg(fig, master = self.master)
self.plotWidget = self.plotCanvas.get_tk_widget()
self.plotWidget.grid(row = 0, column = 1, rowspan = 3, sticky = tk.N)
fig.canvas.draw()
I expect the plot to update automatically but instead it does nothing. I know the data is read and processed as if you close the application, start it up again and then load the same data file the plot produced is correct.
I revisited some of the answers I initially looked at and picked my way through them and this one is the best I found and it actually does what I want!
There were a few sublte differences that I needed to change:
Create the figure and canvas to start with
Use these variables to create the plot
I copied the linked solution to see how it works and managed to get it to work. Now the next thing is to get it to plot with my data! But now that I have got it updating it should be easier to finish off.
I am creating two Python scripts to produce some plots for a technical report. In the first script I am defining functions that produce plots from raw data on my hard-disk. Each function produces one specific kind of plot that I need. The second script is more like a batch file which is supposed to loop around those functions and store the produced plots on my hard-disk.
What I need is a way to return a plot in Python. So basically I want to do this:
fig = some_function_that_returns_a_plot(args)
fig.savefig('plot_name')
But what I do not know is how to make a plot a variable that I can return. Is this possible? Is so, how?
You can define your plotting functions like
import numpy as np
import matplotlib.pyplot as plt
# an example graph type
def fig_barh(ylabels, xvalues, title=''):
# create a new figure
fig = plt.figure()
# plot to it
yvalues = 0.1 + np.arange(len(ylabels))
plt.barh(yvalues, xvalues, figure=fig)
yvalues += 0.4
plt.yticks(yvalues, ylabels, figure=fig)
if title:
plt.title(title, figure=fig)
# return it
return fig
then use them like
from matplotlib.backends.backend_pdf import PdfPages
def write_pdf(fname, figures):
doc = PdfPages(fname)
for fig in figures:
fig.savefig(doc, format='pdf')
doc.close()
def main():
a = fig_barh(['a','b','c'], [1, 2, 3], 'Test #1')
b = fig_barh(['x','y','z'], [5, 3, 1], 'Test #2')
write_pdf('test.pdf', [a, b])
if __name__=="__main__":
main()
If you don't want the picture to be displayed and only get a variable in return, then you can try the following (with some additional stuff to remove axis):
def myplot(t,x):
fig = Figure(figsize=(2,1), dpi=80)
canvas = FigureCanvasAgg(fig)
ax = fig.add_subplot()
ax.fill_between(t,x)
ax.autoscale(tight=True)
ax.axis('off')
canvas.draw()
buf = canvas.buffer_rgba()
X = np.asarray(buf)
return X
The returned variable X can be used with OpenCV for example and do a
cv2.imshow('',X)
These import must be included:
from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg
The currently accepted answer didn't work for me as such, as I was using scipy.stats.probplot() to plot. I used matplotlib.pyplot.gca() to access an Axes instance directly instead:
"""
For my plotting ideas, see:
https://pythonfordatascience.org/independent-t-test-python/
For the dataset, see:
https://github.com/Opensourcefordatascience/Data-sets
"""
# Import modules.
from scipy import stats
import matplotlib.pyplot as plt
import pandas as pd
from tempfile import gettempdir
from os import path
from slugify import slugify
# Define plot func.
def get_plots(df):
# plt.figure(): Create a new P-P plot. If we're inside a loop, and want
# a new plot for every iteration, this is important!
plt.figure()
stats.probplot(diff, plot=plt)
plt.title('Sepal Width P-P Plot')
pp_p = plt.gca() # Assign an Axes instance of the plot.
# Plot histogram. This uses pandas.DataFrame.plot(), which returns
# an instance of the Axes directly.
hist_p = df.plot(kind = 'hist', title = 'Sepal Width Histogram Plot',
figure=plt.figure()) # Create a new plot again.
return pp_p, hist_p
# Import raw data.
df = pd.read_csv('https://raw.githubusercontent.com/'
'Opensourcefordatascience/Data-sets/master//Iris_Data.csv')
# Subset the dataset.
setosa = df[(df['species'] == 'Iris-setosa')]
setosa.reset_index(inplace= True)
versicolor = df[(df['species'] == 'Iris-versicolor')]
versicolor.reset_index(inplace= True)
# Calculate a variable for analysis.
diff = setosa['sepal_width'] - versicolor['sepal_width']
# Create plots, save each of them to a temp file, and show them afterwards.
# As they're just Axes instances, we need to call get_figure() at first.
for plot in get_plots(diff):
outfn = path.join(gettempdir(), slugify(plot.title.get_text()) + '.png')
print('Saving a plot to "' + outfn + '".')
plot.get_figure().savefig(outfn)
plot.get_figure().show()
I'm trying to go away from matlab and use python + matplotlib instead. However, I haven't really figured out what the matplotlib equivalent of matlab 'handles' is. So here's some matlab code where I return the handles so that I can change certain properties. What is the exact equivalent of this code using matplotlib? I very often use the 'Tag' property of handles in matlab and use 'findobj' with it. Can this be done with matplotlib as well?
% create figure and return figure handle
h = figure();
% add a plot and tag it so we can find the handle later
plot(1:10, 1:10, 'Tag', 'dummy')
% add a legend
my_legend = legend('a line')
% change figure name
set(h, 'name', 'myfigure')
% find current axes
my_axis = gca();
% change xlimits
set(my_axis, 'XLim', [0 5])
% find the plot object generated above and modify YData
set(findobj('Tag', 'dummy'), 'YData', repmat(10, 1, 10))
There is a findobj method is matplotlib too:
import matplotlib.pyplot as plt
import numpy as np
h = plt.figure()
plt.plot(range(1,11), range(1,11), gid='dummy')
my_legend = plt.legend(['a line'])
plt.title('myfigure') # not sure if this is the same as set(h, 'name', 'myfigure')
my_axis = plt.gca()
my_axis.set_xlim(0,5)
for p in set(h.findobj(lambda x: x.get_gid()=='dummy')):
p.set_ydata(np.ones(10)*10.0)
plt.show()
Note that the gid parameter in plt.plot is usually used by matplotlib (only) when the backend is set to 'svg'. It use the gid as the id attribute to some grouping elements (like line2d, patch, text).
I have not used matlab but I think this is what you want
import matplotlib
import matplotlib.pyplot as plt
x = [1,3,4,5,6]
y = [1,9,16,25,36]
fig = plt.figure()
ax = fig.add_subplot(111) # add a plot
ax.set_title('y = x^2')
line1, = ax.plot(x, y, 'o-') #x1,y1 are lists(equal size)
line1.set_ydata(y2) #Use this to modify Ydata
plt.show()
Of course, this is just a basic plot, there is more to it.Go though this to find the graph you want and view its source code.
# create figure and return figure handle
h = figure()
# add a plot but tagging like matlab is not available here. But you can
# set one of the attributes to find it later. url seems harmless to modify.
# plot() returns a list of Line2D instances which you can store in a variable
p = plot(arange(1,11), arange(1,11), url='my_tag')
# add a legend
my_legend = legend(p,('a line',))
# you could also do
# p = plot(arange(1,11), arange(1,11), label='a line', url='my_tag')
# legend()
# or
# p[0].set_label('a line')
# legend()
# change figure name: not sure what this is for.
# set(h, 'name', 'myfigure')
# find current axes
my_axis = gca()
# change xlimits
my_axis.set_xlim(0, 5)
# You could compress the above two lines of code into:
# xlim(start, end)
# find the plot object generated above and modify YData
# findobj in matplotlib needs you to write a boolean function to
# match selection criteria.
# Here we use a lambda function to return only Line2D objects
# with the url property set to 'my_tag'
q = h.findobj(lambda x: isinstance(x, Line2D) and x.get_url() == 'my_tag')
# findobj returns duplicate objects in the list. We can take the first entry.
q[0].set_ydata(ones(10)*10.0)
# now refresh the figure
draw()