How to draw contour map? - python-3.x

I'm beginner for Python. I believe Python will do this task for 3D contour map.
I have data such as below
Y/X (mm), 0, 10, 20, 30, 40
686.6, -5.02, -0.417, 0, 100.627, 0
694.08, -5.02, -4.529, -17.731, -5.309, -3.535
701.56, 1.869, -4.529, -17.731, -5.309, -3.535
709.04, 1.869, -4.689, -17.667, -5.704, -3.482
716.52, 4.572, -4.689, -17.186, -5.704, -2.51
724, 4.572, -4.486, -17.186, -5.138, -2.51
731.48, 6.323, -4.486, -16.396, -5.138, -1.933
738.96, 6.323, -4.977, -16.396, -5.319, -1.933
746.44, 7.007, -4.251, -16.577, -5.319, -1.688
753.92, 7.007, -4.251, -16.577, -5.618, -1.688
761.4, 7.338, -3.514, -16.78, -5.618, -1.207
768.88, 7.338, -3.514, -16.78, -4.657, -1.207
776.36, 7.263, -3.877, -15.99, -4.657, -0.822
Any help How to start..
Update Question
(1) As you can see the raw data, they has xlabel and ylabel in respectively 1st row, 1st column.
If I use numpy.loadtxt function, How to split "xs" and "ys" ?
data = numpy.loadtxt('131014-data-xy-conv-1.txt')
(2) Do you have ay idea to rotate the matrix M x N from ?
(3) linespace has start = -70 and stop = 60, and num= 60, Do you have any idea how to make a step 5 ?
contour = subplot.contourf(xs, ys, data, levels=numpy.linspace(-70, 60, 60))

You can use matplotlib, namely its contourf function:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy
xs = numpy.array([0, 10, 20, 30, 40])
ys = numpy.array([686.6, 694.08, 701.56, 709.04, 716.52,
724, 731.48, 738.96, 746.44, 753.92, 761.4, 768.88, 776.36])
data = numpy.array([
[-5.02, -0.417, 0, 100.627, 0],
[-5.02, -4.529, -17.731, -5.309, -3.535],
[1.869, -4.529, -17.731, -5.309, -3.535],
[1.869, -4.689, -17.667, -5.704, -3.482],
[4.572, -4.689, -17.186, -5.704, -2.51],
[4.572, -4.486, -17.186, -5.138, -2.51],
[6.323, -4.486, -16.396, -5.138, -1.933],
[6.323, -4.977, -16.396, -5.319, -1.933],
[7.007, -4.251, -16.577, -5.319, -1.688],
[7.007, -4.251, -16.577, -5.618, -1.688],
[7.338, -3.514, -16.78, -5.618, -1.207],
[7.338, -3.514, -16.78, -4.657, -1.207],
[7.263, -3.877, -15.99, -4.657, -0.822]])
fig = plt.figure()
subplot = fig.add_subplot(111, xlabel='$x$, mm', ylabel='$y$, mm')
contour = subplot.contourf(xs, ys, data, levels=numpy.linspace(-20, 120, 20))
subplot.set_xlim((xs[0], xs[-1]))
subplot.set_ylim((ys[0], ys[-1]))
fig.colorbar(contour)
fig.savefig('t.png')
You can see what's matplotlib is capable of here.

Related

Pyplot: subsequent plots with a gradient of colours [duplicate]

I am plotting multiple lines on a single plot and I want them to run through the spectrum of a colormap, not just the same 6 or 7 colors. The code is akin to this:
for i in range(20):
for k in range(100):
y[k] = i*x[i]
plt.plot(x,y)
plt.show()
Both with colormap "jet" and another that I imported from seaborn, I get the same 7 colors repeated in the same order. I would like to be able to plot up to ~60 different lines, all with different colors.
The Matplotlib colormaps accept an argument (0..1, scalar or array) which you use to get colors from a colormap. For example:
col = pl.cm.jet([0.25,0.75])
Gives you an array with (two) RGBA colors:
array([[ 0. , 0.50392157, 1. , 1. ],
[ 1. , 0.58169935, 0. , 1. ]])
You can use that to create N different colors:
import numpy as np
import matplotlib.pylab as pl
x = np.linspace(0, 2*np.pi, 64)
y = np.cos(x)
pl.figure()
pl.plot(x,y)
n = 20
colors = pl.cm.jet(np.linspace(0,1,n))
for i in range(n):
pl.plot(x, i*y, color=colors[i])
Bart's solution is nice and simple but has two shortcomings.
plt.colorbar() won't work in a nice way because the line plots aren't mappable (compared to, e.g., an image)
It can be slow for large numbers of lines due to the for loop (though this is maybe not a problem for most applications?)
These issues can be addressed by using LineCollection. However, this isn't too user-friendly in my (humble) opinion. There is an open suggestion on GitHub for adding a multicolor line plot function, similar to the plt.scatter(...) function.
Here is a working example I was able to hack together
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
def multiline(xs, ys, c, ax=None, **kwargs):
"""Plot lines with different colorings
Parameters
----------
xs : iterable container of x coordinates
ys : iterable container of y coordinates
c : iterable container of numbers mapped to colormap
ax (optional): Axes to plot on.
kwargs (optional): passed to LineCollection
Notes:
len(xs) == len(ys) == len(c) is the number of line segments
len(xs[i]) == len(ys[i]) is the number of points for each line (indexed by i)
Returns
-------
lc : LineCollection instance.
"""
# find axes
ax = plt.gca() if ax is None else ax
# create LineCollection
segments = [np.column_stack([x, y]) for x, y in zip(xs, ys)]
lc = LineCollection(segments, **kwargs)
# set coloring of line segments
# Note: I get an error if I pass c as a list here... not sure why.
lc.set_array(np.asarray(c))
# add lines to axes and rescale
# Note: adding a collection doesn't autoscalee xlim/ylim
ax.add_collection(lc)
ax.autoscale()
return lc
Here is a very simple example:
xs = [[0, 1],
[0, 1, 2]]
ys = [[0, 0],
[1, 2, 1]]
c = [0, 1]
lc = multiline(xs, ys, c, cmap='bwr', lw=2)
Produces:
And something a little more sophisticated:
n_lines = 30
x = np.arange(100)
yint = np.arange(0, n_lines*10, 10)
ys = np.array([x + b for b in yint])
xs = np.array([x for i in range(n_lines)]) # could also use np.tile
colors = np.arange(n_lines)
fig, ax = plt.subplots()
lc = multiline(xs, ys, yint, cmap='bwr', lw=2)
axcb = fig.colorbar(lc)
axcb.set_label('Y-intercept')
ax.set_title('Line Collection with mapped colors')
Produces:
Hope this helps!
An anternative to Bart's answer, in which you do not specify the color in each call to plt.plot is to define a new color cycle with set_prop_cycle. His example can be translated into the following code (I've also changed the import of matplotlib to the recommended style):
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2*np.pi, 64)
y = np.cos(x)
n = 20
ax = plt.axes()
ax.set_prop_cycle('color',[plt.cm.jet(i) for i in np.linspace(0, 1, n)])
for i in range(n):
plt.plot(x, i*y)
If you are using continuous color pallets like brg, hsv, jet or the default one then you can do like this:
color = plt.cm.hsv(r) # r is 0 to 1 inclusive
Now you can pass this color value to any API you want like this:
line = matplotlib.lines.Line2D(xdata, ydata, color=color)
This approach seems to me like the most concise, user-friendly and does not require a loop to be used. It does not rely on user-made functions either.
import numpy as np
import matplotlib.pyplot as plt
# make 5 lines
n_lines = 5
x = np.arange(0, 2).reshape(-1, 1)
A = np.linspace(0, 2, n_lines).reshape(1, -1)
Y = x # A
# create colormap
cm = plt.cm.bwr(np.linspace(0, 1, n_lines))
# plot
ax = plt.subplot(111)
ax.set_prop_cycle('color', list(cm))
ax.plot(x, Y)
plt.show()
Resulting figure here

How to draw vertical average lines for overlapping histograms in a loop

I'm trying to draw with matplotlib two average vertical line for every overlapping histograms using a loop. I have managed to draw the first one, but I don't know how to draw the second one. I'm using two variables from a dataset to draw the histograms. One variable (feat) is categorical (0 - 1), and the other one (objective) is numerical. The code is the following:
for chas in df[feat].unique():
plt.hist(df.loc[df[feat] == chas, objective], bins = 15, alpha = 0.5, density = True, label = chas)
plt.axvline(df[objective].mean(), linestyle = 'dashed', linewidth = 2)
plt.title(objective)
plt.legend(loc = 'upper right')
I also have to add to the legend the mean and standard deviation values for each histogram.
How can I do it? Thank you in advance.
I recommend you using axes to plot your figure. Pls see code below and the artist tutorial here.
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
mu1, sigma1 = 100, 8
mu2, sigma2 = 150, 15
x1 = mu1 + sigma1 * np.random.randn(10000)
x2 = mu2 + sigma2 * np.random.randn(10000)
fig, ax = plt.subplots(1, 1, figsize=(7.2, 7.2))
# the histogram of the data
lbs = ['a', 'b']
colors = ['r', 'g']
for i, x in enumerate([x1, x2]):
n, bins, patches = ax.hist(x, 50, density=True, facecolor=colors[i], alpha=0.75, label=lbs[i])
ax.axvline(bins.mean())
ax.legend()

i am trying to plot an scatter graph but the result shows only x labels . why ylabel is not display?

in my code, if I call pred and test object I get these results.
Pred = array([16.88414476, 33.73226078, 75.357018 , 26.79480124, 60.49103328])
test = array([20, 27, 69, 30, 62], dtype=int64)
I apply:
plt.scatter(pred,test)
How I plot both pred and test results on the graph?
so please help! , how to find the desired output.
Scatter plot would take the given two values as x and y values of the plot.
If you want to plot both of them as separate data, use plt.plot
import matplotlib.pyplot as plt
import numpy as np
Pred = np.array([16.88414476, 33.73226078, 75.357018 , 26.79480124, 60.49103328])
test = np.array([20, 27, 69, 30, 62])
plt.plot(Pred)
plt.plot(test, linestyle='--')
Use could also use the pandas plot functionality
pd.DataFrame({'pred': Pred, 'test': test}).plot()
I think it is not possible to plot 2 arrays in scatter but you can do it in a plot
from matplotlib import pyplot as plt
import numpy as np
Pred = np.array([16.88414476, 33.73226078, 75.357018 , 26.79480124, 60.49103328])
test = np.array([20, 27, 69, 30, 62])
plt.plot(Pred, label='Pred Label')
plt.plot(test, label='Test Label')
plt.legend() # To Show the the labels' names

How to visualize a list of strings on a colorbar in matplotlib

I have a dataset like
x = 3,4,6,77,3
y = 8,5,2,5,5
labels = "null","exit","power","smile","null"
Then I use
from matplotlib import pyplot as plt
plt.scatter(x,y)
colorbar = plt.colorbar(labels)
plt.show()
to make a scatter plot, but cannot make colorbar showing labels as its colors.
How to get this?
I'm not sure, if it's a good idea to do that for scatter plots in general (you have the same description for different data points, maybe just use some legend here?), but I guess a specific solution to what you have in mind, might be the following:
from matplotlib import pyplot as plt
# Data
x = [3, 4, 6, 77, 3]
y = [8, 5, 2, 5, 5]
labels = ('null', 'exit', 'power', 'smile', 'null')
# Customize colormap and scatter plot
cm = plt.cm.get_cmap('hsv')
sc = plt.scatter(x, y, c=range(5), cmap=cm)
cbar = plt.colorbar(sc, ticks=range(5))
cbar.ax.set_yticklabels(labels)
plt.show()
This will result in such an output:
The code combines this Matplotlib demo and this SO answer.
Hope that helps!
EDIT: Incorporating the comments, I can only think of some kind of label color dictionary, generating a custom colormap from the colors, and before plotting explicitly grabbing the proper color indices from the labels.
Here's the updated code (I added some additional colors and data points to check scalability):
from matplotlib import pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
# Color information; create custom colormap
label_color_dict = {'null': '#FF0000',
'exit': '#00FF00',
'power': '#0000FF',
'smile': '#FF00FF',
'addon': '#AAAAAA',
'addon2': '#444444'}
all_labels = list(label_color_dict.keys())
all_colors = list(label_color_dict.values())
n_colors = len(all_colors)
cm = LinearSegmentedColormap.from_list('custom_colormap', all_colors, N=n_colors)
# Data
x = [3, 4, 6, 77, 3, 10, 40]
y = [8, 5, 2, 5, 5, 4, 7]
labels = ('null', 'exit', 'power', 'smile', 'null', 'addon', 'addon2')
# Get indices from color list for given labels
color_idx = [all_colors.index(label_color_dict[label]) for label in labels]
# Customize colorbar and plot
sc = plt.scatter(x, y, c=color_idx, cmap=cm)
c_ticks = np.arange(n_colors) * (n_colors / (n_colors + 1)) + (2 / n_colors)
cbar = plt.colorbar(sc, ticks=c_ticks)
cbar.ax.set_yticklabels(all_labels)
plt.show()
And, the new output:
Finding the correct middle point of each color segment is (still) not good, but I'll leave this optimization to you.

How to plot values on a Python Basemap?

Is it possible to plot values on a basemap?
Let's say I have 3 lists of data.
lat = [50.3, 62.1, 41.4, ...]
lon = [12.4, 14.3, 3.5, ...]
val = [3, 5.4, 7.4, ...]
I've created a simple basemap:
def create_map(ax=None, lllon=6.00, lllat=47.0, urlon=16.00, urlat=55.10):
m = Basemap(llcrnrlon=lllon, llcrnrlat=lllat, \
urcrnrlon=urlon, urcrnrlat=urlat, \
resolution='h', \
projection='tmerc', \
lon_0=(lllon+urlon)/2, lat_0=(lllat+urlat)/2)
m.drawcoastlines()
m.drawcountries()
m.drawrivers()
return m
Now I want to plot the values of the "val" list on this map depending of their coordinates:
m = create_map()
x, y = m(lon,lat)
m.scatter(x, y, val) # somthing like that
plt.show()
Well, i already figured out that basemap is unable to plot 3d values, but is there a way to realize it?
The short, sweet, and simple answer to your first question is yes, you can plot using basemap (here's the documentation for it).
If you're looking to plot in 3d, there is documentation that explains how to plot using Basemap. Here's a simple script to get you started:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
plt.close('all')
fig = plt.figure()
ax = fig.gca(projection='3d')
extent = [-127, -65, 25, 51]
# make the map and axis.
m = Basemap(llcrnrlon=extent[0], llcrnrlat=extent[2],
urcrnrlon=extent[1], urcrnrlat=extent[3],
projection='cyl', resolution='l', fix_aspect=False, ax=ax)
ax.add_collection3d(m.drawcoastlines(linewidth=0.25))
ax.add_collection3d(m.drawcountries(linewidth=0.25))
ax.add_collection3d(m.drawstates(linewidth=0.25))
ax.view_init(azim = 230, elev = 15)
ax.set_xlabel(u'Longitude (°E)', labelpad=10)
ax.set_ylabel(u'Latitude (°N)', labelpad=10)
ax.set_zlabel(u'Altitude (ft)', labelpad=20)
# values to plot - change as needed. Plots 2 dots, one at elevation 0 and another 100.
# also draws a line between the two.
x, y = m(-85.4808, 32.6099)
ax.plot3D([x, x], [y, y], [0, 100], color = 'green', lw = 0.5)
ax.scatter3D(x, y, 100, s = 5, c = 'k', zorder = 4)
ax.scatter3D(x, y, 0, s = 2, c = 'k', zorder = 4)
ax.set_zlim(0., 400.)
plt.show()

Resources