Contour line error with plt.contour in python 3 - python

I am plotting a contour plot in python 3 with matplotlib, and I am getting a strange result. At first, I was using plt.contourf, and notices there was a strange north-south linear artifact in the data that I knew shouldn't be there (I used simulated data). So I changed plt.contourf to plt.contour, and the problem seems to be that some of the edge contours are deformed for some reason (see picture).
Unfortunately, it is hard for me to past a simple version of my code because this is part of a large GUI based app. Here is what I am doing though.
#grid the x,y,z data so it can be used in the contouring
self.beta_zi =
#This is matplot griddata, not the scipy.interpolate.griddata
griddata(self.output_df['x'].values,self.output_df['y'].values,
self.output_df['Beta'].values,
self.cont_grid_x,
self.cont_grid_y,
interp='linear')
#call to the contour itself
self.beta_contour=self.beta_cont_ax.contour(self.cont_grid_x,self.cont_grid_y,
self.beta_zi,
levels=np.linspace(start=0,stop=1, num=11, endpoint=True),
cmap=cm.get_cmap(self.user_beta_cmap.get()))
This seems like a simple problem based on the edges. Has anyone seen this before that can help. I am use a TK backend, which works better with the tkinter based GUI I wrote.
UPDATE: I also tried changing to scipy.interpolate.griddata because matplot's griddata is deprecated, but the problem is the same and persists, so it must be with the actual contour plotting function.

I found that the problem had to do with how I was interpreting the inputs of contour and grid data.
plt.contour and matplot.griddata takes
x = x location of sample data
y = y location of sample data
z = height or z value of sample data
xi = locations of x tick marks on grid
zi = locations of y ticks marks on grid
Typically xi and yi are all the locatoins of each grid node, which is what I was supplying, but in this case you only need the unqiue tick marks on each axis.
Thanks to this post I figured it out.
Matplotlib contour from xyz data: griddata invalid index

Related

Colour between the rings on a python radar graph

I'm rather new to coding and i'm currently stuck on this problem.
I am trying to shade the region from 0-2 on the radar graph and have been using
ax.fill(x_as, values3, color="#757575", alpha=0.3)
where i set values 3 as 2.
However, this creates a hexagon rather than a smooth shading from 0-2.
Not sure if there is a simple way of solving this, but any input would be useful!
Cheers
Current radar graph
Without seeing your code, it is hard to be sure, but most likely you are only using 6 different values in x_as -- the same values you use for your line plots. If instead you use a more densely populated array, say with 100 values, your fill area will appear to be circular:
thetas = np.linspace(0,2*np.pi,100)
ax.fill(thetas, [2 for i in thetas], color = "#757575", alpha = 0.3)
Below a figure with some arbitrary data for the line plots and the above given code for the shaded area:
Hope this helps.

Matplotlib scatterplot axis autoscale fails for small data values

When using Matplotlib's scatterplot, sometimes autoscaling works, sometimes not.
How do I fix it?
As in the example provided in the bug report, this code works:
plt.figure()
x = np.array([0,1,2,3])
x = np.array([2,4,5,9])
plt.scatter(x,y)
But when using smaller values, the scaling fails to work:
plt.figure()
x = np.array([0,1,2,3])
x = np.array([2,4,5,9])
plt.scatter(x/10000,y/10000)
Edit: An example can be found here. I have not specified the specific cause in the question, because when encountering the error it is not obvious what causes it. Also, I have specified the solution and cause in my own answer.
In at least Matplotlib 1.5.1, there is a bug where autoscale fails for small data values, as reported here.
The workaround is to use .set_ylim(bottom,top) (documentation) to manually set the data limits (in this example for the y axis, to set the x axis, use .set_xlim(left,right).
To automatically find the data limits that are pleasing to the eyes, the following pseudocode can be used:
def set_axlims(series, marginfactor):
"""
Fix for a scaling issue with matplotlibs scatterplot and small values.
Takes in a pandas series, and a marginfactor (float).
A marginfactor of 0.2 would for example set a 20% border distance on both sides.
Output:[bottom,top]
To be used with .set_ylim(bottom,top)
"""
minv = series.min()
maxv = series.max()
datarange = maxv-minv
border = abs(datarange*marginfactor)
maxlim = maxv+border
minlim = minv-border
return minlim,maxlim

flipped image in matplotlib

Im trying to plot an image using matplotlib, and it comes out rotated 90 degrees clockwise, which seems to be a common problem. So i need to rotate it back 90 degrees counterclockwise to show my actual image. However when I tried to plot the transpose of the data, i get an error message that says "invalid dimensions for image data" additionally i also tried to set origin to lower because that also seems to be a way to fix such problems, but that only flipped it across the x axis. How do I fix this? here is my original code
from dipy.reconst.dti import color_fa
cfa = color_fa(FA, tenfit.evecs)
cfa_img = nib.Nifti1Image(cfa.astype(np.float32), img.get_affine())
data_cfa = cfa_img.get_data()
import matplotlib.pyplot as plt
plt.figure('color_fa')
plt.imshow(data_cfa[:,:,6,:])
plt.show()
so it shows slice 6 of an image which is 192x192
and when i change the imshow line to
plt.imshow(data_cfa[:,:,6,:].T)
i get that error message.
I'm new to python and matplotlib, so any help would be greatly appreciated!
The problem is that you are trying to transpose an image with three dimensions. The dimensions of your image are N x M x 3, and you would like to have a M x N x 3 array (rotate but keep the color planes intact).
With the .T method you'll unfortunately get an array with dimensions 3 x M x N, which is not what you want. This is the source of the error.
Instead of .T use .transpose(1,0,2).This will transpose the two first axes but leaves the third intact. Now the image should be rotated as you wanted it:
plt.imshow(data_cfa[:,:,6,:].transpose(1,0,2))
See the documentation for np.transpose: http://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html
(If your image were a N x M grayscale image, then the .T trick would have been the right one.)
Try scipy.ndimage.rotate (see example code below). Unlike .T which swaps all the axes (see answer from #DrV), ndimage.rotate is designed to leave the color information alone. It can also handle an arbitrary rotation (e.g. 31.4 degrees). For a broader range of examples look at http://scipy-lectures.github.io/advanced/image_processing/#geometrical-transformations.
data_cfa = rand(10,10,7,3)
plt.subplot(211)
plt.imshow(data_cfa[:,:,6,:])
plt.title('Original')
plt.subplot(212)
plt.imshow(ndimage.rotate(data_cfa[:,:,6,:], 90))
plt.title('Rotated by 90')
plt.show()

Possible to use a custom arrow or polygon as a marker to plot location and heading in matplotlib?

I have a series of x,y coordinates and associated heading angles for multiple aircraft. I can plot the paths flown, and I would like to use a special marker to mark a particular location along the path that also shows the aircraft's heading when it was at that location.
Using matplotlib.pyplot I've used an arrowhead with no base to do this, but having to define the head and tail locations ended up with inconsistent arrowhead lengths when plotting multiple aircraft. I also used a custom three-sided symbol with the tuple (numsides, style, angle) as well as the wedge and bigvee symbols, but they never look very good.
From Custom arrow style for matplotlib, pyplot.annotate Saullo Castro showed a nice custom arrow (arrow1) that I'm wondering whether it can be used or converted in such a way as to just simply plot it at a given x,y and have its orientation defined by a heading angle.
I can plot the custom arrow with the following. Any ideas on how to rotate it to reflect a heading?
a1 = np.array([[0,0],[0,1],[-1,2],[3,0],[-1,-2],[0,-1],[0,0]], dtype=float)
polB = patches.Polygon(a1, closed=True, facecolor='grey')
ax.add_patch(polB)
Thanks in advance.
So I made the polygon a little simpler and also found that the rotation could be done by using mpl.transforms.Affine2D().rotate_deg_around():
a2 = np.array([[newX,newY+2],[newX+1,newY-1],[newX,newY],[newX-1,newY-1],[newX,newY+2]], dtype=float)
polB = patches.Polygon(a2, closed=True, facecolor='gold')
t2 = mpl.transforms.Affine2D().rotate_deg_around(newX,newY,heading) + newax.transData
polB.set_transform(t2)
newax.add_patch(polB)
I first tried to overlay the polygon on a line plotted from the x,y coordinates. However, the scales of the x and y axes were not equal (nor did I want them to be), so the polygon ended up looking all warped and stretched when rotated. I got around this by first adding a new axis with equal x/y scaling:
newax = fig.add_axes(ax.get_position(), frameon=False)
newax.set_xlim(-20,20)
newax.set_ylim(-20,20)
I could at least then rotate all I wanted and not have the warp issue. But then I needed to figure out how to basically connect the two axes so that I could plot the polygon on the new axis at a point referenced from the original axis. The way I figured to do this was by using transformations to go from the data coordinates on the original axis, converting them to display coordinates, and then inverting them back to data coordinates except this time at the data coordinates on the new axis:
inTrans = ax.transData.transform((x, y))
inv = newax.transData.inverted()
newTrans = inv.transform((inTrans[0], inTrans[1]))
newX = newTrans[0]
newY = newTrans[1]
It felt a little like some sort of Rube Goldberg machine to do it this way, but it did what I wanted.
In the end, I decided I didn't like this approach and went with keeping it simpler and using a fancy arrowhead instead of a polygon. Such is life...

Matlab, Python: Fixing colormap to specified values

It is a simple but common task required when trying to fix a colormap according to a 2D matrix of values.
To demonstrate consider the problem in Matlab, the solution does not need to be in Matlab (i.e., the code presented here is only for demonstration purpose).
x = [0,1,2; 3,4,5; 6,7,8];
imagesc(x)
axis square
axis off
So the output is as:
when some values change to over the maximum value it happens like:
x = [0,1,2; 3,4,5; 6,7,18];
which looks logical but makes problems when we wish to compare/trace elements in two maps. Since the colormap association is changed it is almost impossible to find an individual cell for comparison/trace etc.
The solution I implemented is to mask the matrix as:
x = [0,1,2; 3,4,5; 6,7,18];
m = 8;
x(x>=m) = m;
which works perfectly.
Since the provided code requires searching/filtering (extra time consuming!) I wonder if there is a general/more efficient way for this job to be implemented in Matlab, Python etc?
One of the cases that this issue occurs is when we have many simulations sequentially and wish to make a sense-making animation of the progress; in this case each color should keep its association fixed.
In Python using package MatPlotLib the solution is as follows:
import pylab as pl
x = [[0,1,2],[3,4,5],[6,7,18]]
pl.matshow(x, vmin=0, vmax=8)
pl.axis('image')
pl.axis('off')
show()
So vmin and vmax are boundary limits for the full range of colormap.
The indexing is pretty quick so I don't think you need worry.
However, in Matlab, you can pass in the clims argument to imagesc:
imagesc(x,[0 8]);
This maps all values above 8 to the top colour in the colour scale, and all values below 0 to the bottom colour in the colour scale, and then stretches the scale for colours in-between.
imagesc documentation.
f1 = figure;
x = [0,1,2; 3,4,5; 6,7,8];
imagesc(x)
axis square
axis off
limits = get(gca(f1),'CLim');
f2 = figure;
z = [0,1,2; 3,4,5; 6,7,18];
imagesc(z)
axis square
axis off
caxis(limits)

Categories

Resources