Related
I am working on a project for my final year design.
I have a data-set i have managed to collect that i would like to plot as a heat map over an image.
What i have managed to do so far is shown by this image.
The code i used to make this image is
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde
# Generate fake data
x = dd['B']
y = dd['C']
# Calculate the point density
xy = np.vstack([x,y])
z = gaussian_kde(xy)(xy)
# fig, ax = plt.subplots()
# ax.scatter(x, y, c=z, s=1)
# plt.show()
plt.figure()
plt.imshow(cap)
# plt.scatter(dd['B'],dd['C'],c=dd['A'].apply(lambda x: color(x)),s=2, alpha=0.1)
plt.scatter(x, y, c=z, cmap='Reds', s=1, alpha=0.1)
so my question is how can make a plot like this for the data-set(just an x and y point ) that i have.
Thank you.
Try the following : plt.imshow(z)
I have a figure showing the contourf plot and another showing a plot i've made earlier and I want to plot both on the same figure what should I do?
Here is the code of my contourf plot:
import pylab as pl
from pylab import *
import xlrd
import math
import itertools
from matplotlib import collections as mc
import matplotlib.pyplot as plt
import copy as dc
import pyexcel
from pyexcel.ext import xlsx
import decimal
x_list = linspace(0, 99, 100)
y_list = linspace(0, 99, 100)
X, Y = meshgrid(x_list, y_list, indexing='xy')
Z = [[0 for x in range(len(x_list))] for x in range(len(y_list))]
for each_axes in range(len(Z)):
for each_point in range(len(Z[each_axes])):
Z[len(Z)-1-each_axes][each_point] = power_at_each_point(each_point, each_axes)
figure()
CP2 = contourf(X, Y, Z, cmap=plt.get_cmap('Reds'))
colorbar(CP2)
title('Coverage Plot')
xlabel('x (m)')
ylabel('y (m)')
show()
This is the code of my previously plotted plot:
lc = mc.LineCollection(lines, linewidths=3)
fig, ax = pl.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.margins(0.05)
#The code blow is just for drawing the final plot of the building.
Nodes = xlrd.open_workbook(Node_file_location)
sheet = Nodes.sheet_by_index(0)
Node_Order_Counter = range(1, sheet.nrows + 1)
In_Node_Order_Counter = 0
for counter in range(len(Node_Positions_Ascending)):
plt.plot(Node_Positions_Ascending[counter][0], Node_Positions_Ascending[counter][1], marker='o', color='r',
markersize=6)
pl.text(Node_Positions_Ascending[counter][0], Node_Positions_Ascending[counter][1],
str(Node_Order_Counter[In_Node_Order_Counter]),
color="black", fontsize=15)
In_Node_Order_Counter += 1
#Plotting the different node positions on our plot & numbering them
pl.show()
Without your data we can't see what the plot is supposed to look like, but I have some general recommendations.
Don't use pylab. And if you absolutely must use it, use it within its namespace, and don't do from pylab import *. It makes for very sloppy code - for example, linspace and meshgrid are actually from numpy, but it's hard to tell that when you use pylab.
For complicated plotting, don't even use pyplot. Instead, use the direct object plotting interface. For example, to make a normal plot on top of a contour plot, (such as you want to do) you could do the following:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
x = np.linspace(1, 5, 20)
y = np.linspace(2, 5, 20)
z = x[:,np.newaxis] * (y[np.newaxis,:])**2
xx, yy = np.meshgrid(x, y)
ax.contourf(xx, yy, z, cmap='Reds')
ax.plot(x, 0.2*y**2)
plt.show()
Notice that I only used pyplot to create the figure and axes, and show them. The actual plotting is done using the AxesSubplot object.
I have a range of points x and y stored in numpy arrays.
Those represent x(t) and y(t) where t=0...T-1
I am plotting a scatter plot using
import matplotlib.pyplot as plt
plt.scatter(x,y)
plt.show()
I would like to have a colormap representing the time (therefore coloring the points depending on the index in the numpy arrays)
What is the easiest way to do so?
Here is an example
import numpy as np
import matplotlib.pyplot as plt
x = np.random.rand(100)
y = np.random.rand(100)
t = np.arange(100)
plt.scatter(x, y, c=t)
plt.show()
Here you are setting the color based on the index, t, which is just an array of [1, 2, ..., 100].
Perhaps an easier-to-understand example is the slightly simpler
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(100)
y = x
t = x
plt.scatter(x, y, c=t)
plt.show()
Note that the array you pass as c doesn't need to have any particular order or type, i.e. it doesn't need to be sorted or integers as in these examples. The plotting routine will scale the colormap such that the minimum/maximum values in c correspond to the bottom/top of the colormap.
Colormaps
You can change the colormap by adding
import matplotlib.cm as cm
plt.scatter(x, y, c=t, cmap=cm.cmap_name)
Importing matplotlib.cm is optional as you can call colormaps as cmap="cmap_name" just as well. There is a reference page of colormaps showing what each looks like. Also know that you can reverse a colormap by simply calling it as cmap_name_r. So either
plt.scatter(x, y, c=t, cmap=cm.cmap_name_r)
# or
plt.scatter(x, y, c=t, cmap="cmap_name_r")
will work. Examples are "jet_r" or cm.plasma_r. Here's an example with the new 1.5 colormap viridis:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(100)
y = x
t = x
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.scatter(x, y, c=t, cmap='viridis')
ax2.scatter(x, y, c=t, cmap='viridis_r')
plt.show()
Colorbars
You can add a colorbar by using
plt.scatter(x, y, c=t, cmap='viridis')
plt.colorbar()
plt.show()
Note that if you are using figures and subplots explicitly (e.g. fig, ax = plt.subplots() or ax = fig.add_subplot(111)), adding a colorbar can be a bit more involved. Good examples can be found here for a single subplot colorbar and here for 2 subplots 1 colorbar.
To add to wflynny's answer above, you can find the available colormaps here
Example:
import matplotlib.cm as cm
plt.scatter(x, y, c=t, cmap=cm.jet)
or alternatively,
plt.scatter(x, y, c=t, cmap='jet')
Subplot Colorbar
For subplots with scatter, you can trick a colorbar onto your axes by building the "mappable" with the help of a secondary figure and then adding it to your original plot.
As a continuation of the above example:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = x
t = x
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.scatter(x, y, c=t, cmap='viridis')
ax2.scatter(x, y, c=t, cmap='viridis_r')
# Build your secondary mirror axes:
fig2, (ax3, ax4) = plt.subplots(1, 2)
# Build maps that parallel the color-coded data
# NOTE 1: imshow requires a 2-D array as input
# NOTE 2: You must use the same cmap tag as above for it match
map1 = ax3.imshow(np.stack([t, t]),cmap='viridis')
map2 = ax4.imshow(np.stack([t, t]),cmap='viridis_r')
# Add your maps onto your original figure/axes
fig.colorbar(map1, ax=ax1)
fig.colorbar(map2, ax=ax2)
plt.show()
Note that you will also output a secondary figure that you can ignore.
Single colorbar for multiple subplots
sometimes it is preferable to have a single colorbar to indicate data values visualised on multiple subplots.
In this case, a Normalize() object needs to be created using the minimum and maximum data values across both plots.
Then a colorbar object can be created from a ScalarMappable() object, which maps between scalar values and colors.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = x
t1 = x # Colour data for first plot
t2 = 2*x # Color data for second plot
all_data = np.concatenate([t1, t2])
# Create custom Normalise object using the man and max data values across both subplots to ensure colors are consistent on both plots
norm = plt.Normalize(np.min(all_data), np.max(all_data))
fig, axs = plt.subplots(1, 2)
axs[0].scatter(x, y, c=t1, cmap='viridis', norm=norm)
axs[1].scatter(x**2, y, c=t2, cmap='viridis', norm=norm)
# Create the colorbar
smap = plt.cm.ScalarMappable(cmap='viridis', norm=norm)
cbar = fig.colorbar(smap, ax=axs, fraction=0.1, shrink = 0.8)
cbar.ax.tick_params(labelsize=11)
cbar.ax.set_ylabel('T', rotation=0, labelpad = 15, fontdict = {"size":14})
plt.show()
subplots_colorbar
I am trying to plot a surface using matplotlib using the code below:
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d, Axes3D
import pylab as p
vima=0.5
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 16.67, vima)
Y = np.arange(0, 12.5, vima)
X, Y = np.meshgrid(X, Y)
Z = np.sqrt(((1.2*Y+0.6*X)**2+(0.2*Y+1.6*X)**2)/(0.64*Y**2+0.36*X**2))
surf = ax.plot_surface(X, Y, Z,rstride=1, cstride=1, alpha=1,cmap=cm.jet, linewidth=0)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
If you run it you will see a blue surface, but I want to use the whole color range of jet... I know there is a class "matplotlib.colors.Normalize", but I don't know how to use it. Could you please add the necessary code in order to do it?
I realise that the poster's issue has already been resolved, but the question of normalizing the colors was never dealt with. Since I've figured out how I thought I'd just drop this here for anyone else who might need it.
First you create a norm and pass that to the plotting function, I've tried to add this to the OP's code.
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d, Axes3D
import pylab as p
import matplotlib
vima=0.5
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 16.67, vima)
Y = np.arange(0, 12.5, vima)
X, Y = np.meshgrid(X, Y)
Z = np.sqrt(((1.2*Y+0.6*X)**2+(0.2*Y+1.6*X)**2)/(0.64*Y**2+0.36*X**2))
Z = np.nan_to_num(Z)
# Make the norm
norm = matplotlib.colors.Normalize(vmin = np.min(Z), vmax = np.max(Z), clip = False)
# Plot with the norm
surf = ax.plot_surface(X, Y, Z,rstride=1, cstride=1, norm=norm, alpha=1,cmap=cm.jet, linewidth=0)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
The norm works the same way for the "imshow" command.
As JoshAdel noted in a comment (credit belongs to him), it appears that the surface plot is improperly ranging the colormap when a NaN is in the Z array. A simple work-around is to simply convert the NaN's to zero or very large or very small numbers so that the colormap can be normalized to the z-axis range.
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d, Axes3D
import pylab as p
vima=0.5
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 16.67, vima)
Y = np.arange(0, 12.5, vima)
X, Y = np.meshgrid(X, Y)
Z = np.sqrt(((1.2*Y+0.6*X)**2+(0.2*Y+1.6*X)**2)/(0.64*Y**2+0.36*X**2))
Z = np.nan_to_num(Z) # added this line
surf = ax.plot_surface(X, Y, Z,rstride=1, cstride=1, alpha=1,cmap=cm.jet, linewidth=0)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Replying to an old question, I know, but the answers posted were at least in my case somewhat unsatisfactory. For those still stumbling here, I give a solution that worked for me.
Firstly, I did not want use zeros to replace NaNs, as for me they represent points with missing or undefined data. I'd rather not have anything plotted at these points. Secondly, the whole z range of my data was way above zero, so dotting the plot with zeros would result in an ugly and badly scaled plot.
Solution given by leifdenby was quite close, so +1 for that (though as pointed out, the explicit normalisation does not add to the earlier solution). I just dropped the NaN-to-zero replacement, and used the functions nanmin and nanmax instead of min and max in the color scale normalisation. These functions give the min and max of an array but simply ignore all NaNs. The code now reads:
# Added colors to the matplotlib import list
from matplotlib import cm, colors
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d, Axes3D
import pylab as p
vima=0.5
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 16.67, vima)
Y = np.arange(0, 12.5, vima)
X, Y = np.meshgrid(X, Y)
Z = np.sqrt(((1.2*Y+0.6*X)**2+(0.2*Y+1.6*X)**2)/(0.64*Y**2+0.36*X**2))
# MAIN IDEA: Added normalisation using nanmin and nanmax functions
norm = colors.Normalize(vmin = np.nanmin(Z),
vmax = np.nanmax(Z))
# Added the norm=norm parameter
surf = ax.plot_surface(X, Y, Z,rstride=1, cstride=1, alpha=1, norm=norm, cmap=cm.jet, linewidth=0)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Running this, I get a correctly scaled plot, with the (0, 0) datapoint missing. This is also the behaviour that I find most preferable, as the limit (x, y) to (0, 0) does not seem to exist for the function in question.
This has been my first contribution to StackOverflow, I hope it was a good one (wink).
I am using matplotlib for doing this
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [6,3,6,9,12,24]
y = [3,5,78,12,23,56]
ax.plot(x, y, zs=0, zdir='z', label='zs=0, zdir=z')
plt.show()
Now this builds a graph that is horizontal in the 3d space. How do I make the graph vertical so that it faces the user?
What I want to do is build multiple such vertical graphs that are separated by some distance and are facing the user.
bp's answer might work fine, but there's a much simpler way.
Your current graph is 'flat' on the z-axis, which is why it's horizontal. You want it to be vertical, which means that you want it to be 'flat' on the y-axis. This involves the tiniest modification to your code:
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [6,3,6,9,12,24]
y = [3,5,78,12,23,56]
# put 0s on the y-axis, and put the y axis on the z-axis
ax.plot(xs=x, ys=[0]*len(x), zs=y, zdir='z', label='ys=0, zdir=z')
plt.show()
Then you can easily have multiple such graphs by using different values for the ys parameter (for example, ys=[2]*len(x) instead would put the graph slightly behind).
Mayavi, in particular the mlab module, provides powerful 3D plotting that will work on large and or complex data, and should be easy to use on numpy arrays.
You can set the view angle of the 3d plot with the view_init() function. The example below is for version 1.1 of matplotlib.
from mpl_toolkits.mplot3d import axes3d
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = [6,3,6,9,12,24]
y = [3,5,78,12,23,56]
ax.plot(x, y, zs=0, zdir='z', label='zs=0, zdir=z')
ax.view_init(90, -90)
plt.show()
According to the documentation you want to use the ax.plot_surface(x,y,z) method. More information and chart types here.
The following should work:
x = [1,2,3]
y = [4,5,6]
z = [7,8,9]
data = zip(x,y,z)
#map data on the plane
X, Y = numpy.meshgrid(arange(0, max(x), 1), arange(0, max(y), 1))
Z = numpy.zeros((len(Y), len(X)), 'Float32')
for x_,y_,z_ in data:
Z[x_, y_] = z_ #this should work, but only because x and y are integers
#and arange was done with a step of 1, starting from 0
fig = p.figure()
ax = p3.Axes3D(fig)
ax.plot_surface(X, Y, Z)