I'm trying to plot electricity usage against time. I'm using this script:
from datetime import datetime
import matplotlib.pyplot as plt
import numpy as np
timelist = []
valuelist = []
# Logic that populates timelist and valuelist
timeaxis = np.array(timelist)
valueaxis = np.array(valuelist)
plt.plot(timeaxis, valueaxis, 'r-')
plt.savefig('elec_use.png', bbox_inches='tight')
plt.show()
The x-axis labels in the plot I get running the program above is all crammed into the length of the graph.
I tried rotating the labels by adding xticks like so:
plt.xticks(timeaxis, rotation=90)
This causes the labels to get trimmed.
How can I fix the problem? I have tried adding plt.gcf().subplots_adjust(bottom=0.25) but this does not fix the labels, it merely increases the real estate to the bottom of the graph. I want the x-axis labels to say Jun 02 2016 or simply Jun 02. I don't mind the graph being wide. Thanks in advance for any help.
You could use gcf().autofmt_xdate to format the x-axis nicely. And for the date string format, you could use matplotlib.dates.DateFormatter. It will be something like below:
So you code will be something like this:
fig, ax = plt.subplots(1)
timelist = []
valuelist = []
# Logic that populates timelist and valuelist
timeaxis = np.array(timelist)
valueaxis = np.array(valuelist)
ax.plot(timeaxis, valueaxis, 'r-')
# rotate and align the tick labels so they look better
fig.autofmt_xdate()
# use a more precise date string for the x axis locations in the
# toolbar
import matplotlib.dates as mdates
ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d')
plt.savefig('elec_use.png', bbox_inches='tight')
plt.show()
Related
I'm trying to create a simple stacked area chart. Here is my code:
x = [1990,1995,2000,2005,2010]
y = [df['a'],df['b'],df['c']]
...
plt.stackplot(x,y, labels=['a,b,c'], ...)
...
plt.show()
However, x-axis on the graph created goes up in intervals of 2.5 so it looks like this:
1990.0, 1992.5, 1995.0....
How do I change it so that the graph created on the x-axis goes up in intervals of 5?
You can create a subplot and set the major and minor locators of x axis like this:
import matplotlib.pyplot as plt
from matplotlib.ticker import (AutoMinorLocator, MultipleLocator)
fig, ax = plt.subplots()
ax.set_xlim(1990, 2015)
ax.xaxis.set_major_locator(MultipleLocator(5))
ax.xaxis.set_minor_locator(AutoMinorLocator(1))
plt.stackplot(x,y, labels=['a,b,c'], ...)
plt.show()
I'm having with my xticks on my plot.
I have an hh:mm:ss format data on my x vector, but the xticks label are just eating up space on my x vector.
I'm trying to use only major xticks which would show the x vector label on 5 minutes basis.
but, the label not showing correctly.
right now this is the code that i wrote:
# -*- coding: utf-8 -*-
from os import listdir
from os.path import isfile, join
import pandas as pd
from Common import common as comm
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt
fp = FontProperties(fname="../templates/fonts/msgothic.ttc")
config = comm.configRead()
commonConf = comm.getCommonConfig(config)
peopleBhvConf = comm.getPeopleBhvConf(config)
files = [f for f in listdir(commonConf['resultFilePath']) if isfile(join(commonConf['resultFilePath'], f))]
waitTimeGraphInput = [s for s in files if peopleBhvConf['resultFileName'] in s]
waitTimeGraphFile = commonConf['inputFilePath'] + waitTimeGraphInput[0]
waitTimeGraph = pd.read_csv(waitTimeGraphFile)
# Create data
N = len(waitTimeGraph.index)
x = waitTimeGraph['ホール入時間']
y = waitTimeGraph['滞留時間(出-入sec)']
xTicks = pd.date_range(min(x), max(x), freq="5min")
fig, ax = plt.subplots()
ax.scatter(x, y)
ax.set_xticklabels(xTicks, rotation='vertical')
plt.axhline(y=100, xmin=min(x), xmax=max(x), linewidth=2, color = 'red')
plt.setp(ax.get_xticklabels(), visible=True, rotation=30, ha='right')
plt.savefig(commonConf['resultFilePath'] + '1人1人の待ち時間分布.png')
plt.show()
and this is the result:
as you can see, the labels are still being printed only on the front of my plotting.
I'm expecting it would being printed on my major xticks position only.
The problem
If I understand correctly what is going on, xTicks array is shorter than x, am I right? If so, this is the issue.
I don't see in your code where you set the tick position, but I guess you are showing all of them, one per each element of x. But since you set the tick labels manually with ax.set_xticklabels(xTicks, rotation='vertical'), matplotlib has no way to know at which ticks those labels should go, hence it fills the first available ticks, and if there are more ticks, they are left without labels.
If you were able to read the labes, you would see that the written dates do not correspond to the labelled positions on the axis.
How to fix it
The general rule, be sure when you set tick labels manually, that the array containing the label has the same length of the array of the ticks. Add empty strings for the ticks where you do not want to have a labels.
However, since you spoke of major ticks and minor ticks, I show you how to set them in your case, where you have dates on the x axis.
Drop the xTicks, is not needed. Don't set the tick labels manually, hence don't use ax.set_xticklabels().
Your code should be:
fig, ax = plt.subplots()
ax.scatter(x, y)
plt.axhline(y=100, xmin=min(x), xmax=max(x), linewidth=2, color = 'red')
ax.xaxis.set_major_locator(MinuteLocator(interval=5))
ax.xaxis.set_minor_locator(MinuteLocator(interval=1))
ax.xaxis.set_major_formatter(DateFormatter('%H:%M:%S'))
plt.setp(ax.get_xticklabels(), visible=True, rotation=30, ha='right')
plt.savefig(commonConf['resultFilePath'] + '1人1人の待ち時間分布.png')
Remember to import the locator and formatter:
from matplotlib.dates import MinuteLocator, DateFormatter
A brief explanation: MinuteLocator finds each minute interval in your x axis and place a tick. The parameter interval allows you to set a tick each N minutes. So in the above code a major tick is placed each 5 minutes, a minor tick each minute.
DateFormatter simply format the date accordingly to the string (here I choose the format hour, minute, second). Note that no formatter has been set for minor ticks, so by default matplotlib uses the null formatter (no labels for minor ticks).
Here the documentation on the dates module of matplotlib.
To give you an idea of the result, here is an image I created using the code above with random data (just look at the x axis).
I have this following code in order to generate scatterplots
import matplotlib.pyplot as plt
line = plt.figure()
plt.plot(xvalue, yvalue)
plt.grid(True)
plt.savefig("test.png")
plt.show()
and here is the screenshot of the plot:
I am just wondering if i could change the x-axis labels into strings. I have stored all the labels in
xlabel = ['2015/4/1', '2015/4/11', '2015/4/12', '2015/4/18', '2015/4/19'...]
Is there any function for matplotlib so that i could set x-axis labels to the values in "xlabel"?
many thx!
ALso my labels are overlapped, anything i could do to fix this problem? thx!
Here is my answer. You target was to plot the datetime as xticklabel.
I always do something like this. Code like this:
## For example, I have 9 daily value during 2013-04-01 to 2014-04-10
start = datetime.datetime.strptime("01-04-2013", "%d-%m-%Y")
end = datetime.datetime.strptime("10-04-2013", "%d-%m-%Y")
date = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]
plt.figure(figsize=(12,4))
## y is the data I want to plot
ind = np.arange(len(y))
ax=plt.subplot()
plt.plot(ind,y,lw = 3)
k = []
for i in range(0,len(ind),1):
k.append(str(date[i])[0:10])
plt.xticks(ind,k,rotation=65)
Update
To solve the overlap problem, I recommend the code below:
for label in ax.xaxis.get_ticklabels()[::2]:
label.set_visible(False)
For daily value in a month, you can get a figure like this:
Do:
plt.xticks(xs, labels)
Where xs is a list of the positions for the ticks, and labels is the list of labels.
I'm building a Seaborn barplot. The x-axis are dates, and the y-axis are integers.
I'd like to format major/minor ticks for the dates. I'd like Mondays' ticks to be bold and a different color (ie, "major ticks"), with the rest of the week less bold.
I have not been able to get major and minor tick formatting on the x-axis to work with Seaborn barplots. I'm stumped, and thus turning here for help.
I'm starting with the stackoverflow example that answered this question: Pandas timeseries plot setting x-axis major and minor ticks and labels
If I do a simple modification it to use a Seaborn barplot and I lose my X-axis ticks:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as dates
import seaborn as sns
idx = pd.date_range('2011-05-01', '2011-07-01')
s = pd.Series(np.random.randn(len(idx)), index=idx)
###########################################
## Swap out these two lines of code:
#fig, ax = plt.subplots()
#ax.plot_date(idx.to_pydatetime(), s, 'v-')
## with this one
ax = sns.barplot(idx.to_pydatetime(), s)
###########################################
ax.xaxis.set_minor_locator(dates.WeekdayLocator(byweekday=(1),
interval=1))
ax.xaxis.set_minor_formatter(dates.DateFormatter('%d\n%a'))
ax.xaxis.grid(True, which="minor")
ax.yaxis.grid()
ax.xaxis.set_major_locator(dates.MonthLocator())
ax.xaxis.set_major_formatter(dates.DateFormatter('\n\n\n%b\n%Y'))
plt.tight_layout()
## save the result to a png instead of plotting to screen:
myFigure = plt.gcf()
myFigure.autofmt_xdate()
myFigure.set_size_inches(11,3.8)
plt.title('Example Chart', loc='center')
plt.savefig('/tmp/chartexample.png', format='png', bbox_inches='tight')
I've tried a variety of approaches but something in Seaborn seems to be overriding or undoing any attempts at major and minor axis formatting that I've managed to cook up yet beyond some simple styling for all ticks when I use set_xticklabels().
I can sort of get formatting on just the major ticks by using MultipleLocator(), but I can't get any formatting on the minor ticks.
I've also experimented with myFigure.autofmt_xdate() to see if it would help, but it doesn't seem to like mixed major & minor ticks on the same axis either.
I came across this while trying to solve the same problem. Based on the useful pointer from #mwaskom (that categorical plots like boxplots lose their structure and just become date-named categories) and ended up doing the location and formatting in Python as so:
from datetime import datetime
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as dates
import seaborn as sns
idx = pd.date_range('2011-05-01', '2011-07-01')
s = pd.Series(np.random.randn(len(idx)), index=idx)
fig, ax = plt.subplots(figsize = (12,6))
ax = sns.barplot(idx.to_pydatetime(), s, ax = ax)
major_ticks = []
major_tick_labels = []
minor_ticks = []
minor_tick_labels = []
for loc, label in zip(ax.get_xticks(), ax.get_xticklabels()):
when = datetime.strptime(label.get_text(), '%Y-%m-%d %H:%M:%S')
if when.day == 1:
major_ticks.append(loc)
major_tick_labels.append(when.strftime("\n\n\n%b\n%Y"))
else:
minor_ticks.append(loc)
if when.weekday() == 0:
minor_tick_labels.append(when.strftime("%d\n%a"))
else:
minor_tick_labels.append(when.strftime("%d"))
ax.set_xticks(major_ticks)
ax.set_xticklabels(major_tick_labels)
ax.set_xticks(minor_ticks, minor=True)
ax.set_xticklabels(minor_tick_labels, minor=True)
Of course, you don't have to set the ticks based on parsing the labels which were installed from the data, if it's easier to start with the source data and just keep the indices aligned, but I prefer to have a single source of truth.
You can also mess with font weight, rotation, etc, on individual labels by getting the Text objects for the relevant label and calling set_ methods on it.
This seems like it should be easy - but I can't see how to do it:
I have a plot with time on the X-axis. I want to set two sets of ticks, minor ticks showing the hour of the day and major ticks showing the day/month. So I do this:
# set date ticks to something sensible:
xax = ax.get_xaxis()
xax.set_major_locator(dates.DayLocator())
xax.set_major_formatter(dates.DateFormatter('%d/%b'))
xax.set_minor_locator(dates.HourLocator(byhour=range(0,24,3)))
xax.set_minor_formatter(dates.DateFormatter('%H'))
This labels the ticks ok, but the major tick labels (day/month) are drawn on top of the minor tick labels:
How do I force the major tick labels to get plotted below the minor ones? I tried putting newline escape characters (\n) in the DateFormatter, but it is a poor solution as the vertical spacing is not quite right.
Any advice would be appreciated!
You can use axis method set_tick_params() with the keyword pad. Compare following example.
import datetime
import random
import matplotlib.pyplot as plt
import matplotlib.dates as dates
# make up some data
x = [datetime.datetime.now() + datetime.timedelta(hours=i) for i in range(100)]
y = [i+random.gauss(0,1) for i,_ in enumerate(x)]
# plot
plt.plot(x,y)
# beautify the x-labels
plt.gcf().autofmt_xdate()
ax = plt.gca()
# set date ticks to something sensible:
xax = ax.get_xaxis()
xax.set_major_locator(dates.DayLocator())
xax.set_major_formatter(dates.DateFormatter('%d/%b'))
xax.set_minor_locator(dates.HourLocator(byhour=range(0,24,3)))
xax.set_minor_formatter(dates.DateFormatter('%H'))
xax.set_tick_params(which='major', pad=15)
plt.show()
PS: This example is borrowed from moooeeeep
Here's how the above snippet would render: