I am reading the following discussion:
setting axis scale in matplotlib contour plot
From the discussion above, to get arbitrary ratio, we could use
plt.figure(figsize=(8,2))
# ...
plt.tight_layout()
However, this setting is for figure not for contourf.
I used the above codes in my codes
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import pandas as pd
import math
rm = pd.read_excel("test_3d.xlsx", header = None)
# find min values of noise
rec = np.shape(rm)
# grid
X = np.arange(1,rec[1]+1,1)
Y = np.arange(1,rec[0]+1,1)
x , y = np.meshgrid(X,Y)
# plots
plt.clf()
con = plt.contourf(x,y,rm, cmap=cm.jet)
plt.figure(figsize=(8,2))
plt.tight_layout()
plt.title('2457MHz')
plt.show()
The result I got is
The ratio of bottom plot is what I want; however, I use plt.figure(figsize=(8,2)), which is not for contourf. Therefore, I did not get the correct result.
Is there any way that I can plot arbitrary ratio for contourf?
Instead of setting the figsize, use Axes.set_aspect to change the aspect ratio of the contour plot's Axes:
fig, ax = plt.subplots()
ax.contourf(x, y, rm, cmap='viridis')
ax.set_aspect(0.25)
If you prefer to stick with the plt syntax, access the Axes using plt.gca:
plt.contourf(x, y, rm, cmap='viridis')
plt.gca().set_aspect(0.25)
Related
I'm working with data that has the data has 3 plotting parameters: x,y,c. How do you create a custom color value for a scatter plot?
Extending this example I'm trying to do:
import matplotlib
import matplotlib.pyplot as plt
cm = matplotlib.cm.get_cmap('RdYlBu')
colors=[cm(1.*i/20) for i in range(20)]
xy = range(20)
plt.subplot(111)
colorlist=[colors[x/2] for x in xy] #actually some other non-linear relationship
plt.scatter(xy, xy, c=colorlist, s=35, vmin=0, vmax=20)
plt.colorbar()
plt.show()
but the result is TypeError: You must first set_array for mappable
From the matplotlib docs on scatter 1:
cmap is only used if c is an array of floats
So colorlist needs to be a list of floats rather than a list of tuples as you have it now.
plt.colorbar() wants a mappable object, like the CircleCollection that plt.scatter() returns.
vmin and vmax can then control the limits of your colorbar. Things outside vmin/vmax get the colors of the endpoints.
How does this work for you?
import matplotlib.pyplot as plt
cm = plt.cm.get_cmap('RdYlBu')
xy = range(20)
z = xy
sc = plt.scatter(xy, xy, c=z, vmin=0, vmax=20, s=35, cmap=cm)
plt.colorbar(sc)
plt.show()
Here is the OOP way of adding a colorbar:
fig, ax = plt.subplots()
im = ax.scatter(x, y, c=c)
fig.colorbar(im, ax=ax)
If you're looking to scatter by two variables and color by the third, Altair can be a great choice.
Creating the dataset
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame(40*np.random.randn(10, 3), columns=['A', 'B','C'])
Altair plot
from altair import *
Chart(df).mark_circle().encode(x='A',y='B', color='C').configure_cell(width=200, height=150)
Plot
When plotting data using pcolormesh on a basemap projection (or a cartopy projection) I notice strange lines appear when I set the alpha value to less than 1.
Example code:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
plt.clf()
dpp =1 # degrees per pixel
lons = np.arange(-180,180+dpp,dpp)
lats = -1*np.arange(-90,90+dpp,dpp)
m = Basemap(projection='robin',lon_0=0)
data = np.random.random((np.size(lats), np.size(lons)))
lons, lats = np.meshgrid(lons, lats)
x, y = m(lons, lats)
im = m.pcolormesh(x, y, x, latlon=False, cmap='RdBu')
#im = m.pcolormesh(lons, lats, data, latlon=True, cmap='RdBu')
m.colorbar(im)
plt.show()
The output shows strange lines appearing:
If I instead set alpha=1 the lines disappear and the behavior is as expected:
Any ideas on how to get pcolormesh to work with a nonzero alpha value?
Use pcolor instead of pcolormesh, it is a bit slower but it does a better job with handling rasterized output. Be sure to set snap = True, this will align the grid to the pixels.
Example
import numpy as np
import matplotlib.pyplot as plt
lons, lats = np.meshgrid(np.arange(-180,180), np.arange(90,-90,-1))
im = plt.pcolor(lons, lats, lons, cmap='RdBu', alpha=0.5, snap=True)
cbar = plt.colorbar(im)
cbar.set_alpha(0.5)
plt.show()
This should work with mpl_toolkits.basemap as well.
The lines in the colorbar are caused by the open issue #1188, as far as I know there is not a work around known which does not involve manually creating the colorbar.
Since it is a global map, I got it to work using imshow instead of pcolor or pcolormesh:
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
plt.clf()
lons, lats = np.meshgrid(np.arange(-180,180), np.arange(90,-90,-1))
im = ax.imshow(lons, transform=ccrs.PlateCarree(),cmap='RdBu', alpha=0.5, extent=[-180,180,-90,90])
cbar = plt.colorbar(im)
cbar.set_alpha(0.5)
plt.show()
There is still the issue with the colorbar however.
I would like to use a ColorFunction similar to that in Mathematica for my plots in python.
In other words, I would like to call pyplot.plot(x, y, color=c), where c is a vector, defining the color of each data point.
Is there any way to achieve this using the matplotlib library?
To the best of my knowledge, there is no equivalent in Matplotlib, but we can get the similar result following two steps: draw points with varied colors and draw the line.
Here is a demo.
The source code,
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
import random
fig, ax = plt.subplots()
nrof_points = 100
x = np.linspace(0, 10, nrof_points)
y = np.sin(x)
colors = cm.rainbow(np.linspace(0, 1, nrof_points)) # generate a bunch of colors
# draw points
for idx, point in enumerate(zip(x, y)):
ax.plot(point[0], point[1], 'o', color=colors[idx], markersize=10)
# draw the line
ax.plot(x, y, 'k')
plt.grid()
plt.show()
While I agree with #SparkAndShine that there is no way to parameterize the color of one line, it is possible to color many lines to create a visual effect that is largely the same. This is at the heart of a demo in the MatPlotLib documentation. However, this demo is not the simplest implementation of this principle. Here is an alternate demo based on #SparkAndShine's response:
colored sine (can't post as image since I don't have the reputation)
Source code:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
fig, ax = plt.subplots()
nrof_points = 100
x = np.linspace(0, 10, nrof_points)
y = np.sin(x)
colors = cm.rainbow(np.linspace(0, 1, nrof_points)) # generate a bunch of colors
# draw points
for idx in range(0,np.shape(x)[0]-2,1):
ax.plot(x[idx:idx+1+1], y[idx:idx+1+1], color=colors[idx])
# add a grid and show
plt.grid()
plt.show()
I have questions related to creating a simple lineplot in Python with mplot3D where the area under the plot is filled. I am using Python 2.7.5 on RedHatEnterprise 7.2, matplotlib 1.2.0 and numpy 1.7.2.
Using the code below, I am able to generate a line plot. This is displayed as expected with the beginning / end of the plot set by the limits of the imported data set.
I am then trying to fill the area between the line plot and -0.1 using the answer given by Bart from Plotting a series of 2D plots projected in 3D in a perspectival way. This works, however, the filled area is continued beyond the limits of the data set. This is also the case when running the example from the link.
This screen shot shows the plot generated with filled area extending beyond the set axis limits.
How do I achieve that the filled area is only the range of the data set or the axis limits whichever is smaller?
How do I add a legend for those plots onto the figure?
Code as follows:
from numpy import *
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
x,y = genfromtxt("data.dat",unpack=True)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.add_collection3d(plt.fill_between(x,y,-0.1, color='orange', alpha=0.3,label="filled plot"),1, zdir='y')
ax.plot(x,y,1,zdir="y",label="line plot")
ax.legend()
ax.set_xlim3d(852.353,852.359)
ax.set_zlim3d(-0.1,5)
ax.set_ylim3d(0,2)
ax.get_xaxis().get_major_formatter().set_useOffset(False)
plt.show()
I don't know how to put fill_between working the way you want it to, but I can provide an alternative using a 3D polygon:
from numpy import *
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection # New import
#x,y = genfromtxt("data.dat",unpack=True)
# Generated some random data
w = 3
x,y = np.arange(100), np.random.randint(0,100+w,100)
y = np.array([y[i-w:i+w].mean() for i in range(3,100+w)])
z = np.zeros(x.shape)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#ax.add_collection3d(plt.fill_between(x,y,-0.1, color='orange', alpha=0.3,label="filled plot"),1, zdir='y')
verts = [(x[i],z[i],y[i]) for i in range(len(x))] + [(x.max(),0,0),(x.min(),0,0)]
ax.add_collection3d(Poly3DCollection([verts],color='orange')) # Add a polygon instead of fill_between
ax.plot(x,z,y,label="line plot")
ax.legend()
ax.set_ylim(-1,1)
plt.show()
The code above generates some random data. Builds vertices from it and plots a polygon with those vertices. This will give you the plot you wish (but does not use fill_between). The result is:
I'm using matplotlib to produce a 3d trisurf graph. I have everything working except that I would like to invert the y-axis, so that the origin is 0,0 not 0,100. I've looked through the matplotlib axes3d API and cannot figure out how to do this. Here is my code:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
# my data, xs=xaxis, ys=yaxis, zs=zaxis
mortar_xs = []
cycles_ys = []
score_zs = []
#... populate my data for the 3 arrays: mortar_xs, cycles_ys, score_zs
# plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(mortar_xs,cycles_ys,score_zs,cmap=cm.coolwarm)
ax.set_zlim(bottom=0.0,top=1.0)
ax.legend()
ax.set_xlabel("# Mortar")
ax.set_ylabel("# Goals")
ax.set_zlabel("# Score")
plt.show()
My graph produced is the following, but I need the '# Goals' or the y-axis inverted, so that the origin is 0,0 not 0,100. If possible, I would like to do this without changing my data.
tmdavison's comment is what I was looking for:
ax.set_ylim(0,100)
Or
ax.set_ylim(100,0)
The simplest method would be to use ax.invert_yaxis()