xticks and labels stuck on one side of the subplot - python

I am plotting 3 maps on one figure. For some reason when I go to label the xaxis the numbers are all crammed on one side of the plot. Is there anyone to space the values out?
for j in xrange(0,3):
data = mydatalist[j]
a.append(fig.add_subplot(3,2,j+1))]
m.append(Basemap(projection='mill', llcrnrlat=-90, urcrnrlat=90, \
llcrnrlon=30,urcrnrlon=390, resolution='c', ax=a[j]))
x=np.linspace(30,390,288)
y = np.linspace(-90, 90, 234)
x, y = np.meshgrid(x, y)
x, y = m[j](x,y)
cintervals = [-0.1,-0.09, -0.08, -0.07, -0.06,-0.05, -0.04, -0.03, -0.02,-0.01,\
0, 0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1]
mesh = m[j].contourf(x,y,data,cintervals, cmap=plt.cm.jet)
xlab=np.concatenate([np.arange(30,181,30),np.arange(-150,31,30)])
plt.xticks(np.linspace(30, 390, 13),xlab)
plt.tick_params(labelsize=8)
plt.show()

Your problem is with co-ordinate mismatch between map coordinates and lat / long
You assign your x ticks to be displayed along the x axis spaced according to
np.linspace(30, 390, 13)
However - if you look at your values in x (i.e. the actual x co-ordinates that you are plotting against in the contourf line), you see they run from 0 to 40030154.74248523.
To avoid this - replace
plt.xticks(np.linspace(30, 390, 13),xlab)
with
plt.xticks(np.linspace(min(x[0]),max(x[0]), len(xlab)),xlab)
Note - you can produce this effect with a lot smaller but complete example, which might have helped you to isolate the issue. Take a look at how to produce a Minimal, complete and verifiable example. As it stands, your code doesn't run as it is missing a, m, mydatalist and the required imports.
I've put in the code below that you might have provided - retaining the subplot loop - although in reality you will likely get the same effect even with just one plot, rather than subplots.
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
x=np.linspace(30,390,288)
y = np.linspace(-90, 90, 234)
xg, yg = np.meshgrid(x, y)
fig = plt.figure()
for j in xrange(0,3):
a = fig.add_subplot(3,2,j+1)
m = Basemap(projection='mill', llcrnrlat=-90, urcrnrlat=90, llcrnrlon=30,urcrnrlon=390, resolution='c', ax=a)
m.drawcoastlines() # Just put something on the map - doesn't need to be your complex contour plot
x, y = m(xg,yg)
#You can see the problem with using hard-coded 30,390 if you print this
#x=30 and x=390 are both in the lowest 0.001% of the x axis
#print x
xlab=np.concatenate([np.arange(30,181,30),np.arange(-150,31,30)])
plt.xticks(np.linspace(30,390,13),xlab)
#Working version commented below
#plt.xticks(np.linspace(min(x[0]),max(x[0]), len(xlab)),xlab)
plt.tick_params(labelsize=8)
plt.show()

Switching to a Gall Stereographic projection solved the problem for me, although i'm not sure why it does not work on a Miller projection.

Related

How to show only the outline of a bar plot matplotlib

I'm plotting data as a bar plot in matplotlib and am trying to only show the outline of the bars, so that it appears as a 'stepped graph' of the data.
I've added my code below along with an image of the desired output.
plt.bar(x, y, align='center', width=0.1, edgecolor='black', color='none')
The plot I have:
The plot I would like:
Are there any other libraries that may be able to produce this? The bar keyword arguments don't seem to have anything that can.
Your image looks like a function that is horizontal around each x,y value. The following code simulates this:
for every x,y: create two new points one at x-0.5 and one at x+0.5, both with the same y
to close the shape at the ends, add (x[0]-0.5, 0) at the start and (x[-1]+0.5, 0) at the end.
import numpy as np
from matplotlib import pyplot as plt
x = np.arange(0, 30, 1)
y = np.random.uniform(2, 10, 30)
xs = [x[0] - 0.5]
ys = [0]
for i in range(len(x)):
xs.append(x[i] - 0.5)
xs.append(x[i] + 0.5)
ys.append(y[i])
ys.append(y[i])
xs.append(x[-1] + 0.5)
ys.append(0)
plt.plot(xs, ys, color='dodgerblue')
# optionally color the area below the curve
plt.fill_between(xs, 0, ys, color='gold')
PS: #AsishM. mentioned in the comments that matplotlib also has its own step function. If that function fulfils, please use that one. If you need some extra control or variation, this answer could give a start, such as coloring the area below the curve or handling the shape at the ends.

Scatter plot over 2D-histogram in matplotlib with log-scale

I have two sets of points with values (x, y). One is enormous (300k) and one is small (2k). I want to show a scatter plot of the latter over a 2D-histogram of the former in log-log scale. plt.xscale('log')-like commands keep messing up the histogram and when I just take logs of x's and y's and then do all the plotting, my ticks are say -3 not 10^-3 and the pretty logarithmic minor ticks are missing altogether. What's the most elegant solution in matplotlib? Do I have to dig into the artist layer?
If you forgive a bit of self-advertisement, you may use my library physt (see https://github.com/janpipek/physt). Then, you can write code like this:
import numpy as np
import matplotlib.pyplot as plt
from physt import h2
# Data
r1 = np.random.normal(0, 1, 20000)
r2 = np.random.normal(0, .3, 20000) + r1
x = np.exp(r1)
y = np.exp(r2)
# Plot scatter
fig, ax = plt.subplots()
ax.scatter(x[:1000], y[:1000], s=2)
H = h2(x, y, "exponential")
H.plot(ax=ax, zorder=-1) # Necessary to put behind
Which, I hope is the solution to your problem:

Stretching a line from a point in the xy-plane towards (x,y,z) point in matplotlib

I am trying to create a line that starts from the (x,y,0) point in the xy-plane and ends at the (x,y,z) value.
Is this possible in matplotlib?
Here's an example of what I have:
versus what I want:
Here we have the dot at (1,1,1). So basically I want to know if it's possible to extend a line going from (1,1,0) in the xy-plane to (1,1,1) in 3D.
Hope my question is clear to understand with this example.
Here is what I did.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
import numpy as np
fig = plt.figure(figsize=(1[![enter image description here][1]][1]5,10))
ax = fig.add_subplot(111, projection='3d')
# points
xs = np.asarray([np.cos(i) for i in np.arange(0,np.pi/2,(np.pi/2)/10)])
ys = np.arange(0,10,1)
zs = np.arange(0,10,1)
# plot points
ax.scatter(xs=xs, ys=ys, zs=zs, s=200, c=zs, cmap=cm.viridis_r, alpha=1.0)
# create the line
zs_l = np.asarray([[i, -1] for i in zs])
# color list
cl = [cm.get_cmap('viridis_r')(i/zs_l.shape[0]) for i in range(zs_l.shape[0])]
# draw the lines
for i, p in enumerate(zs_l):
ax.plot(xs=[xs[i]]*2, ys=[ys[i]]*2, zs=zs_l[i], markersize=0, lw=3, c=cl[i])
This doesn't make any sense. If you're working in three dimensions, then every point can be described in three dimensions, including your starting point. Describing something with only two coordinates in three dimensional space is essentially describing a line; if you only explicitly label the x and y coordinates, then all possible z values are valid- so you end up with a line.
What you want to do is make one of the coordinates (x, y, or z) zero.

Connect 2 points from separate graphs in python (matplotlib)

I am trying to plot a graph like the following and want to connect the points by lines. However, as you can see some of the points (above 0.04 on X axis) are partially overlapping and that does not allow us to represent the connection between them.
What I want to do is, make 2 separate graphs with 1 graph having all the points above 0.04 (so that it will be zoomed in and the points will be separated) and other one with just the one point in top left corner.
Note that, the size of the points also contains some meaning. So, I can not make the points smaller or larger in size. (unless the change is uniform across all the points)
What is the good way to do this? Is there any function in matplotlib providing such feature? Or is there any other python library apart from matplotlib where I can do this in a better way?
Edit Based on this post, a better solution than my previous one might be:
import matplotlib.pylab as pl
import matplotlib
import numpy as np
pl.close('all')
x = np.linspace(0.019, 0.021, 4)
y = np.linspace(0.09, 0.10, 4)
s = np.random.randint(10, 200, 4)
fig = pl.figure()
ax1=pl.subplot(121)
pl.scatter(x, y, s=s)
pl.xlim(0.01, 0.04)
pl.ylim(0.04, 0.12)
pl.xticks([0.01,0.02,0.03,0.04])
pl.yticks([0.04,0.06,0.08,0.10,0.12])
ax2=pl.subplot(122)
pl.scatter(x, y, s=s)
pl.xlim(0.018, 0.022)
pl.ylim(0.08, 0.11)
pl.xticks([0.018,0.020,0.022])
pl.yticks([0.08,0.095,0.11])
transFigure = fig.transFigure.inverted()
for i in range(x.size):
xy1 = transFigure.transform(ax1.transData.transform([x[i],y[i]]))
xy2 = transFigure.transform(ax2.transData.transform([x[i],y[i]]))
line = matplotlib.lines.Line2D((xy1[0],xy2[0]),(xy1[1],xy2[1]),
transform=fig.transFigure)
fig.lines.append(line)
The other (old) solution:
Interesting question. I came up with the "solution" below (although it ain't pretty...); it does an ax.transData.transform from the data coordinates to figure coordinates, and uses ax.annote to draw the arrows, but this solution unfortunately only works if you keep the figure dpi (dots per inch) equal to the figure ppi (points per inch).
If I can think of a better solution, I'll post it here.
import matplotlib.pylab as pl
import numpy as np
x = np.linspace(0.019, 0.021, 4)
y = np.linspace(0.09, 0.10, 4)
s = np.random.randint(10, 200, 4)
# Transform the data coordinates to figure (pixel) coordinates
def get_display_coordinates(x,y):
ax = pl.gca()
xd = np.zeros_like(x)
yd = np.zeros_like(y)
for i in range(x.size):
xd[i], yd[i] = ax.transData.transform([x[i], y[i]])
return xd, yd
pl.figure(dpi=72)
ax=pl.subplot(121)
sc=pl.scatter(x, y, s=s)
pl.xlim(0.01, 0.04)
pl.ylim(0.04, 0.12)
pl.xticks([0.01,0.02,0.03,0.04])
pl.yticks([0.04,0.06,0.08,0.10,0.12])
xd_1, yd_1 = get_display_coordinates(x,y)
ax=pl.subplot(122)
pl.scatter(x, y, s=s)
pl.xlim(0.018, 0.022)
pl.ylim(0.08, 0.11)
pl.xticks([0.018,0.020,0.022])
pl.yticks([0.08,0.095,0.11])
xd_2, yd_2 = get_display_coordinates(x,y)
for i in range(x.size):
ax.annotate("",
xy=(xd_2[i], yd_2[i]), xycoords='figure pixels',
xytext=(xd_1[i], yd_1[i]), textcoords='figure pixels',
arrowprops=dict(arrowstyle="->", connectionstyle="arc3"))
pl.savefig('test.png', dpi=72)

Can python/matplotlib's confourf be made to plot a limited region of data?

Am trying to make a contour plot with matplotlib's contourf. Is there a way to zoom in on a particular region of my data and leave the rest unplotted? For instance, maybe my horizontal extent goes from -1 to 101, but I just want to plot the data that's in between 0 and 100 inclusive, and I want the boundary of the plot to be drawn at 0 on the left and 100 on the right. I thought the "extent" keyword would do the job, but it is inactive when X and Y data are given. I know that I can mask the extraneous data in various ways, but that leaves the boundaries of the plot drawn beyond my region of interest, which is not what I want. I guess I could also filter or interpolate my data to my region of interest and then give that filtered data to contourf, but if I can just make contourf focus on a particular region, it would be alot easier. Thanks.
Perhaps you are looking for plt.xlim:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-1,101,100)
y = np.linspace(-1,101,100)
x, y = np.meshgrid(x, y)
z = x*x+y*y
plt.figure()
plt.xlim(0, 50)
plt.contourf(x, y, z)
plt.show()
Above, plt.xlim(0, 50) was used instead of plt.xlim(0,100) just to emphasize the change. Without plt.xlim(0, 50) the plot looks like this:

Categories