Python - Set limits at Scatter matrix from pandas - python

I am doing a scatter matrix plot, but when I try to set the xlim and ylim, the diagonal terms of the plot get wrecked.
My code is:
axS=scatter_matrix(dfS, alpha=0.5, figsize=(10, 10),
diagonal='kde',color="black")
for i in range(5):
for j in range(5):
axS[i,j].set_xlim(0.0,1.0)
axS[i,j].set_ylim(0.0,1.0)
plt.suptitle('Separable')
plt.show()
Without the limits (i.e. without the 'for i in range...'), the image I get is
Notice that the x and y limits are not the same in all the subplots.
Now, if I add the limits, the image I get is
Now I get to scale the same subplot to the same limits. However, neither the limit labels are right nor the diagonal plots.
Is there another way of setting the limits that won't mess the whole picture?
Thank you.

The problem is that you actually don't want the y axis of your KDE plots to have the range (0,1).
Try this:
axS=scatter_matrix(dfS, alpha=0.5, figsize=(10, 10),
diagonal='kde',color="black")
for i in range(5):
for j in range(5):
axS[i,j].set_xlim(0.0,1.0)
if i != j:
axS[i,j].set_ylim(0.0,1.0)
plt.suptitle('Separable')
plt.show()

Related

Matplotlib not showing correct and desired x-axis

I have a barplot I am trying to plot without the x-axis ticks overlapping. I have settled on an angle of 45 degrees, and a max. number of ticks of 50, as this is about the max. of what can be shown without overlapping (IF the ticks are tilted at 45 degrees).
However, in my attempts I ran into the problem of Matplotlib not setting the x-axis to what I desire, whatever I try. I need to plot multiple datasets, for all of which the time runs from -15.8 through somewhere around 1200-1800.
I tried several solutions I found online, but all to no avail. The code below does not work, as it does not show the correct ticks. The range stops well before the last number in the timepoints list.
import numpy as np
from matplotlib import pyplot as plt
# Mock data
timepoints = list(np.arange(-15.8, 1276.2, 4))
patient_counts = np.random.randint(300, 600, len(timepoints))
x_tick_pos = [i + 0.5 for i in range(len(timepoints))]
# Plot barplot
fig, ax = plt.subplots(figsize=(16, 10))
ax.bar(x_tick_pos, patient_counts, align='center', width=1.0)
# Set x axis ticks
ax.set_xticklabels(timepoints, rotation=45)
ax.locator_params(axis='x', nbins=20)
plt.show()
Clearly, the x-axis does not come close to the expected values.
EDIT
To expand, this question is a follow-up from this thread. The code based on the answer in that question is as follows
# Plot barplot
fig, ax = plt.subplots(figsize=(16, 10))
ax.bar(x_tick_pos, patient_counts, align='center', width=1.0)
# Set x axis ticks
ax.set_xticks(x_tick_pos)
ax.set_xticklabels(x_ticks, rotation=45)
This appears to set the right x-ticks, except they overlap a lot- hence why I want only a max of 50 ticks to show:
This might be a simple case of fixing the x_tick_pos list expression. In your mock example, if we print them out ...
x_tick_pos = [i + 0.5 for i in range(len(timepoints))]
print(x_tick_pos[:5], x_tick_pos[-5:])
... we get what your figure reflects:
[0.5, 1.5, 2.5, 3.5, 4.5] [318.5, 319.5, 320.5, 321.5, 322.5]
Changing the assignment to
x_tick_pos = [i + 0.5 for i timepoints]
would appear to give the expected ticks.
The issue is that the positioning of the ticks is written so that they line up with another graph above this one, as per this post.
There are two solutions:
forget about positioning the ticks relative to another graph, in case this bar plot is plotted in a standalone fashion
resetting the ticks after plotting the bar plot to give them correct labels:
# Plot barplot
fig, ax = plt.subplots(figsize=(16, 10))
ax.bar(x_tick_pos, patient_counts, align='center', width=1.0)
# Set x axis ticks
ticks_step = int(len(missings_df.index) / 50) # 50 here is the max. nr of ticks
x_ticks = [missings_df.index[i] for i in range(0, len(missings_df.index), int(len(missings_df)/50))]
x_tick_pos = [i + 0.5 for i in range(0, len(missings_df.index), int(len(missings_df)/50))]
ax.set_xticks(x_tick_pos)
ax.set_xticklabels(x_ticks, rotation=45)
This correctly plots the x-axis:

Is there a way to make the legend in matplotlib fit better within the plot?

I need to plot a line plot with multiple lines.
Due to a large number of lines, the legend gets so large that it hides some of the lines, is there a way to automatically set the y ticks so that there will be enough room in the plot for the legend to fit properly?
Example plot:
Thank you.
You can adjust the xlim and the dict prop, for example
x = np.linspace(1,10,10)
y = x + np.random.rand(10,10)
labels = list('abcdefghij')
fig,ax = plt.subplots(figsize=(12,6))
ax.plot(x,y,'-o')
ax.set_xlim(1,11)
ax.legend(labels,loc='upper right', prop={'size': 10})
Tuning ax.set_xlim to leave enough space for the legend, and the size of the legend is controlled by prop={'size':10}

ax.locator_params(nbins=k) does not work in matplotlib

I have this simple piece of code where I try to plot simple graph while limiting number of x ticks. There are hundreds of items in iters variable and if they get plotted it would just create one fat black line.
However, ax.locator_params does not work and the number of ticks aren't reduced.
I have tried setting it on plt object, but no help.
I also tried specifying x and y axes in locator_params, but no help as well.
Finally, I have tried moving ax.locator_params before and after ax.plot, but nothing seemed to help. I am completely out of ideas.
fig, ax = plt.subplots(1, 1, figsize=(20,10))
ax.locator_params(tight=True, nbins=4)
ax.plot(iters, vals)
plt.xticks(rotation=30)
plt.show()
locator_params() with nbins= is only supported for numerical axes where the tick positions are set via MaxNLocator.
To get the same effect with text ticks, the current ticks can be stored in a list (get_xticks) and then be replaced by a subset. Note that changes to ticks (and to limits) should be called after the main plot functions.
xticks = ax.get_xticks()
ax.set_xticks(xticks[::len(xticks) // 4]) # set new tick positions
ax.tick_params(axis='x', rotation=30) # set tick rotation
ax.margins(x=0) # set tight margins

Using AxesGrid to plot data with different x and y range in a square [duplicate]

I want to make x and y axes be of equal lengths (i.e the plot minus the legend should be square ). I wish to plot the legend outside (I have already been able to put legend outside the box). The span of x axis in the data (x_max - x_min) is not the same as the span of y axis in the data (y_max - y_min).
This is the relevant part of the code that I have at the moment:
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize=15 )
plt.axis('equal')
plt.tight_layout()
The following link is an example of an output plot that I am getting : plot
How can I do this?
Would plt.axis('scaled') be what you're after? That would produce a square plot, if the data limits are of equal difference.
If they are not, you could get a square plot by setting the aspect of the axes to the ratio of xlimits and ylimits.
import numpy as np
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1,2)
ax1.plot([-2.5, 2.5], [-4,13], "s-")
ax1.axis("scaled")
ax2.plot([-2.5, 2.5], [-4,13], "s-")
ax2.set_aspect(np.diff(ax2.get_xlim())/np.diff(ax2.get_ylim()))
plt.show()
One option you have to is manually set the limits, assuming that you know the size of your dataset.
axes = plt.gca()
axes.set_xlim([xmin,xmax])
axes.set_ylim([ymin,ymax])
A better option would be to iterate through your data to find the maximum x- and y-coordinates, take the greater of those two numbers, add a little bit more to that value to act as a buffer, and set xmax and ymax to that new value. You can use a similar method to set xmin and ymin: instead of finding the maximums, find the minimums.
To put the legend outside of the plot, I would look at this question: How to put the legend out of the plot

Second y scale repeating axis ticks

I have some code below which plots 3 sets of random numbers by adding them to a plot (simulating real world data gathered from say a temperature sensor).
I am attempting to make 2 scales on the same plot.
Here, y2List is negative and this is the data set that I would like to create the second axis for. I figured out how to do this using other questions on here.
The problem is that when each data point is added, the second y axis ticks are shown again so that the second y axis is very crowded with numbers. I can get round this by setting a limit on the second y axis, which produces an image like this:
The second y axis is slightly darker than the others, and this is because python is plotting the same numbers on top of the existing ones after each point is plotted (I can tell because the numbers get darker as each point is plotted)
My question... is there a way to make the second y axis only plot the second scale only once? This is obviously just to make the plot aesthetically pleasing but every little helps!
My code is below:
plt.ion() # enable interactivity
def makeFig():
ax.plot(xList, yList, color='blue', label='something1' if x == 0 else '')
ax.plot(xList, y1List, color='red', label='something2' if x == 0 else '')
ax2 = ax.twinx()
ax2.plot(xList, y2List, color='orange', label='something else' if x == 0 else '')
ax2.set_ylim(-20,0)
xList=list()
yList=list()
y1List=list()
y2List=list()
x=0
while x<11:
fig1=plt.figure(1)
ax = fig1.add_subplot(111)
x_1 = datetime.datetime.now()
date_formatter = DateFormatter('%H:%M:%S')
y=np.random.random()
y1=np.random.random() *3
y2=np.random.random() *(-13)
xList.append(x_1)
yList.append(y)
y1List.append(y1)
y2List.append(y2)
makeFig()
plt.gcf().autofmt_xdate()
ax = plt.gca()
ax.xaxis.set_major_formatter(date_formatter)
max_xticks = 10
xloc = plt.MaxNLocator(max_xticks)
ax.xaxis.set_major_locator(xloc)
plt.get_current_fig_manager().window.wm_geometry("940x700+5+0")
plt.draw()
plt.legend(loc=2, bbox_to_anchor=(1, 0.5), prop={'size':10})
x+=1
plt.pause(0.5)
You should move the creation of the figure and the twin axes outside of your loop. They only need to be done once.
Specifically, move fig1=plt.figure(1), ax = fig1.add_subplot(111) and ax2 = ax.twinx() outside the loop.

Categories