Plotly vertical 3D surface plot in z-x plane not showing up - python

I want to plot a plane in the z-x plane, but I am having problems.
I am able to successfully plot the plane into the z-y plane with the following code:
import plotly.graph_objects as go
import numpy as np
x1 = np.zeros(100)
y1 = np.linspace(-5, 5, 100)
z1 = np.linspace(-2.5, 2.5, 50)
rc = np.random.rand(100,50) # random surface colors
plane = go.Surface(x=x1, y=y1, z=np.array([z1] * len(x1)), surfacecolor=rc)
figure = go.Figure()
figure.add_traces([plane])
figure.show()
This gives the following figure:
To plot the same in the z-x plane, this should be achievable (from my understanding) by simply swapping the x and y parameters of the surface plot:
plane = go.Surface(x=y1, y=x1, z=np.array([z1] * len(x1)), surfacecolor=rc)
However, now the surface plot never shows up in the figure.
There is no error message or warning and looking at the data representation, all the data fields seem to be set the way they should.
So what am I missing?
Thanks for your feedback

I was having the exact same problem and google sent me here. Searching for a solution, I came across this answer: https://stackoverflow.com/a/62504443
According to the answer, you have to transpose the array of the z argument.
plane = go.Surface(x=y1, y=x1, z=np.array([z1] * len(x1)).T, surfacecolor=rc)
For the surface coloring you would have change to
rc = np.random.rand(100,100)

Related

Python Drawing polygon with real sizes

I'm trying to draw polygons with Python. Polygons are parcel of land with their actual coordinates. So far I have tried matplotlib and tkinter but no result. Is there a library where I can get these polygons scaled and vector based? The scale will be subject to change according to the size of the plot. Like 1/50, 1/100 or 1/200. As a result, can I have an architectural drawing with real coordinates?
Some example:
def fDraw(self, x, y):
x.append(x[0])
y.append(y[0])
xs = np.array(x)
ys = np.array(y)
plt.plot(xs,ys)
plt.show()
y = [19803.76, 19827.50, 19829.54, 19805.39]
x = [21065.67, 21063.77, 21079.64, 21081.62]
VLand.fDraw(x,y)
You'll want to call set_aspect('equal') so the plotted chart retains a square aspect ratio:
import matplotlib.pyplot as plt
xs = [21065.67, 21063.77, 21079.64, 21081.62]
ys = [19803.76, 19827.50, 19829.54, 19805.39]
plt.fill(xs, ys, edgecolor="r", fill=False)
plt.gca().set_aspect('equal')
plt.show()
This renders
which shows the same visual shape as the original screenshot.

3D surface plot in Python using plotly

I have a question about how the plotly surface code works.
I've got the data from dataframe to plot surface 3D graph , 1D array of x , y and z
example :
x (temperatures) = [26,25,24,29,21,20,21,21,26]
y (humidity) = [50,60,50,40,50,70,80,90,90]
z (power consumption) = [12,13,14,11,11,10,11,12,15]
I need to plot each point (ex: x1,y1,z1) to be a surface and I have used this code
import plotly.graph_objects as go
import numpy as np
#x,y,z from above
fig = go.Figure(data = go.Surface(z=z,
x=x,
y=y))
fig.update_traces(contours_z = dict(show = True , usecolormap = True ,
highlightcolor = 'limegreen' , project_z = True))
fig.update_layout(title = 'Linear')
fig.show()
but it doesn't show anything.
(I also known that z need to be 2D array but I don't know why it is)
How can I fix this problem?
Thank you
My answer consists of two parts:
How you can plot this data in 3d.
What's needed to create a 3d surface plot.
Plotting your data in 3D
With the data you have - three vectors of x, y, and z, you can easily create a 3D scatter plot:
fig = go.Figure(data=[go.Scatter3d(x=x, y=y, z=z,
mode='markers')])
fig.show()
Here's what it looks like, and you can rotate it and swivel it in all directions.
3D Surface Plot
To create a 3D surface plot, you need a z-value for each combination of a and y. Think of a surface plot as a map. For each point (x,y) on the map, you need to provide the altitude (z) at that point, so that plotly can create the surface you're looking for.

How to rotate theta ticklabels in a matplotlib polar plot?

In a matplotlib polar plot, I would like to rotate each individual theta ticklabel by a different angle. However, I cannot find anything in the documentation to do that. Here's a simple plot to illustrate:
from matplotlib import pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.axes(polar=True)
ax.set_thetalim(0., np.pi/4.)
ax.set_rlim(0., 2.)
# set the size of theta ticklabels (works)
thetatick_locs = np.linspace(0.,45.,4)
thetatick_labels = [u'%i\u00b0'%np.round(x) for x in thetatick_locs]
ax.set_thetagrids(thetatick_locs, thetatick_labels, fontsize=16)
This adds labels at 0, 15, 30 and 45 degrees. What I'd like to do is rotate the 15 degree label by 15 degrees, the 30 degree label by 30 degrees, and so on, so that each label's text direction is radially outward. Since get_xticklabels on a PolarAxes instance seems to get the theta ticklabels, I tried:
for i,t in enumerate(ax.get_xticklabels()):
t.set_rotation(thetatick_locs[i])
However, that did nothing. Is there any other way of doing what I want? In general, I'm finding that the documentation for polar axes is not as thorough as for rectangular axes, probably because fewer people use it. So maybe there's already a way to do this.
Your current method works for cartesian coordinates but for polar coordinates, you can use the workaround solution presented earlier here. I have adapted that answer for you below. You can add the following code after setting the theta grids
fig.canvas.draw()
labels = []
for label, angle in zip(ax.get_xticklabels(), thetatick_locs):
x,y = label.get_position()
lab = ax.text(x,y, label.get_text(), transform=label.get_transform(),
ha=label.get_ha(), va=label.get_va())
lab.set_rotation(angle)
labels.append(lab)
ax.set_xticklabels([])
plt.show()

Matplotlib plot has slanted lines

I'm trying to plot projections of coordinates onto a line, but for some reason, Matplotlib is plotting the projections in a slightly slanted manner. Ideally, I would like the (blue) projections to be perpendicular to the (green) line. Here's an image of how it looks with sample data:
As you can see, the angles between the blue lines and the green line are slightly obtuse instead of right. I tried playing around with the rotation parameter to the annotate function, but this did not help. The code for this plot is below, although the data might look a bit different since the random generator is not seeded:
import numpy as np
import matplotlib.pyplot as plt
prefs = {'color':'purple','edgecolors':'black'}
X = np.dot(np.random.rand(2,2), np.random.rand(2,50)).T
pts = np.linspace(-1,1)
v1_m = 0.8076549717643662
plt.scatter(X[:,0],X[:,1],**prefs)
plt.plot(pts, [v1_m*x for x in pts], color='lightgreen')
for x,y in X:
# slope of connecting line
# y = mx+b
m = -np.reciprocal(v1_m)
b = y-m*x
# find intersecting point
zx = b/(v1_m-m)
zy = v1_m*zx
# draw line
plt.annotate('',(zx,zy),(x,y),arrowprops=dict(linewidth=2,arrowstyle='-',color='lightblue'))
plt.show()
The problem lies in the unequal axes which makes it look like they are not at a right angle. Use plt.axis('equal') to have equal axis spans on x- and y-axis and a square figure with equal height and width. plt.axis('scaled') works the same way. As pointed out by #CedricZoppolo, you should set the equal aspect ratios before plt.show(). As per docs, setting the aspect ratio to "equal" means
same scaling from data to plot units for x and y
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,8))
# Your code here
plt.axis('equal')
plt.show()
Choosing a square figure is not necessary as it works also with rectangular figures as
fig = plt.figure(figsize=(8,6))
# Your code here
plt.axis('equal')
plt.show()
The blue lines not being perpendicular is due to axis not being equal.
You just need to add below line before plt.show()
plt.gca().set_aspect('equal')
Below you can see the resulted graph:

Create a stack of polar plots using Matplotlib/Python

I need to generate a stack of 2D polar plots (a 3D cylindrical plot) so that I can view a distorted cylinder. I want to use matplotlib since I already have it installed and want to distribute my code to others who only have matplotlib. For example, say I have a bunch of 2-D arrays. Is there any way I can do this without having to download an external package? Here's my code.
#!usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-180.0,190.0,10)
theta = (np.pi/180.0 )*x # in radians
A0 = 55.0
offset = 60.0
R = [116.225,115.105,114.697,115.008,115.908,117.184,118.61,119.998,121.224,122.216,\
122.93,123.323,123.343,122.948,122.134,120.963,119.575,118.165,116.941,116.074,115.66\
,115.706,116.154,116.913,117.894,119.029,120.261,121.518,122.684,123.594,124.059,\
123.917,123.096,121.661,119.821,117.894,116.225]
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8],polar=True) # Polar plot
ax.plot(theta,R,lw=2.5)
ax.set_rmax(1.5*(A0)+offset)
plt.show()
I have 10 more similar 2D polar plots and I want to stack them up nicely. If there's any better way to visualize a distorted cylinder in 3D, I'm totally open to suggestions. Any help would be appreciated. Thanks!
If you want to stack polar charts using matplotlib, one approach is to use the Axes3D module. You'll notice that I used polar coordinates first and then converted them back to Cartesian when I was ready to plot them.
from numpy import *
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
n = 1000
fig = plt.figure()
ax = fig.gca(projection='3d')
for k in linspace(0, 5, 5):
THETA = linspace(0, 2*pi, n)
R = ones(THETA.shape)*cos(THETA*k)
# Convert to Cartesian coordinates
X = R*cos(THETA)
Y = R*sin(THETA)
ax.plot(X, Y, k-2)
plt.show()
If you play with the last argument of ax.plot, it controls the height of each slice. For example, if you want to project all of your data down to a single axis you would use ax.plot(X, Y, 0). For a more exotic example, you can map the height of the data onto a function, say a saddle ax.plot(X, Y, -X**2+Y**2 ). By playing with the colors as well, you could in theory represent multiple 4 dimensional datasets (though I'm not sure how clear this would be). Examples below:

Categories