python pyplot negative contour lines not displayed - matplotlib

minr=min(r_s)
maxr=max(r_s)
mini=min(i_s)
maxi=max(i_s)
xi=np.arange(minr,maxr, 0.1)
yi=np.arange(mini,maxi, 0.1)
zi=mlab.griddata(r_s, i_s, r_z, xi, yi, interp='linear')
plt.rcParams['contour.negative_linestyle'] = 'dashed'
CS=plt.contour(xi,yi,zi,50, linewidths =2.0)
plt.clabel(CS, inline=1, fontsize=10)
CS = plt.contourf(xi,yi,zi,15,cmap=plt.cm.rainbow)
plt.colorbar()
plt.xlabel('RS')
plt.ylabel('IS')
plt.show()
print ("END")
The above code is written to display a contour map of scattered 3D points r_s, i_s, r_z. I was able to plot the contour map/lines but only positive contour lines are displayed. Am I missing something? I want to show many contour lines including the negative ones.
data varies as follows:
r_s: from -7 to 2.0 with a step of 0.1
i_s: from -3 to 15 with a step of 0.1
r_z: from -1100 to 400 randomly

I was able to find a solution to my problem. The code is fine. The problem is in the data. In fact, some data points (few points) were above 10^6 which forced the contour plot not to show the negative points (about -1000). After fixing the data, I was able to plot contour lines including negative contour lines with the above code.

Related

Matplotlib, Inkscape, Spyder, plots and SVG compatibility (true axis size)

I have been plotting data for years during my PhD and always had to fight with something that unfortunately plagues the scientific community: negligent data manipulation.
My problem is that when I plot with matplotlib two graphics with different number lengths in the Y axis, the result is two graphics with two different X axis sizes.
When I copy the resulting SVG image directly from Spyder IPython console (Copy SVG) and paste in Inkscape for editing, matching the axis is a painful task which requires scaling them correctly with absolute precision. I am aware there plugins that are able to rescale plots in Inkscape and etc.
Bonus solved problem 1: for some reason, the size of an SVG created by matplotlib is scaled by 0.75 relative to Inkscape
Bonus solved problem 2: Matplotlib uses... inches, so the 25.4 that is in the following code lines is simply to convert from inch to millimeters.
Sometimes, having more control at the root is better than patching and patching and patching. So here is my solution to those who have been agonizing like me over being able to have two plots with the same absolute axis sizes:
from matplotlib import pyplot as plt
inch = False # Set to True if you want to use inch (blergh...).
width = 50 # The actual size in millimeters for the X axis to have.
height = 20 # The actual size in millimeters for the Y axis to have.
figsize = [(-0.212+width)/(1+24.4*(not inch)),(-0.212+height)/(1+24.4*(not inch))] # [W, H]
# Attention to the 0.212 mm which is thickness of the axis line; the cap at the end of the axis is half of thickness and is accounted for the size of the axis in Inkscape. So, when you use the size of a line from Inkscape as the desired size of the axis in a plot from matplotlib, ax.get_linewidth() by default should be 0.8 (whatever 0.8 is.. but it seems like 0.212/25.4 * 100).
height_scale = 3 # Scale to account for the axis title, labels and ticks.
width_scale = 2 # Scale to account for the axis title, labels and ticks.
figsize = [width_scale*figsize[0]/0.75, height_scale*figsize[1]/0.75]
fig = plt.figure(figsize = (figsize[0], figsize[1]))
wpos = (50/(1+24.4*(not inch)))/(figsize[0]/0.75) # Giving 50 mm mandatory position shift for the Y axis, to accommodate the title, labels and ticks.
hpos = (40/(1+24.4*(not inch)))/(figsize[1]/0.75) # Giving 40 mm mandatory position shift for the X axis to accommodate the title, labels and ticks.
# Now comes the problem. The AXIS size is defined relatively to the FIGURE size. The following values will simply use the rescaled FIGURE sizes:
wscale = 1/width_scale # = (width_scale*figsize[0]/0.75)/width_scale = figsize[0]/0.75 which is our target size for Inkscape.
hscale = 1/height_scale
ax = fig.add_axes([wpos, hpos, wscale, hscale])
Then you can plot at will, copy the SVG output (in Spyder's IPython console, at least) and paste it in Inkscape.
The only set back is that the whole FIGURE size will be abnormal and you'll have to remove the white background from it in Inkscape. But that is something probably all of us already do.
This is a minimal working code. You can paste it in your IPython console and copy the SVG output, paste it in Inkscape and check the axis line size. It will be with a width of 50 mm and a height of 20 mm.

Scatter plot without x-axis

I am trying to visualize some data and have built a scatter plot with this code -
sns.regplot(y="Calls", x="clientid", data=Drop)
This is the output -
I don't want it to consider the x-axis. I just want to see how the data lie w.r.t y-axis. Is there a way to do that?
As #iayork suggested, you can see the distribution of your points with a striplot or a swarmplot (you could also combine them with a violinplot). If you need to move the points closer to the y-axis, you can simply adjust the size of the figure so that the width is small compared to the height (here i'm doing 2 subplots on a 4x5 in figure, which means that each plot is roughly 2x5 in).
fig, (ax1,ax2) = plt.subplots(1,2, figsize=(4,5))
sns.stripplot(d, orient='vert', ax=ax1)
sns.swarmplot(d, orient='vert', ax=ax2)
plt.tight_layout()
However, I'm going to suggest that maybe you want to use distplot instead. This function is specifically created to show the distribution of you data. Here i'm plotting the KDE of the data, as well as the "rugplot", which shows the position of the points along the y-axis:
fig = plt.figure()
sns.distplot(d, kde=True, vertical=True, rug=True, hist=False, kde_kws=dict(shade=True), rug_kws=dict(lw=2, color='orange'))

Dotted line style from non-evenly distributed data

I'm new to Python and MatPlotlib.
This is my first posting to Stackoverflow - I've been unable to find the answer elsewhere and would be grateful for your help.
I'm using Windows XP, with Enthought Canopy v1.1.1 (32 bit).
I want to plot a dotted-style linear regression line through a scatter plot of data, where both x and y arrays contain random floating point data.
The dots in the resulting dotted line are not distributed evenly along the regression line, and are "smeared together" in the middle of the red line, making it look messy (see upper plot resulting from attached minimal example code).
This does not seem to occur if the items in the array of x values are evenly distributed (lower plot).
I'm therefore guessing that this is an issue with how MatplotLib renders dotted lines, or with how Canopy interfaces Python with Matplotlib.
Please could you tell me a workaround which will make the dots on the dotted line type appear evenly distributed; even if both x and y data are non-evenly distributed; whilst still using Canopy and Matplotlib?
(As a general point, I'm always keen to improve my coding skills - if any code in my example can be written more neatly or concisely, I'd be grateful for your expertise).
Many thanks in anticipation
Dave
(UK)
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
#generate data
x1=10 * np.random.random_sample((40))
x2=np.linspace(0,10,40)
y=5 * np.random.random_sample((40))
slope, intercept, r_value, p_value, std_err = stats.linregress(x1,y)
line = (slope*x1)+intercept
plt.figure(1)
plt.subplot(211)
plt.scatter(x1,y,color='blue', marker='o')
plt.plot(x1,line,'r:',label="Regression Line")
plt.legend(loc='upper right')
slope, intercept, r_value, p_value, std_err = stats.linregress(x2,y)
line = (slope*x2)+intercept
plt.subplot(212)
plt.scatter(x2,y,color='blue', marker='o')
plt.plot(x2,line,'r:',label="Regression Line")
plt.legend(loc='upper right')
plt.show()
Welcome to SO.
You have already identified the problem yourself, but seem a bit surprised that a random x-array results in the line be 'cluttered'. But you draw a dotted line repeatedly over the same location, so it seems like the normal behavior to me that it gets smeared at places where there are multiple dotted lines on top of each other.
If you don't want that, you can sort your array and use that to calculate the regression line and plot it. Since its a linear regression, just using the min and max values would also work.
x1_sorted = np.sort(x1)
line = (slope * x1_sorted) + intercept
or
x1_extremes = np.array([x1.min(),x1.max()])
line = (slope * x1_extremes) + intercept
The last should be faster if x1 becomes very large.
With regard to your last comment. In your example you use whats called the 'state-machine' environment for plotting. It means that specified commands are applied to the active figure and the active axes (subplots).
You can also consider the OO approach where you get figure and axes objects. This means you can access any figure or axes at any time, not just the active one. Its useful when passing an axes to a function for example.
In your example both would work equally well and it would be more a matter of taste.
A small example:
# create a figure with 2 subplots (2 rows, 1 column)
fig, axs = plt.subplots(2,1)
# plot in the first subplots
axs[0].scatter(x1,y,color='blue', marker='o')
axs[0].plot(x1,line,'r:',label="Regression Line")
# plot in the second
axs[1].plot()
etc...

matplotlib: preventing a few very large (or small) values to affect my contour

in plotting the data some times there are a few very large (or very small) numbers which, if not taken care of, will affect the contour in a bad way. a solution is to take out the 10% highest and lowest data out of the contour color grading and considering them as less than and more than. the following figure shows the idea:
the two arrow shapes on the top and the bottom of the bar support this idea. any value above 14 will be shown in white and any value below -2 will be shown in black color. how is it possible in matplotlib?
How can I define:
- to put the 5% of highest values and 5% of lowest values in two categories shown in the triangular parts in both ends of the bar? (Should I define it the contour operation or are there other ways?)
- what if I want to give certain values instead of the percentage? for instance, ask to put any value above 14 on the white triangule and any value below -2 as black areas?
Thank you so much for your help.
Taken from http://matplotlib.org/examples/api/colorbar_only.html. You can play with it and you will see if it could solve your problem.
import matplotlib.pyplot as plt
from matplotlib import mpl
import numpy as np
x = np.linspace(-1,1,100)
X,Y = np.meshgrid(x,x)
Z = np.exp(-X**2-Y**2)
vmin = 0.3 #Lower value
vmax = 0.9 #Upper value
bounds = np.linspace(vmin,vmax,4)
cmap = mpl.colors.ListedColormap([(0,0,0),(0.5,0.5,0.5),(0,1,0),(1,1,1)])
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
plt.imshow(Z,cmap=cmap,interpolation='nearest',vmin=vmin,vmax=vmax)
ax = plt.colorbar().ax
cb = mpl.colorbar.ColorbarBase(ax, norm=norm,
extend='both',
cmap=cmap)
cmap.set_over([0,0,1])
cmap.set_under([1,0,0])
plt.show()

Plot error bars (percentile)

I'm quite new to python and I need some help. I would like to plot errorbars equivalent to 1sigma standard deviations on my plot as the 16th and 84th percentile values of the distributions. I tried with (using matplotlib):
err=np.std(x)
but it just gives me the standard deviations.
Thanks.
If you want vertical error bars
ax = plt.gca()
ax.errorbar(x, y, yerr=np.vstack([error_low, error_high]))
plt.draw()
where error_low and error_high are 1D sequences of the same length an x and y. The error bars are drawn at y[i] - error_low[i] and y[i] + error_high[i].
matplotlib just draws what you tell it to, it is your job to provide the semantics.
errorbar documentation