Plot 3D density plot from many 2D arrays - python-3.x

I am trying to plot a 3D density plot from many 2D numpy arrays of the same shape. Each [x,y] coordinate returns an intensity (how dense it is at that point).
I cannot figure out how to plot this using matplotlib
I'm able to successfully get a contour plot by just plotting one 2D array, or using imshow to get a nice slice of my density at a certain 'z' cut, but just plotting that 2D array.
I have an object: data, which when I apply the method slice() and pass in an integer from 0 to 480, I get a 2D array of that 'z' cross section:
plt.imshow(data.slice(200))
I want to be able to plot a density map by iterating over data.slice(n) for n-> 0 to 480 and plot that on a single image.
I'm not sure how to do such a thing.

If you have lots of slices that you want to view as a density map from one side, you can average over all the cells along a given axis and them view that as an image.
import numpy as np
import matplotlib.pyplot as plt
def plot_projections(d):
# project onto the appropriate plane by averaging
d_mean_0 = d.mean(axis=0)
d_mean_1 = d.mean(axis=1)
d_mean_2 = d.mean(axis=2)
plt.subplot(1, 3, 1)
plt.imshow(d.mean(axis=0), cmap='rainbow')
plt.subplot(1, 3, 2)
plt.imshow(d.mean(axis=1), cmap='rainbow')
plt.subplot(1, 3, 3)
plt.imshow(d.mean(axis=2), cmap='rainbow')
plt.show()
# random seeded 10x10x10 array
d = np.random.randint(0, 10, size=(10,10,10))
plot_projections(d)
# pack matrix with 10s along one plane
for i in range(len(d)):
d[2][i] = np.array([10,10,10,10,10,10,10,10,10,10])
plot_projections(d)

Related

Is there a way to apply 3d-like appearance (like bevel) to 2d matplotlib plots?

I've been working for a while with the matplotlib package in Python, and I know that you can do 2D graphs (usually involving two "dimensions", x and y) or 3D graphs (with functions like plot3D). However, I am unable to find documentation about giving a '3D aesthetic' to a 2D plot.
That is, giving the plot a bit of volume, some shadows, etc.
To give an example, let's say I wanted to create a donut chart in matplotlib. A first draft could be something like this:
import matplotlib.pyplot as plt
#Given an array of values 'values' and,
#optionally, an array of colors 'colors'
#and an array of labels 'labels':
ax = plt.subplot()
ax.pie(
x = values,
labels = labels,
colors = colors
)
center_circle = plt.Circle((0,0), radius = 0.5, fc = "white")
ax.add_artist(center_circle)
plt.show()
However, a quick graph with Excel can give a much more appealing result:
Looking at the documentation of plt.pie, I was not able to find anything significant, apart from the parameter shadow, which when set to True, gives an underwhelming result:
Also, I would like to add effect such as the use of bevel (like the 3d-look of the borders of each wedge of the pie) and more style things. How could I improve the look of my graph with matplotlib? Is it even possible to accomplish it with this library?
One solution might be using a different library. I am not familiar with seaborn, but I know it is also a powerful visualisation library. The same with plotly. Does any one of these libraries allow for these kind of customisations?
There are a whole bunch of options on the matplotlib website for pie charts here: https://matplotlib.org/stable/gallery/pie_and_polar_charts/index.html
Matplotlib does not have a built-in option to add a bevel to a 2D pie chart or any other types of charts directly.
But, you could do this (raised shaddow) for a 3d effect:
import matplotlib.pyplot as plt
# Pie chart, where the slices will be ordered and plotted counter-clockwise:
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
shadow=True, startangle=90)
ax1.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle.
plt.show()
which give this:

Plotting new points in a subspace after dimensionality reduction

I would like to plot points with 100 parameters each with values between 0-99 on a 2 dimensional plot. This should be straightforward with normal methods of dimensionality reduction (PCA/tSNE/UMAP etc) but I need to be able to add subsequent points to the plot without it needing to recalculate and therefore change
I am picturing an algorithm that takes a data-point with it's 100 values and converts it to X,Y coordinates that can then be plotted. Points proximal in the 2D projection are proximal in the original 100D space. Does such an algorithm exist? If not, any alternative approaches?
Thanks
I am not sure I understood the question correctly but with an initial set X, we can fit a PCA to compute the principal components. Then, we can use these principal components to transform new samples.
from sklearn.decomposition import PCA
import numpy as np
import matplotlib.pyplot as plt
n_samples, n_feats = 50, 100
X = np.random.randint(0, 99, size=n_samples * n_feats).reshape(n_samples, n_feats)
pca = PCA(n_components=2).fit(X)
X_reduced = pca.transform(X)
plt.scatter(X[:, 0], X[:, 1])
This plots,
Then, when a new sample comes in
new_sample = np.random.randint(0, 99, size=100).reshape(1, 100)
new_sample_reduced = pca.transform(new_sample)
plt.scatter(new_sample_reduced[:, 0], new_sample_reduced[:, 1], color="red")
We can plot it

How to generate random points uniformly distributed over 40*40 rectangular region centered at (0,0) using python?

I am trying to generate random points uniformly distributed over rectangular region centered at (0,0) using numpy and matplotlib.
The words, random points uniformly distributed is not easy to interprete. This is one of my interpretation shown as a runnable code. Sample output plot is also given.
import matplotlib.pyplot as plt
import numpy as np
# create array of meshgrid over a rectangular region
# range of x: -cn/2, cn/2
# range of y: -rn/2, rn/2
cn, rn = 10, 14 # number of columns/rows
xs = np.linspace(-cn/2, cn/2, cn)
ys = np.linspace(-rn/2, rn/2, rn)
# meshgrid will give regular array-like located points
Xs, Ys = np.meshgrid(xs, ys) #shape: rn x cn
# create some uncertainties to add as random effects to the meshgrid
mean = (0, 0)
varx, vary = 0.007, 0.008 # adjust these number to suit your need
cov = [[varx, 0], [0, vary]]
uncerts = np.random.multivariate_normal(mean, cov, (rn, cn))
# plot the random-like meshgrid
plt.scatter(Xs+uncerts[:,:,0], Ys+uncerts[:,:,1], color='b');
plt.gca().set_aspect('equal')
plt.show()
You can change the values of varx and vary to change the level of randomness of the dot array on the plot.
As #JohanC mentioned in comments, you need points with x and y coordinates between -20 and 20. To create them use:
np.random.uniform(-20, 20, size=(n,2))
with n being your desired number of points.
To plot them:
import matplotlib.pyplot as plt
plt.scatter(a[:,0],a[:,1])
sample plot for n=100 points:

How to interpolate 2D spatial data with kriging in Python?

I have a spatial 2D domain, say [0,1]×[0,1]. In this domain, there are 6 points where some scalar quantity of interest has been observed (e.g., temperature, mechanical stress, fluid density, etc.). How can I predict the quantity of interest at unobserved points? In other words, how may I interpolate spatial data in Python?
For example, consider the following coordinates for points in the 2D domain (inputs) and corresponding observations of the quantity of interest (outputs).
import numpy as np
coordinates = np.array([[0.0,0.0],[0.5,0.0],[1.0,0.0],[0.0,1.0],[0.5,1.],[1.0,1.0]])
observations = np.array([1.0,0.5,0.75,-1.0,0.0,1.0])
The X and Y coordinates can be extracted with:
x = coordinates[:,0]
y = coordinates[:,1]
The following script creates a scatter plot where yellow (resp. blue) represents high (resp. low) output values.
import matplotlib.pyplot as plt
fig = plt.figure()
plt.scatter(x, y, c=observations, cmap='viridis')
plt.colorbar()
plt.show()
I would like to use Kriging to predict the scalar quantity of interest on a regular grid within the 2D input domain. How can I do this in Python?
In OpenTURNS, the KrigingAlgorithm class can estimate the hyperparameters of a Gaussian process model based on the known output values at specific input points. The getMetamodel method of KrigingAlgorithm, then, returns a function which interpolates the data.
First, we need to convert the Numpy arrays coordinates and observations to OpenTURNS Sample objects:
import openturns as ot
input_train = ot.Sample(coordinates)
output_train = ot.Sample(observations, 1)
The array coordinates has shape (6, 2), so it is turned into a Sample of size 6 and dimension 2. The array observations has shape (6,), which is ambiguous: Is it going to be a Sample of size 6 and dimension 1, or a Sample of size 1 and dimension 6? To clarify this, we specify the dimension (1) in the call to the Sample class constructor.
In the following, we define a Gaussian process model with constant trend function and squared exponential covariance kernel:
inputDimension = 2
basis = ot.ConstantBasisFactory(inputDimension).build()
covariance_kernel = ot.SquaredExponential([1.0]*inputDimension, [1.0])
algo = ot.KrigingAlgorithm(input_train, output_train,
covariance_kernel, basis)
We then fit the value of the trend and the parameters of the covariance kernel (amplitude parameter and scale parameters) and obtain a metamodel:
# Fit
algo.run()
result = algo.getResult()
krigingMetamodel = result.getMetaModel()
The resulting krigingMetamodel is a Function which takes a 2D Point as input and returns a 1D Point. It predicts the quantity of interest. To illustrate this, let us build the 2D domain [0,1]×[0,1] and discretize it with a regular grid:
# Create the 2D domain
myInterval = ot.Interval([0.0, 0.0], [1.0, 1.0])
# Define the number of interval in each direction of the box
nx = 20
ny = 10
myIndices = [nx - 1, ny - 1]
myMesher = ot.IntervalMesher(myIndices)
myMeshBox = myMesher.build(myInterval)
Using our krigingMetamodel to predict the values taken by the quantity of interest on this mesh can be done with the following statements. We first get the vertices of the mesh as a Sample, and then evaluate the predictions with a single call to the metamodel (there is no need for a for loop here):
# Predict
vertices = myMeshBox.getVertices()
predictions = krigingMetamodel(vertices)
In order to see the result with Matplotlib, we first have to create the data required by the pcolor function:
# Format for plot
X = np.array(vertices[:, 0]).reshape((ny, nx))
Y = np.array(vertices[:, 1]).reshape((ny, nx))
predictions_array = np.array(predictions).reshape((ny,nx))
The following script produces the plot:
# Plot
import matplotlib.pyplot as plt
fig = plt.figure()
plt.pcolor(X, Y, predictions_array)
plt.colorbar()
plt.show()
We see that the predictions of the metamodel are equal to the observations at the observed input points.
This metamodel is a smooth function of the coordinates: its smoothness increases with covariance kernel smoothness and squared exponential covariance kernels happen to be smooth.

Plot several boxplots in one figure

I am using python-3.x and I would like to plot several boxplots in one figure, all the data from one numpy array where the shape of this array is (100, 301)
If I use the code below it will plot them all (I will have 301 boxplots in one figure which is too much)
fig, ax = plt.subplots()
ax.boxplot(my_data)
plt.show()
I don't want to plot all the data, I just want to plot 10, 15 or 20 (variable number) of the data by using for loop or any method that work best.
for example, I want to plot boxplots every 50 number of data that mean I will have around 6 boxplots from 301 in my figure, I tried to use for loop but no luck
Any advice would be much appreciated
You can just use indexing to plot every 50th data points using a variable step. To have separate box plots and avoid overlapping, you can specify the positions of individual box plot using the positions parameter. my_data[:, ::step] gives you the desired data to plot. Below is an example using some random data.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
my_data = np.random.randint(0, 20, (100, 301))
step = 50
posit = range(my_data[:, ::step].shape[1])
ax.boxplot(my_data[:, ::step], positions=posit)
plt.show()

Resources