Matplotlib many subplots xtick labels intercepting - python

I'm plotting many subplots in the same figure. I encounter the problem that xtick labels intercept one with each other. I do not want any space between the subplots.
Here is an example:
In particular I would like xtick labels not to be above/below the green lines, just like it happens at the points indicated with red squares.
One idea I had so far was, in a case where my max=4 and min=0, I'd draw tick labels for 1 2 and 3 at their respective locations, e.g 1,2,3. Then I'd draw 4 at the position 3.8 and 0 at the position 0.2. Any ideas?
thanks!

Not exactly what you asked for, but a quick solution is to set the alignment parameter:
pylab.xticks(..., horizontalalignment='left')
pylab.yticks(..., verticalalignment='bottom')
This will apply to all ticks.

This is how I would do it:
axScatter.set_xticks([0, 1, 2, 3, 4 ,5 ,6])
axScatter.set_yticks([-8, -6, -4, -2, 0, 2, 4, 6])
And you can use:
axScatter.yaxis.set_major_formatter(nullfmt)
To make the y axis labels disappear for the top right and bottom right plots.

The whole plt.figure routine should look something like this:
fig = plt.figure()
axplot_topleft = fig.add_subplot(2,2,1)
axplot_topleft.xaxis.set_major_formatter(nullfmt)
axplot_topleft.set_yticks([-8, -6, -4, -2, 0, 2, 4, 6])
axplot_topright = fig.add_subplot(2,2,2)
axplot_topright.xaxis.set_major_formatter(nullfmt)
axplot_topright.yaxis.set_major_formatter(nullfmt)
axplot_bottomleft = fig.add_subplot(2,2,3)
axplot_bottomleft.set_xticks([0, 1, 2, 3, 4 ,5 ,6])
axplot_bottomleft.set_yticks([-8, -6, -4, -2, 0, 2, 4, 6])
axplot_bottomright = fig.add_subplot(2,2,4)
axplot_bottomright.yaxis.set_major_formatter(nullfmt)
axplot_bottomright.set_xticks([0, 1, 2, 3, 4 ,5 ,6])

Related

How to plot scatter graph with SCATTER fill_between in Python?

I am a manufacturing engineer, very new to Python and Matplotlib. Currently, I am trying to plot a scatter time graph, where for every single record, I have the data (read from a sensor) and upper and lower limits for that data that will stop the tool if data is not between them.
So for a simple set of data like this:
time = [1, 2, 3, 7, 8, 9, 10]*
data = [5, 6, 5, 5, 6, 7, 8]
lower_limit = [4, 4, 5, 5, 5, 5, 5]
upper_limit = [6, 6, 6, 7, 7, 7, 7]
When the tool is not working, nothing will be recorded, hence a gap b/w 3 & 7 in time records.
The desired graph would look like this:
A few rules that I am trying to stick to:
All three graphs (data, upper_limit, and lower_limit) are required to be scattered points and not lines, with the x-axis (time) being shared among them. - required.
A green highlight that fills between upper and lower limits, considering only the two points with the same time for each highlight. - highly recommended.
(I tried matplotlib.fill_between, but it creates a polygon between trend lines, rather than straight vertical lines between matching pairs of L.L. & U.L. dots. Therefore, it won't be accurate, and it will fill up the gap b/w times 3s and 7s, which is not desired. Also, I tried to use matplot.bar for limits along the scatter plot for the 'data', but I was not able to set a minimum = lower_limit for the bars.)
When the value of data is not equal to or between the limits, the representing dot should appear in red, rather than the original color. -highly recommended.
So, with all of that in mind, and thousands of records per day, a regular graph, for a 24hr time span, should look like the following: (notice the gap due to possible lack of records in a time span, as well as vertical green lines, for the limits.)
Thanks for your time and help!
This is a version using numpys masking and matplotlibs errorbar
import matplotlib.pyplot as plt
import numpy as np
time = np.array( [0, 1, 2, 3, 7, 8, 9, 10] )
data = np.array([2, 5, 6, 5, 5, 6, 7, 8] )
lower = np.array([4, 4, 4, 5, 5, 5, 5, 5] )
upper = np.array([6, 6, 6, 6, 7, 7, 7, 7] )
nn = len( lower )
delta = upper - lower
### creating masks
inside = ( ( upper - data ) >= 0 ) & ( ( data - lower ) >= 0 )
outside = np.logical_not( inside )
fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.errorbar( time, lower, yerr=( nn*[0], delta), ls='', ecolor="#00C023" )
ax.scatter( time[ inside ], data[ inside ], c='k' )
ax.scatter( time[ outside ], data[ outside ], c='r' )
plt.show()
Something like this should work, plotting each component separately:
time = [1, 2, 3, 7, 8, 9, 10]
data = [5, 6, 5, 5, 6, 7, 8]
lower_limit = [4, 4, 5, 5, 5, 5, 5]
upper_limit = [6, 6, 6, 7, 7, 7, 7]
# put data into dataframe and identify which points are out of range (not between the lower and upper limit)
df = pd.DataFrame({'time': time, 'data': data, 'll': lower_limit, 'ul': upper_limit})
df.loc[:, 'in_range'] = 0
df.loc[((df['data'] >= df['ll']) & (df['data'] <= df['ul'])), 'in_range'] = 1
# make the plot
fig, ax = plt.subplots()
# plot lower-limit and upper-limit points
plt.scatter(df['time'], df['ll'], c='green')
plt.scatter(df['time'], df['ul'], c='green')
# plot data points in range
plt.scatter(df.loc[df['in_range']==1, :]['time'], df.loc[df['in_range']==1, :]['data'], c='black')
# plot data points out of range (in red)
plt.scatter(df.loc[df['in_range']==0, :]['time'], df.loc[df['in_range']==0, :]['data'], c='red')
# plot lines between lower limit and upper limit
plt.plot((df['time'],df['time']),([i for i in df['ll']], [j for j in df['ul']]), c='lightgreen')

matplotlib discrete bin plot

With discrete bin plot I refer to a type of plot which does not connect the points with a straight line, but uses a constant value for all the region which is closest to each point.
This is an example of this type of plot using PDL and PGPLOT.
pdl> use PDL::Graphics::PGPLOT;dev('/xs');$x=rint(grandom(20)*10);print $x;bin($x);hold;points($x,{color=>'red'})
[-19 -3 4 7 -8 -2 9 15 4 7 1 -14 -4 -4 11 6 -15 -13 2 1]Graphics on HOLD
This type of plot is sometimes useful.
I am interested in knowing a way to display this type of plot in matplotlib. I could not find a specific function.
Alternative ways to do it in matplotlib would also be useful as well as perhaps other packages for plotting in python. Thank you very much!
This is called a step plot in matplotlib:
import matplotlib.pyplot as plt
y = [-19, -3, 4, 7, -8, -2, 9, 15, 4, 7, 1, -14, -4, -4, 11, 6, -15, -13, 2, 1]
plt.step(range(len(y)), y, 'o-', where='mid')

Matplotlib's bar chart displays uneven bars

If we look at this code and x,y data,
rects1 = plt.bar([0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,1],[1, 2, 4, 10, 5, 9, 1,4, 9, 9],edgecolor='black')
plt.xlabel('Sample Mean')
plt.ylabel('Probability')
this displays the following graph
I can not understand how the x values go beyond 1 and even takes negative values. Also, why do the bars have different widths?
The problem is that your x-values are separated by a spacing of 0.1 and the default bar width is 1 so you see overlapping bars. The solution is to define the bar width. In your case, a bar width smaller than 0.1 will work perfectly fine. For instance, you can use width=0.05 and you will get the following graph.
Why negative?: The bars are by default centered at 0, 1, 2, 3 and so on. So your first bar in the question was drawn centered at 0 and had a width of 1. That's why it was spanning from -0.5 to +0.5.
rects1 = plt.bar([0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,1],
[1, 2, 4, 10, 5, 9, 1,4, 9, 9], width=0.05, edgecolor='black')
plt.xlabel('Sample Mean')
plt.ylabel('Probability')
If you don't want bars at x<0: You can align your bars to the right by passing argument align='edge.
rects1 = plt.bar([0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,1],
[1, 2, 4, 10, 5, 9, 1,4, 9, 9], width=0.05, align='edge',
edgecolor='black')

How to draw a map using python

I want to draw a map using python, not really a map with full information, just a get together of a series of small shapes to reflect land use.
The data is like below
1 2 2 3 3 2
2 3 3 1 1 2
1 1 1 1 3 3
3 3 3 3 4 1
Each number represents one land use type. and their positions in the matrix are their coordinates.
I used VBA to do that before, the whole map consists many small square shapes representing land use, but since the data was so large, it took a long time to generate the map, also delete the map.
My question are :
I wonder in python, is there any more fast way to generate this kind of map, as a whole, not a series of shapes, i think that would be faster??
I have tried using contourf, as below, but it says "out of bounds for axis 1", but actually, I printed X,Y and cordi, they have the same shape, why still out of bounds?
y = np.arange(0, 4 , 1)
x = np.arange(0, 6 , 1)
X,Y = np.meshgrid(x,y)
# cordi is the matrix containing all the data
# pyplot is imported before
plt.contourf(X,Y, Cordi[X,Y], 8, alpha=.75, cmap='jet')
Thank you very much for answering!
What about using imshow, which produces something like a heatmap. Here is an example:
In [1]: import numpy as np
In [2]: import matplotlib.pyplot as plt
In [3]: coord_data = np.array([[1, 2, 2, 3, 3, 2], [2, 3, 3, 1, 1, 2],
[1, 1, 1, 1, 3, 3], [3, 3, 3, 3, 4, 1]])
In [4]: map = plt.imshow(coord_data)
In [5]: plt.colorbar(map)
Out[5]: <matplotlib.colorbar.Colorbar instance at 0x7f3df2559c20>
In [6]: plt.show()
You can specify the interpolation level using the interpolation keyword (examples), and the colors used using the cmap keyword (example colormaps).
If you don't use interpolation='nearest', neighboring data points with the same value will look like contours.

Matplotlib skips data -

I am trying to plot a bar chart using matplotlib. My issue is I have some "0" values in the list and matplotlib eats some of these values, how do I make sure it always plots all the values.
Here is the code:
counter_trim = counter[6:(len(counter)-6)]
pos = np.arange(len(Test_names[6:]))
width =.65
ax = plt.axes()
ax.set_ylabel('Number of failures')
ax.set_title('Distribution of ABT failures')
ax.set_xticks(pos + (width/2))
xtickNames= ax.set_xticklabels(Test_names[6:])
plt.setp(xtickNames, rotation=90, fontsize=10)
plt.bar(pos, counter_trim, width, color='b')
plt.tight_layout()
print 'Distribution plot can be found here:' +image_filepath
plt.savefig(image_filepath)
To make things more clear,
here are the values of pos : [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
and values of counter_trim: [0, 0, 0, 1, 17, 6, 0, 14, 32, 11, 0, 0, 2, 0, 1, 0, 0]
The code above skips first 3 and last 2 zeros, but rest everything is same!
Any ideas how to avoid this?
try out something like this:
plt.xlim(0, len(counter_trim))
as he is drawing no actual bar I guess the plot command omits these entries. I could not try it with your labels on x as they are not with the text but this worked with a standard axis.

Categories

Resources