Date labels intersecting - python

I'm using Matplotlib to plot data on Ubuntu 15.10. My y-axis has numeric values and my x-axis timestamps.
I'm having the problem that the date labels intersect with each other making it look bad. How do I increase the distance between the x-axis ticks/labels to be evenly spaced still? Since the automatic selection of ticks was bad I'm okay with manually setting the amount of date ticks. Any other solution is appreciated, too.
Besides, I'm using the following DateFormatter:
formatter = DateFormatter('%m/%d/%y')
axis = plt.gca()
axis.xaxis.set_major_formatter(formatter)

You could add the following to your code:
plt.gcf().autofmt_xdate()
Which automatically formats the x axis for you (rotates the labels to something like 30 degrees etc).
You can also manually set the amount of x ticks that show on your x-axis to avoid it getting crowded, by using the following:
max_xticks = 10
xloc = plt.MaxNLocator(max_xticks)
ax.xaxis.set_major_locator(xloc)
I personally use both together as it makes the graph look much nicer when using dates.

You can simply set the locations you want to be labeled:
axis.set_xticks(x[[0, int(len(x)/2), -1]])
where x would be your array of timestamps

Related

Discontinuous axis in Matplotlib with categorical variable on axis

I have a plot of values w/ errorbars with a categorical variable on the X-axis, made using the errorbar method. I have followed the instructions here to create a discontinuity in the X-axis (I'm only showing points with values > or < some absolute threshold).
So far so good, with one slight issue - the axis break ends up being exactly on a data point on each side, which makes it harder to read on the axis, and also, the datapoints themselves end up split in two, which is kind of awkward.
I would like the axis break to instead be between datapoints, something like:
----(last value before break)--/ /--(first value after break)----
Is there a way to do this?
The breakpoints are determined with set_xlim, and I'm not sure if there's a way to do move them off the datapoints with a categorical x-axis...
sort_res_h = sort_res_a[sort_res_a > threshold]
sort_res_l = sort_res_a[sort_res_a < -threshold]
ax0.errorbar(sort_res_a.index, sort_res_a, yerr=chg_dpm_err, fmt='o')
ax1.errorbar(sort_res_a.index, sort_res_a, yerr=chg_dpm_err, fmt='o')
ax0.set_xlim(xmax=sort_res_h.index[-1])
ax1.set_xlim(xmin=sort_res_l.index[0])
I am going to share what I have been able to complete so far, although it is not a flawless solution. But maybe this will help you in any case. I would propose that you set your xaxis limits using the ticks positions, instead of the data. The problem is that if you take ticks as provided by default by matplotlib, sometimes there are more ticks than those that you see (for example there could be ticks before the minimum value in the xaxis or after the maximum). As in your case you seem to be setting the ticks, I think this should work (Replace the way you set your axes limits by this. I only provide the code for the ax0):
# First we get current ticks positions
ax0_xticks_positions = ax0.get_xticks()
# then we get the distance between two ticks
ax0_ticks_distance = ax0_xticks_positions[1] - ax0_xticks_positions[0]
# percentage of tick separation that we want the axis to extend beyond/before the last/first tick
percentage_add = 0.5
# set the xlim to the last tick position plus a percentage of tick distance
ax0.set_xlim(xmax = ax0_xticks_positions[-1] + percentage_add*ax0_ticks_distance)
You can play around with percentage_add until you find a value that suits you. For ax1 you would have to use the first tick:
ax1.set_xlim(xmin = ax1_xticks_positions[0] - percentage_add*ax0_ticks_distance)
The problem of this solution, is if the tick you use to fix the limit is outside the current axis limits. That would make the breakpoint go further than you would expect. To solve that, you can compare the tick position (for example ax0_xticks_positions[-1]) to the applicable axis limit (following the example ax0.get_xlim()[-1]). If the tick position is larger than the limit, you would have to use the second to last tick ax0_xticks_positions[-2]

Matplotlib best practices for automatically spacing out/omitting overlapping tick labels and annotations

I've decided to use Matplotlib in one of my projects which involves having to automatically generate graphs and slapping them onto reports.
Trying to make matplotlib graphs attractive to the eye is something that's been a lot of fun - however there's still just 1 little bit I'm somewhat stuck on!
Right now, I have an issue in cases where there are tonnes of data points. The problem occurs when the x-axis ticks and the annotations overlap!
With few datapoints, the graph is very pretty:
However, in edge cases with very large amount of datapoints, it gets completely messed up:
What I'd basically like Matplotlib to do is to use some kind of determination to make sure that no other annotation element is within range when it applies an annotation. Same concept for the x-axis ticks!
The solutions I've ruled out are things like the x-axis showing every other tick, since in some cases it's possible that even just the first 3 ticks are very close to each other!
You can control your xticks using both set_xticks and set_xticklabels methods knowing that you're controlling just the x-axis. So, your data won't be affected
Here is an example; I've generated a list called days which contains all days in 2019 and the output graph:
from datetime import date, timedelta
import matplotlib.pyplot as plt
sdate = date(2019, 1, 1)
edate = date(2019, 12, 31)
delta = edate - sdate
days = [sdate + timedelta(days=i) for i in range(delta.days+1)]
fig, ax = plt.subplots()
ax.set_xticks(range(365))
ax.set_xticklabels(days)
plt.xticks(rotation=45)
plt.show()
And it generated this graph which looks close enough to yours:
Now, let's see how to use set_xticks and set_xticklabels to handle this issue. All you need to do is to limit the vectors getting passed to these two methods like so:
#skips 30 items in-between
ax.set_xticks(range(0, 365, 30))
ax.set_xticklabels(days[::30])
And this produces this graph:
That's how you can control the ticks of your x-axis. I pretty much believe you can find a similar way to control the labels of your data points.

X-ticks overlapping with Matplotlib

I have a script for plotting big data sets. I have a problem while setting the xticks in my plot. I have tried the following code:
plt.xticks(configDBcomplete.index),max(configDBcomplete.index[-1]),5),data,rotation=90, fontsize= 12
The problem is that I have more than 2000 data points for x and the ticks get overlapped. I want to have ticks at every 5th data point. I have tried using np.arange as:
plt.xticks(np.arange(min(configDBcomplete.index),max(configDBcomplete.index[-1]),5),data,rotation=90, fontsize= 12
but it plots the first 50 data points along the plot and not the corresponding ones. Any idea how to solve this?
Currently you are using the whole data for setting the x-ticklabels. The first argument to the xticks() function is the location of the ticks and the second argument is the tick labels.
You need to use indexing to get every 5th data point (corresponding to the ticks). You can access it using [::5]. So you need to pass data[::5] to your xticks() as
plt.xticks(np.arange(min(configDBcomplete.index),max(configDBcomplete.index[-1]),5),data[::5],rotation=90, fontsize= 12)
You can also use range() as
plt.xticks(range(min(configDBcomplete.index),max(configDBcomplete.index[-1]),5),data[::5],rotation=90, fontsize= 12)

How to force set x ticks on matplotlib, or set datetime type with no year

So I have a function that will take a pandas dataframe and plot it, along with displaying some error metrics, and I also have a function that will take a pandas dataframe with a datetime type index, and take the daily average of the values in the dataframe. The problem is, when I try to plot the daily average, it looks really bad with matplotlib because it plots everyday as a seperate tick on the x axis. I have all this code in a package called Hydrostats, the github reposity source code for the daily average function is here, and the source code for the plotting function is here. The plot for a linear time series is is below.
The Daily Average plot is shown below
As you can see, you can't see any of the x axis ticks because they are all so squished together.
You can set the ticks used for the x axis via ax.set_xticks() and labels via ax.set_xticklabels().
For instance you could just provide that method with a list of dates to use, such as every 20th value of the current pd.DataFrame index (df.index[::20]) and then set the formatting of the date string as below.
# Get the current axis
ax = plt.gca()
# Only label every 20th value
ticks_to_use = df.index[::20]
# Set format of labels (note year not excluded as requested)
labels = [ i.strftime("%-H:%M") for i in ticks_to_use ]
# Now set the ticks and labels
ax.set_xticks(ticks_to_use)
ax.set_xticklabels(labels)
Notes
If labels still overlap, you could also rotate the them by passing the rotatation argument (e.g. ax.set_xticklabels(labels, rotation=45)).
There is a useful reference for time string formats here: http://strftime.org.
I faced similar issue with my plot
Matplotlib automatically handles timestamps on axes, but only when they are in timestamp format. Timestamps in index were in string format, so I changed read_csv to
pd.read_csv(file_path, index_col=[0], parse_dates=True)
Try changing the index to timestamp format. This solved the problem for me hope it does the same for you.

how to set unequal x axis intervals in Matplotlib

Now I just simply use plt.plot(x,y1,'b.-') to plot a figure, but it turns out so many data are displayed between 0 to 10 on the x axis, so I want to set x axis like this 0,1,5,10,100,1000,100000
thus, the massive data between 0 to 10 can be more spread out.
How can I do it in Python, I am using Matplotlib
0,1,5,10,100,1000,100000?
If you can live with (0.01, 0.1,), 1, 10, 100, 1000, 10000, 100000,… - then change the xscale to log:
plt.xscale('log')
See the accepted answer to the question How do I convert (or scale) axis values and redefine the tick frequency in matplotlib? Essentially, the matplotlib.pyplot.xticks command can be used to control to location and labels of the tick marks.
However, your data will still be plotted on a linear scale, so this won't strecth out the data between 0 and 10. You will need to use a different axis scaling to do this, using, for example, set_xscale.

Categories