How to plot with mplot3d - python

I am trying to plot the solutions of a minimization problem,
'X, Y = meshgrid(gammas, psis)'
gammas and psis are my 2 axes,
'mplot3d(X, Y, x)'
x is the solution of my problem,
While executing my script : name 'mplot3d' is not defined......

import pylab
def scatterme(x, y, z):
pylab.figure()
imi = pylab.scatter(x, y, c = z, edgecolor = "none")
pylab.colorbar(imi)
pylab.show()
In this case, my x and y are what for you would be X.flatten() and Y.flatten() and the z would be your x.flatten(). This code also works if your data does not come from something square, so if you just want to see what something looks like, if you have a lot of x and y values, and for each one you have a z, this shows you what you want as well.
Note: this is not a 3D plot, but i (personnal opinion) feel that a scatterplot in which the z-dimension is your colorbar seems to show much more what you need to know, compared to a 3D plot that you have to rotate around all the time, to be able to see at the angle that might show you something you want to know
Edit:
for the full code, that you can just copypaste (put this after the first piece in my post)
import numpy
X,Y = meshgrid(gammas, psis)
scatterme(X.flatten(), Y.flatten(), x.flatten())

Related

Matplotlib: bar/bin style plot of a piecewise constant function

I want to make a demonstration for the approximation of an integral of a continuous function with piecewise constant step functions.
The resulting plot should look something like this:
I have the piece constant function, my problem is that I don't know how to plot it since the typical candidates don't seem to work:
It looks similar to a histogram, but is generated very differently.
And from what I have seen bar-charts don't align to the number line.
The plt.step() method on the other hand does not include the bins/bars; using it I got this so far:
with this code
kwargs = dict(drawstyle = 'steps-mid')
plt.plot(times, f(times), '-')
plt.plot(times, fitted_values, **kwargs)
Is there a dedicated function, or some kwargs argument that I overlooked, that can plot what I need here?
Edit:
Thank you for the answer #Stef ! I just tried this solution and recognized an issue with a bar-plot here.
plt generates a bar for every value in the times array. Now I get this result:
You can use bar with the align parameter:
import numpy as np
x = np.linspace(0, 1, 11)
y = x**2 + 1
plt.plot(x, y, 'r-')
plt.bar(x, y, width=0.1, align='edge', fc='lightgreen', ec='k')
plt.xlim(0, 1)

Heatmap in Python using matplotlib from 3 independent arrays

I would like to do a heatmap plot using three independent vectors x, y and z. I have looked at examples over the internet and most of them show how to do heatmap plot for x, y and z represented as a 2D matrix
So, can someone please help me on how can I convert 3 independent vectors to a 2d matrix, which I can eventually use for doing heatmap plots
One thing that I thought was to create matrix by first discretizing and arranging in ascending order x and y, and finding z at the new "x" and "y" combinations. But, there could be cases in which "z" cannot be computed due to lack of data during interpolation
I am bit confused, and I would like to seek help in this regard
Have a look at pcolormesh. It does what you need: create a heat map of data that do not lie on a regular grid. You can specify how the data are interpolated (and extrapolated).
From the docs:
matplotlib.pyplot.pcolormesh(*args, alpha=None, norm=None, cmap=None, vmin=None, vmax=None, shading='flat', antialiased=False, data=None, **kwargs)
Create a pseudocolor plot with a non-regular rectangular grid.
Call signature:
pcolor([X, Y,] C, **kwargs)
X and Y can be used to specify the corners of the quadrilaterals.
Thank you group memebers. With your help, I have been able to reach closer to the solution. The thing that I did was
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
x = mdf_merged.get('VariableX').samples
y = mdf_merged.get('VariableY').samples
z = mdf_merged.get('VariableZ').samples
###
xi = np.linspace(min(x),max(x),10)
yi = np.linspace(min(y),max(y),20)
zi = griddata((x, y), z, (xi[None,:], yi[:,None]), method='linear')
plt.pcolormesh(xi, yi, zi)

Rainbow scatter plot Python

I have to make the following scatterplot in python. The code for this plot is :
n = 1024
X = np.random.normal(0,1,n)
Y = np.random.normal(0,1,n)
plt.scatter(X,Y)
But as espected, this wont give the colours. I've tried a lot, but can't find the solution. I know it has something to do with the angle of X/Y in the plot, but can't find out how to do this.
The logic is most likely angle from origo to point. This can be calculated easily with np.arctan2(X, Y). I don't know which colormap that is used in your example but you can probably find it here: https://matplotlib.org/examples/color/colormaps_reference.html
Use the angles of the points to the c keyword in plt.scatter
To get something similar to your example:
plt.scatter(X,Y, c=np.arctan2(X, Y), cmap='rainbow', s=50, alpha=0.8)

Add colorbar to scatter plot or change the plot type

I am plotting some data that includes spatial (x, y) components as well as a z component, which is the value of the measurement at that point in space. I was looking at the gallery, and I'm just not getting it. I think that what I want is a pcolormesh, but I don't understand what I need to put in for arguments. I finally had success getting a scatter plot to do basically what I want, but it's less pretty than I want. If I could figure out a way to make the points in the scatter plot bigger, I would be a lot happier with my plot. Furthermore, I am stuck on trying to add a legend - I only need the colorbar portion, since the end user doesn't really care about the X and Y dimensions. Looking at the colorbar example, it seems that I need to add an axis, but I don't understand how I'm telling it that the axis I need is the Z axis.
x_vals = list(first_array[data_loc_dictionary['x_coord_index']][:])
y_vals = list(first_array[data_loc_dictionary['y_coord_index']][:])
y_vals = [-i for i in y_vals]
z_vals = list(first_array[data_loc_dictionary['value_index']][:])
plt.scatter(x_vals, y_vals, s = len(x_vals)^2, c = z_vals, cmap = 'rainbow')
plt.show()
Here is an example of what I am trying to duplicate:
And here is what the code above produces:
I would like the second to look a little more like the first, i.e., if there were a way to adjust the markers to be large enough to approximate that look, that would be ideal
I am struggling with creating a legend. Colorbar seems to be the way to go, but I am not comprehending how to specify that it needs to be based on the Z values.
Good catch with the ^2 -
What about this basic example:
# generate random data
In [63]: x = np.random.rand(20)
In [64]: y = np.random.rand(20)
In [65]: z = np.random.rand(20)
# plot it with square markers: marker='s'
In [66]: plt.scatter(x, y, s=len(x)**2, c=z, cmap='rainbow', marker='s')
Out[66]: <matplotlib.collections.PathCollection at 0x39e6c90>
# colorbar
In [67]: c = plt.colorbar(orientation='horizontal')
In [68]: c.set_label('This is a colorbar')
In [69]: plt.show()
The Size of the points is given by
s : scalar or array_like, shape (n, ), optional, default: 20
size in points^2.
I see no reason why s=len(x)**2 is a good choice by default. I would play around with it according to your preference.
In case you want to know how to replicate your initial example image with pcolormesh, I would do:
import numpy as np
import matplotlib.pyplot as plt
f, ax = plt.subplots(figsize=(6, 5))
grid = np.arange(-5, 6)
x, y = np.meshgrid(grid, grid)
z = np.random.randn(len(x), len(y))
mask = (np.abs(x) + np.abs(y)) > 4
z = np.ma.masked_array(z, mask)
mesh = ax.pcolormesh(x - .5, y - .5, z, cmap="coolwarm", vmin=-3, vmax=3)
plt.colorbar(mesh)
To produce:

Plotting mplot3d / axes3D xyz surface plot with log scale?

I've been looking high and low for a solution to this simple problem but I can't find it anywhere! There are a loads of posts detailing semilog / loglog plotting of data in 2D e.g. plt.setxscale('log') however I'm interested in using log scales on a 3d plot(mplot3d).
I don't have the exact code to hand and so can't post it here, however the simple example below should be enough to explain the situation. I'm currently using Matplotlib 0.99.1 but should shortly be updating to 1.0.0 - I know I'll have to update my code for the mplot3d implementation.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = Axes3D(fig)
X = np.arange(-5, 5, 0.025)
Y = np.arange(-5, 5, 0.025)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet, extend3d=True)
ax.set_zlim3d(-1.01, 1.01)
ax.w_zaxis.set_major_locator(LinearLocator(10))
ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f'))
fig.colorbar(surf)
plt.show()
The above code will plot fine in 3D, however the three scales (X, Y, Z) are all linear. My 'Y' data spans several orders of magnitude (like 9!), so it would be very useful to plot it on a log scale. I can work around this by taking the log of the 'Y', recreating the numpy array and plotting the log(Y) on a linear scale, but in true python style I'm looking for smarter solution which will plot the data on a log scale.
Is it possible to produce a 3D surface plot of my XYZ data using log scales, ideally I'd like X & Z on linear scales and Y on a log scale?
Any help would be greatly appreciated. Please forgive any obvious mistakes in the above example, as mentioned I don't have my exact code to have and so have altered a matplotlib gallery example from my memory.
Thanks
Since I encountered the same question and Alejandros answer did not produced the desired Results here is what I found out so far.
The log scaling for Axes in 3D is an ongoing issue in matplotlib. Currently you can only relabel the axes with:
ax.yaxis.set_scale('log')
This will however not cause the axes to be scaled logarithmic but labeled logarithmic.
ax.set_yscale('log') will cause an exception in 3D
See on github issue 209
Therefore you still have to recreate the numpy array
I came up with a nice and easy solution taking inspiration from Issue 209. You define a small formatter function in which you set your own notation.
import matplotlib.ticker as mticker
# My axis should display 10⁻¹ but you can switch to e-notation 1.00e+01
def log_tick_formatter(val, pos=None):
return f"$10^{{{int(val)}}}$" # remove int() if you don't use MaxNLocator
# return f"{10**val:.2e}" # e-Notation
ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
ax.zaxis.set_major_locator(mticker.MaxNLocator(integer=True))
set_major_locator sets the exponential to only use integers 10⁻¹, 10⁻² without 10^-1.5 etc. Source
Important! remove the cast int() in the return statement if you don't use set_major_locator and you want to display 10^-1.5 otherwise it will still print 10⁻¹ instead of 10^-1.5.
Example:
Try it yourself!
from mpl_toolkits.mplot3d import axes3d
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
fig = plt.figure(figsize=(11,8))
ax1 = fig.add_subplot(121,projection="3d")
# Grab some test data.
X, Y, Z = axes3d.get_test_data(0.05)
# Now Z has a range from 10⁻³ until 10³, so 6 magnitudes
Z = (np.full((120, 120), 10)) ** (Z / 20)
ax1.plot_wireframe(X, Y, Z, rstride=10, cstride=10)
ax1.set(title="Linear z-axis (small values not visible)")
def log_tick_formatter(val, pos=None):
return f"$10^{{{int(val)}}}$"
ax2 = fig.add_subplot(122,projection="3d")
# You still have to take log10(Z) but thats just one operation
ax2.plot_wireframe(X, Y, np.log10(Z), rstride=10, cstride=10)
ax2.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
ax2.zaxis.set_major_locator(mticker.MaxNLocator(integer=True))
ax2.set(title="Logarithmic z-axis (much better)")
plt.savefig("LinearLog.png", bbox_inches='tight')
plt.show()
in osx: ran ax.zaxis._set_scale('log') (notice the underscore)
There is no solution because of the issue 209. However, you can try doing this:
ax.plot_surface(X, np.log10(Y), Z, cmap='jet', linewidth=0.5)
If in "Y" there is a 0, it is going to appear a warning but still works. Because of this warning color maps don´t work, so try to avoid 0 and negative numbers. For example:
Y[Y != 0] = np.log10(Y[Y != 0])
ax.plot_surface(X, Y, Z, cmap='jet', linewidth=0.5)
I wanted a symlog plot and, since I fill the data array by hand, I just made a custom function to calculate the log to avoid having negative bars in the bar3d if the data is < 1:
import math as math
def manual_log(data):
if data < 10: # Linear scaling up to 1
return data/10
else: # Log scale above 1
return math.log10(data)
Since I have no negative values, I did not implement handling this values in this function, but it should not be hard to change it.

Categories

Resources