Scaling in matplotlib.pyplot? - python

I am generating planar coordinates within the range (x,y) in [0,500]x[0,500]. When using matplotlib.pyplot to visualize them, the axes only show the part that contains already generated points. How can I scale the axes so that they correspond to [0,500]x[0,500]?
This is what I have for now:

Use ax.set_xlim([0, 500]) and set_ylim

You can set the row and column size of the plot area by the following..
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (10,5)
But the figure.figsize accepts the parameter in inches, so if you need it to be in other units, then adjust the parameter by converting from inches to your desired unit.
Hope this helps.

Related

Python matplotlib contourf plot

I have one questions about matplotlib and contourf.
I am using the last version of matplotlib with python3.7. Basically I have to matrix I want to plot on the same contour plot but using different colormap. One important aspect is that, for instance, if we have zero matrixA and matrixB with shape=(10,10) then the positions in which matrixA is different of zero are the positions in which matrixB are non-zero, and viceversa.
In other words I want to plot in different colors two different mask.
Thanks for your time.
Edited:
I add an example here
import numpy
import matplotlib.pyplot as plt
matrixA=numpy.random.randn(10,10).reshape(100,)
matrixB=numpy.random.randn(10,10).reshape(100,)
mask=numpy.random.uniform(10,10)
mask=mask.reshape(100,)
indexA=numpy.where(mask[mask>0.5])[0]
indexB=numpy.where(mask[mask<=0.5])[0]
matrixA_masked=numpy.zeros(100,)
matrixB_masked=numpy.zeros(100,)
matrixA_masked[indexA]=matrixA[indexA]
matrixB_masked[indexB]=matrixB[indexB]
matrixA_masked=matrixA_masked.reshape(100,100)
matrixB_masked=matrixB_masked.reshape(100,100)
x=numpy.linspace(0,10,1)
X,Y = numpy.meshgrid(x,x)
plt.contourf(X,Y,matrixA_masked,colormap='gray')
plt.contourf(X,Y,matrixB_masked,colormap='winter')
plt.show()
What I want is to be able to use different colormaps that appear in the same plot. So for instance in the plot there will be a part assigned to matrixA with a contour color (and 0 where matrixB take place), and the same to matrixB with a different colormap.
In other works each part of the contourf plot correspond to one matrix. I am plotting decision surfaces of Machine Learning Models.
I stumbled into some errors in your code so I have created my own dataset.
To have two colormaps on one plot you need to open a figure and define the axes:
import numpy
import matplotlib.pyplot as plt
matrixA=numpy.linspace(1,20,100)
matrixA[matrixA >= 10] = numpy.nan
matrixA_2 = numpy.reshape(matrixA,[50,2])
matrixB=numpy.linspace(1,20,100)
matrixB[matrixB <= 10] = numpy.nan
matrixB_2 = numpy.reshape(matrixB,[50,2])
fig,ax = plt.subplots()
a = ax.contourf(matrixA_2,cmap='copper',alpha=0.5,zorder=0)
fig.colorbar(a,ax=ax,orientation='vertical')
b=ax.contourf(matrixB_2,cmap='cool',alpha=0.5,zorder=1)
fig.colorbar(b,ax=ax,orientation='horizontal')
plt.show()
You'll also see I've changed the alpha and zorder
I hope this helps.

RGB polar plot in Python

I am trying to produce RGB polar plots in Python and I was expecting matplotlib.pyplot.imshow to be able to do it. However, whenever I try plotting data using this method I obtain a blank output.
import matplotlib.pyplot as plt
import numpy as np
data = np.array([[[0,0,1],[0,1,0],[1,0,0]],[[0,0,0.5],[0,0.5,0],[0.5,0,0]]])
# Sample, any N,M,3 data should work
ax = plt.subplot(111,polar=True)
ax.imshow(data,extent=[0,2*np.pi,0,1]) # Produces a white circle
Is there a good way to accomplish this using the aforementioned method or another ?
Thanks.
EDIT: I managed to make a single quadrant by using extent=[0,np.pi/2,0,1] but its use is clearly bugged for polar plots. since anything but a full quadrant doesn't produce the expected outcome.
Using imshow on a polar plot is unfortunately not possible, because the imshow grid is necessarily quadratic in its pixels. You may however use pcolormesh and apply a trick (similar to this one), namely to provide the colors as color argument to pcolormesh, as it would usually just take 2D input.
import matplotlib.pyplot as plt
import numpy as np
data = np.array([[[0,0,1],[0,1,0],[1,0,0]],
[[0,0,0.5],[0,0.5,0],[0.5,0,0]]])
ax = plt.subplot(111, polar=True)
#get coordinates:
phi = np.linspace(0,2*np.pi,data.shape[1]+1)
r = np.linspace(0,1,data.shape[0]+1)
Phi,R = np.meshgrid(phi, r)
# get color
color = data.reshape((data.shape[0]*data.shape[1],data.shape[2]))
# plot colormesh with Phi, R as coordinates,
# and some 2D array of the same shape as the image, except the last dimension
# provide colors as `color` argument
m = plt.pcolormesh(Phi,R,data[:,:,0], color=color, linewidth=0)
# This is necessary to let the `color` argument determine the color
m.set_array(None)
plt.show()
The result is not a circle because you do not have enough points. Repeating the data, data = np.repeat(data, 25, axis=1) would then allow to get a circle.

Change axis range into latitude and longitude using matplotlib in python

How can I use yaxis and xaxis, which I want and that are not correlated with data in the plot?
For example, I want to plot the world map as an image using the code below:
import matplotlib.pyplot as plt
fig = plt.figure()
plt.imshow(world_map)
As a result, I got xaxis: 0...image_size_x from the left to the rigth and yaxis: 0...image_size_y from top to bottom.
What do I need to to do to change its axis range into latitude and longitude formats? Thus the figure axis should contain degrees (from 90 to -90) on the both fields (x and y) regardless of what its real data plotted in the figure.
Setting
pylab.ylim([90,-90])
will shift the image to the bottom by 90 pixels and reduced the y-dimension of the image into the scale of image_size_y/90. So it'll not work because xlim/ylim works with data, plotted in the figure.
In short: Use the extent keyword with imshow.
In code:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subaxis(111)
ax.imshow(world_map, extent=[-180,180,-90,90], aspect='auto')
If your map is then upside down, add the keyword argument origin='lower' to the imshow. That aspect='auto' is needed to make the map scalable in both dimensions independently. (The rest of the extra rows with add_subaxis are just to make the code more object-oriented, the real beef is in the keyword arguments.)
If imshow is not given the extents of the image, it thinks that you'll want to have each pixel centered at positions (0,0), (0,1), ..., (Nx-1, Ny-1), and then the image extents will start from (-.5, -.5).
Assuming (based on your post) the image is fine but the axis labels are off, try playing around with this, which will manually implement the axis labels:
plt.figure(1)
ax = plt.subplot(111)
#... do your stuff
#need to figure out your image size divided by the number of labels you want
#FOR EXample, if image size was 180, and you wanted every second coordinate labeled:
ax.set_xticks([i for i in range(0,180,2)]) #python3 code to create 90 tick marks
ax.set_xticklabels([-i for i in range(-90,90,2)]) #python3 code to create 90 labels
#DO SAME FOR Y
The trick im using is to figure out how many labels you want (here, its 90: 180/2), add the tickmarks evenly in the range (0,imagesize), then manually do the labels. Here is a general formula:
ax.set_xticks([i for i in range(0,IMAGE_SIZE,_EVERY_XTH_COORD_LABELED)]) #python3 code to create 90 tick marks
ax.set_xticklabels([-i for i in range(-90,90,EVERY_XTH_COORD_LABELED)]) #python3 code to create 90 labels

Scale axes 3d in matplotlib

I'm facing issues in scaling axes 3d in matplotlib. I have found another questions but somehow the answer it does not seems to work. Here is a sample code:
import matplotlib as mpl
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
data=np.array([[0,0,0],[10,1,1],[2,2,2]])
fig=plt.figure()
ax=Axes3D(fig)
ax.set_xlim3d(0,15)
ax.set_ylim3d(0,15)
ax.set_zlim3d(0,15)
ax.scatter(data[:,0],data[:,1],data[:,2])
plt.show()
It seems it just ignore the ax.set commands...
In my experience, you have to set your axis limits after plotting the data, otherwise it will look at your data and adjust whatever axes settings you entered before to fit it all in-frame out to the next convenient increment along the axes in question. If, for instance, you set your x-axis limits to +/-400 but your data go out to about +/-1700 and matplotlib decides to label the x-axis in increments of 500, it's going to display the data relative to an x-axis that goes out to +/-2000.
So in your case, you just want to rearrange that last block of text as:
fig=plt.figure()
ax=Axes3D(fig)
ax.scatter(data[:,0],data[:,1],data[:,2])
ax.set_xlim3d(0,15)
ax.set_ylim3d(0,15)
ax.set_zlim3d(0,15)
plt.show()
The way of ColorOutOfSpace is good. But if you want to automate the scaling you have to search for the maximum and minimum number in the data and scale with those values.
min = np.amin(data) # lowest number in the array
max = np.amax(data) # highest number in the array
ax.set_xlim3d(min, max)
ax.set_ylim3d(min, max)
ax.set_zlim3d(min, max)

Python - matplotlib axes limits approximate ticker location

When no axes limits are specified, matplotlib chooses default values as nice, round numbers below and above the minimum and maximum values in the list to be plotted.
Sometimes I have outliers in my data and I don't want them included when the axes are selected. I can detect the outliers, but I don't want to actually delete them, just have them be beyond the area of the plot. I have tried setting the axes to be the minimum and maximum value in the list not including the outliers, but that means that those values lie exactly on the axes, and the bounds of the plot do not line up with ticker points.
Is there a way to specify that the axes limits should be in a certain range, but let matplotlib choose an appropriate point?
For example, the following code produces a nice plot with the y-axis limits automatically set to (0.140,0.165):
from matplotlib import pyplot as plt
plt.plot([0.144490353418, 0.142921640661, 0.144511781706, 0.143587888773, 0.146009766101, 0.147241517391, 0.147224266382, 0.151530932135, 0.158778411784, 0.160337332636])
plt.show()
After introducing an outlier in the data and setting the limits manually, the y-axis limits are set to slightly below 0.145 and slightly above 0.160 - not nearly as neat and tidy.
from matplotlib import pyplot as plt
plt.plot([0.144490353418, 0.142921640661, 0.144511781706, 0.143587888773, 500000, 0.146009766101, 0.147241517391, 0.147224266382, 0.151530932135, 0.158778411784, 0.160337332636])
plt.ylim(0.142921640661, 0.160337332636)
plt.show()
Is there any way to tell matplotlib to either ignore the outlier value when setting the limits, or set the axes to 'below 0.142921640661' and 'above 0.160337332636', but let it decide an appropriate location? I can't simply round the numbers up and down, as all my datasets occur on a different scale of magnitude.
You could make your data a masked array:
from matplotlib import pyplot as plt
import numpy as np
data = [0.144490353418, 0.142921640661, 0.144511781706, 0.143587888773, 500000, 0.146009766101, 0.147241517391, 0.147224266382, 0.151530932135, 0.158778411784, 0.160337332636]
data = np.ma.array(data, mask=False)
data.mask = data>0.16
plt.plot(data)
plt.show()
unutbu actually gave me an idea that solves the problem. It's not the most efficient solution, so if anyone has any other ideas, I'm all ears.
EDIT: I was originally masking the data like unutbu said, but that doesn't actually set the axes right. I have to remove the outliers from the data.
After removing the outliers from the data, the remaining values can be plotted and the y-axis limits obtained. Then the data with the outliers can be plotted again, but setting the limits from the first plot.
from matplotlib import pyplot as plt
data = [0.144490353418, 0.142921640661, 0.144511781706, 0.143587888773, 500000, 0.146009766101, 0.147241517391, 0.147224266382, 0.151530932135, 0.158778411784, 0.160337332636]
cleanedData = remove_outliers(data) #Function defined by me elsewhere.
plt.plot(cleanedData)
ymin, ymax = plt.ylim()
plt.clf()
plt.plot(data)
plt.ylim(ymin,ymax)
plt.show()

Categories