Python matplotlib changing the major unit scale of the x-axis - python

I have a figure that isn't showing the correct dates on the x-axis. Possibly because there are too many observations to show and it results in not showing any. I am not sure if I should use the set_xticks function, but it gives me the attribute error
AttributeError: module 'matplotlib.pyplot' has no attribute 'set_xticks'
My current code is this:
def plot_w(dataframe,ticker,benchmark):
# a. Printing highest observed values and corresponding date
max1 = data_df.loc[:, ticker].max()
max2 = data_df.loc[:, benchmark].max()
max1_date = data_df[data_df[ticker] == max1]['Date'].values[0]
max2_date = data_df[data_df[benchmark] == max2]['Date'].values[0]
print("The highest adjusted close price observed at: \n", ticker, ":", max1.round(2), "USD on the date ", max1_date,
"\n", benchmark, ":", max2.round(2), "USD on the date", max2_date)
# b. Setting up plot based on dropdown input
I = data_df.columns == ticker
mpl_figure = dataframe.loc[:, ['Date',ticker,benchmark]]
mpl_figure.plot(x='Date', y=[ticker,benchmark], style=['-b','-k'], figsize=(10, 5), fontsize=11, legend='true', linestyle = '-')
plt.ylabel("USD",labelpad=5)
plt.locator_params(axis='x', nbins=20)
title = "Adjusted close prices for " + ticker + " and " + benchmark
plt.title(title)
plt.set_xticks(data_df['Date'].values) # Code fails here
# c. Creating the widget for the plot
widgets.interact(plot_w,
dataframe = widgets.fixed(data_df),
ticker = widgets.Dropdown(
options=data_df.columns,
value='ATVI',
description='Company 1:',
disabled=False,
),
benchmark = widgets.Dropdown(
options=data_df.columns,
value='AAPL',
description='Company 2:',
disabled=False,
)
)
The figure looks like this:

set_xticks is for an axis, if you are setting ticks for a figure it's
plt.xticks(data_df['Date'].values)

Alternatively, you can try the following inside your function working on an axis object. The idea is to first create an axis instance ax, and then pass it to the plot command. Later use it to set the x-ticks.
I = data_df.columns == ticker
fig, ax = plt.subplots(figsize=(10, 5))
mpl_figure = dataframe.loc[:, ['Date',ticker,benchmark]]
mpl_figure.plot(x='Date', y=[ticker,benchmark], style=['-b','-k'], ax=ax, fontsize=11, legend='true', linestyle = '-')
plt.ylabel("USD",labelpad=5)
plt.locator_params(axis='x', nbins=20)
title = "Adjusted close prices for " + ticker + " and " + benchmark
plt.title(title)
ax.set_xticks(data_df['Date'].values)

The module matplotlib.pyplot has no set_xticks function, but an xticks function instead. (link to doc). However, the class object matplotlib.axes.Axes does have set_xticks (link to doc).
The easiest fix in your code is thus
plt.xticks(data_df['Date'].values)
Side note: I am not entirely sure why matplotlib.pyplot keeps around two functions with (almost) the same effect but different names. I guess allowing it to be called from either the module or the object is an imitation of MATLAB, but in MATLAB the function name is the same.

Related

Update a matlib plot in tkinter canvas

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.

Matplotlib unable to save the file correctly or completely

I have been trying to construct visualizations of machine data and I am using pandas dataframe to store the data. I am using a for loop to go select the various slices of the dataset. The visualizations I have constructed has time on the X-axis and because the visualization is in milliseconds the width of the plots is very long.
def jobwise_plotter(prog_no):
df = single_df[single_df['PRG_NO']==prog_no]
#fig1 = plt.figure()
#jobs_list = list(df['Job_no'].unique())
#tools_list = list(df['TOOL_No.'].unique())
for job in list(df['Job_no'].unique()):
df_temp = df[df['Job_no']==job]
time_axis_max = 0
for tool in list(df_temp['TOOL_No.'].unique()):
plt.plot(df_temp['Time'][df_temp['TOOL_No.']==tool],
df_temp['Spindle'][df_temp['TOOL_No.']==tool], label=str(tool))
if int(df_temp['Time'][df_temp['TOOL_No.']==tool].max()) > time_axis_max:
time_axis_max = int(df_temp['Time'][df_temp['TOOL_No.']==tool].max())
plt.title("Prog No. : "+ str(prog_no) + ", Job no : "+ str(job) + ", All Tools")
plt.xlabel("Time (in ms.)")
plt.ylabel("Spindle Load")
name = "prog_"+str(prog_no)+"_"+"JOB_"+str(job)+"_All_tools"
plt.xticks(np.arange(0, time_axis_max+10000, 5000))
plt.grid(linewidth = 2, linestyle = '-', color='#eff3f9')
lgd = plt.legend(loc='upper center', bbox_to_anchor=(0.5, 0.98), ncol=10)
plt.tight_layout()
fig1 = plt.gcf()
fig1.set_size_inches(100, 10)
#fig1 = plt.gcf()
print(name)
fig1.savefig(name, dpi=500, bbox_extra_artists=(lgd,))
plt.show()
The code is working fine and constructing the necessary visualizations in the IPython notebook but the saved image cannot be viewed (Frozen my system thrice now).
Is there any limit to image that could be stored? The figure is viewable within the notebook and we can even download it from the browser.
The figure shown inside the Jupyter notebook is saved using fig.savefig(<some buffer>, bbox_inches="tight").
Hence, in order to obtain the same figure when saving to disc, you would also need to save it using the bbox_inches="tight" argument,
fig.savefig("output.png", bbox_inches="tight")

Setting xaxis values to %.2f on a bar graph

I have a bar graph with multiple data series and i want to set the xaxis values to a significant value of %.2f I already tried using the set_major formatter for the first graph, but it resets the values to 0, while the values should be like the second graph.
How can I fix this?
My code look like this:
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.ticker as mtick
# select the measurement location
MATH = "import/data/place"
SAVE = "save/location"
fig, axes = plt.subplots(figsize=(12,15),nrows=2, ncols=1) # size of the plots and the placing
fig.subplots_adjust(hspace=0.5) # set space between plots
DATA = pd.read_csv(MATH,delimiter=',',usecols = [2,3,4,5,6,7,8,9,10,11,12],names = ['set_t','set_rh',
'type','math','ref','LUFFT','VPL','VPR','VVL','VVR','PRO'], parse_dates=True)
# select the data
temp = DATA.loc[(DATA['type']=='T')&(DATA['math']=='dif')] # dif temperature data
rh = DATA.loc[((DATA['type']=='RH')&(DATA['math']=='dif'))] # dif relative humidity data
# plot temperature
fg = temp.plot.bar(x='set_t',y = ['LUFFT','VPL','VPR','VVL','VVR','PRO'],
color = ['b','firebrick','orange','forestgreen','darkturquoise','indigo'],
ax=axes[0])
fg.grid(True)
fg.set_ylabel('$ΔT$(°C)',fontsize = 12)
fg.set_xlabel('ref $T$ (°C)',fontsize = 12)
fg.set_title('Difference in T from reference at constant relative humidity 50%',fontsize = 15)
fg.yaxis.set_major_formatter(mtick.FormatStrFormatter('%.2f'))
fg.xaxis.set_major_formatter(mtick.FormatStrFormatter('%.2f'))
# plot relative humidity
df = rh.plot.bar(x='set_t',y = ['LUFFT','VPL','VPR','VVL','VVR','PRO'],
color = ['b','firebrick','orange','forestgreen','darkturquoise','indigo'],
ax=axes[1])
df.grid(True)
df.set_ylabel('$ΔU$(%)',fontsize = 12)
df.set_xlabel('ref $T$ (°C)',fontsize = 12)
df.set_title('Difference in U from reference at constant relative humidity 50%',fontsize = 15)
plt.tight_layout()
plt.savefig(SAVE + "_example.jpg")
plt.show()
A sample of my data:
07:40:00,07:50:00,39.85716354999982,51.00504745588235,T,dif,,0.14283645000018197,-0.07502069285698099,-0.15716354999978677,0.0020201234696060055,-0.07111703837193772,-0.0620802166664447,
07:40:00,07:50:00,39.85716354999982,51.00504745588235,RH,dif,,-0.40504745588239643,3.994952544117652,2.994952544117652,4.994952544117652,,6.994952544117652,
08:40:00,08:50:00,34.861160704969016,51.1297401832298,T,dif,,0.22883929503095857,0.2509082605481865,-0.2575243413326831,0.24864321659958222,0.14092262836431502,-0.04441070496899613,
08:40:00,08:50:00,34.861160704969016,51.1297401832298,RH,dif,,-0.32974018322978793,3.8702598167702007,2.8702598167702007,4.870259816770201,,6.870259816770201,
This is due to the fact that with a grouped barplot like this, made by Pandas, the x-axes loses its actual 'range', and the values associated with the tick position become the position itself. That's a bit cryptic, but you can see with fg.get_xlim() that the values have lost 'touch' with the original data, and are simply increasing integers. You can explore/debug the 'values' and 'positions' Matplotlib uses if you provide a FuncFormatter with a function like this:
def check_pos(val, pos):
print(val, pos)
return '%.2f' % val
This basically shows that no formatter is going to work for your case.
Luckily the ticklabels are set correctly (as text), so you could parse these to float, and format them as you wish.
Remove your formatter altogether, and set the xticklabels with:
fg.set_xticklabels(['%.2f' % float(x.get_text()) for x in fg.get_xticklabels()])
Note that Matplotlib itself is perfectly capable of preserving the correct tickvalues in combination with a bar plot, but you would have to do the 'grouping' etc yourself, so that's not very convenient as well.

How to remove microseconds from matplotlib plot?

I have been through the pylab examples and many axis formatting questions, but am still unable to remove the microseconds from the x-axis in the plot below.
Original code before trying to alter axis/tick properties and its output.
#filenames to be read in
file0 = 'results'
#Get data from file strore in record array
def readIn(fileName):
temp = DataClass()
with open('%s.csv' % fileName) as csvfile:
temp = mlab.csv2rec(csvfile,names = ['date', 'band','lat'])
return temp
#plotting function(position number, x-axis data, y-axis data,
# filename,data type, units, y axis scale)
def iPlot(num,xaxi,yaxi,filename,types, units,scale):
plt.subplot(2,1,num)
plt.plot_date(xaxi,yaxi,'-')
plt.title(filename + "--%s" % types )
plt.ylabel(" %s %s " % (types,units))
plt.ylim(0,scale)
plt.xticks(rotation=20)
# Set plot Parameters and call plot funciton
def plot():
nameB = "Bandwidth"
nameL = "Latency"
unitsB = " (Mbps)"
unitsL = "(ms)"
scaleB = 30
scaleL = 500
iPlot(1,out0['date'],out0['lat'],file0,nameL,unitsL,scaleL)
iPlot(2,out0['date'],out0['band'],file0,nameB,unitsB,scaleB)
def main():
global out0
print "Creating plots..."
out0 = readIn(file0)
plot()
plt.show()
main()
My attempt was to alter the code above by adding:
months = date.MonthLocator() # every month
days = date.DayLocator()
hours = date.HourLocator()
minutes = date.MinuteLocator()
seconds = date.SecondLocator()
def iPlot(num,xaxi,yaxi,filename,types, units,scale):
plt.subplot(2,1,num)
plt.plot_date(xaxi,yaxi,'-')
plt.title(filename + "--%s" % types )
plt.ylabel(" %s %s " % (types,units))
plt.ylim(0,scale)
# Set Locators
ax.xaxis.set_major_locator(days)
ax.xaxis.set_minor_locator(hours)
majorFormatter = date.DateFormatter('%M-%D %H:%M:%S')
ax.xaxis.set_major_formatter(majorFormatter)
ax.autoscale_view()
Is the major formatter I'm setting being over written by a default on? Is there a way to just turn off the microseconds without mucking with the rest of the format? I am fairly unclear on where the microseconds come from as my data contains none.
I've a couple of problems with your code. First, it doesn't work (and I mean it doesn't work even when I make all the mock sample data). Second, it's not really a minimal working example showcasing what's wrong, I can't figure out what your date is, I presume matplotlib.dates? Third I can't see your plot (your full label with the '%M-%D part on it as well)
Now issues I have with that is, I can't figure out how do you even get past the line with ('%M-%D %H:%M:%S') which throws an incorrect syntax my way. (Matplotlib 1.3.1 Win7 both on python2.6.6 and 3.4). I can't see what your ax is, or how does your data look like, all of this can be problematic when it comes to stuff like this. Even having an overly large time span can cause ticks to "overflow" (especially when you try to put hour locators on a range of years, i.e. that throws an error at 7200 ticks I think?)
Meanwhile, here's my min working example that doesn't display the same behavior as yours.
import matplotlib as mpl
import matplotlib.pyplot as plt
import datetime as dt
days = mpl.dates.DayLocator()
hours = mpl.dates.HourLocator()
x = []
for i in range(1, 30):
x.append(dt.datetime(year=2000, month=1, day=i,
hour=int(i/3), minute=i, second=i))
y = []
for i in range(len(x)):
y.append(i)
fig, ax = plt.subplots()
plt.xticks(rotation=45)
ax.plot_date(x, y, "-")
ax.xaxis.set_major_locator(days)
ax.xaxis.set_minor_locator(hours)
majorFormatter = mpl.dates.DateFormatter('%m-%d %H:%M:%S')
ax.xaxis.set_major_formatter(majorFormatter)
ax.autoscale_view()
plt.show()
(This all shouldn't probably be an answer, maybe it'll turn out it helps you, but it's too long to be a comment).
If you're not using subplots, don't use them.
Simply remove any mention of the subplot() or subplots() functions, then to get an axis handle you could use: ax = plt.gca() above any reference to ax.
Maybe something like:
...
# Set Locators
ax = plt.gca()
ax.xaxis.set_major_locator(days)
ax.xaxis.set_minor_locator(hours)
...
Then, you'll get a ValueError: Invalid format string error -- likely because you have %D isn't a valid strftime string formatting directive. (You probably want %m-%d %H:%M:%S.) If you fix that, your plot will display with your formatter.

what is the corresponding matplotlib code of this matlab code

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()

Categories

Resources