How can i change background colour? - python

I made a cuboid with the following code.
##defining to plot the cuboid
def cuboid(center, size):
"""
Create a data array for cuboid plotting.
============= ================================================
Argument Description
============= ================================================
center center of the cuboid, triple
size size of the cuboid, triple, (x_length,y_width,z_height)
:type size: tuple, numpy.array, list
:param size: size of the cuboid, triple, (x_length,y_width,z_height)
:type center: tuple, numpy.array, list
:param center: center of the cuboid, triple, (x,y,z)
"""
ox, oy, oz = center
l, w, h = size
###Added the fig in order to be able to plot it later
ax = fig.gca(projection='3d') ##plot the project cuboid
X=[ox-l/2,ox-l/2,ox-l/2,ox-l/2,ox+l/2,ox+l/2,ox+l/2,ox+l/2] ##corner points of the cuboid
Y=[oy+w/2,oy-w/2,oy-w/2,oy+w/2,oy+w/2,oy-w/2,oy-w/2,oy+w/2]
Z=[oz-h/2,oz-h/2,oz+h/2,oz+h/2,oz+h/2,oz+h/2,oz-h/2,oz-h/2]
ax.scatter(X,Y,Z,c='g',marker='o') #the plot before rotated
X_new = ([]) #attaining new corner points after rotated
Y_new = ([])
Z_new = ([])
for i in range(0,8):
c=np.matrix([[X[i]], ##reading every corner points into matrix format
[Y[i]],
[Z[i]]])
u=Rot_Mat*c ##rotating every corner point with the rotation matrix
X_new = np.append(X_new, u.item(0)) ##appending the corner points with the neighbours
Y_new = np.append(Y_new, u.item(1))
Z_new = np.append(Z_new, u.item(2))
print('\nvertex=\n',c)
print('\nnew_vertex=\n',u)
###Doing a dot product between Rot_Mat and c as earlier but using np.dot as it is necessary with Numpy format, reshaping from(3,1) to (3)
side[i,:] = np.dot(Rot_Mat, c).reshape(3)
sides = [[side[0],side[1],side[2],side[3]], ##defining the 6 sides of cuboid
[side[4],side[5],side[6],side[7]],
[side[0],side[1],side[4],side[5]],
[side[2],side[3],side[4],side[5]],
[side[1],side[2],side[5],side[6]],
[side[4],side[7],side[0],side[3]]]
ax.scatter(X_new,Y_new,Z_new,c='darkred',marker='o') #the plot of corner points after rotated
ax.scatter(ox,oy,oz,c='crimson',marker='o') #the previous plot of center
## Add title
plt.title('Plot_for_PSM', fontsize=20)
##labelling the axes
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.add_collection3d(Poly3DCollection(sides, facecolors='blue', linewidths=1, edgecolors='r', alpha=.25)) ###This draw the plane sides as requred
plt.gca().legend(('previous_center','previous_vertices','rotated_vertices','same_center'))
ax.set_xlim([0,4.5])
ax.set_ylim([-.75,.75])
ax.set_zlim([0,1])
I have few doubts .
I want to plot y&z in one plot. That must be other plot to the given figure as sub plot. The frame must contain y&z axes of which x-axis should not be there. The background frame of the cuboid must be of different colour i.e. rather white black or yellow.
So,can you give any suggestions or code hint in order to solve this.

Related

How to evenly spread annotation imageboxes around a scatterplot?

I would like to annotate a scatterplot with images corresponding to each datapoint. With standard parameters the images end up clashing with each other and other important features such as legend axis, etc. Thus, I would like the images to form a circle or a rectangle around the main scatter plot.
My code looks like this for now and I am struggling to modify it to organise the images around the center point of the plot.
import matplotlib.cbook as cbook
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
import seaborn as sns
#Generate n points around a 2d circle
def generate_circle_points(n, centre_x, center_y, radius=1):
"""Generate n points around a circle.
Args:
n (int): Number of points to generate.
centre_x (float): x-coordinate of circle centre.
center_y (float): y-coordinate of circle centre.
radius (float): Radius of circle.
Returns:
list: List of points.
"""
points = []
for i in range(n):
angle = 2 * np.pi * i / n
x = centre_x + radius * np.cos(angle)
y = center_y + radius * np.sin(angle)
points.append([x, y])
return points
fig, ax = plt.subplots(1, 1, figsize=(7.5, 7.5))
data = pd.DataFrame(data={'x': np.random.uniform(0.5, 2.5, 20),
'y': np.random.uniform(10000, 50000, 20)})
with cbook.get_sample_data('grace_hopper.jpg') as image_file:
image = plt.imread(image_file)
# Set logarithmic scale for x and y axis
ax.set(xscale="log", yscale='log')
# Add grid
ax.grid(True, which='major', ls="--", c='gray')
coordianates = generate_circle_points(n=len(data),
centre_x=0, center_y=0, radius=10)
# Plot the scatter plot
scatter = sns.scatterplot(data=data, x='x', y='y', ax=ax)
for index, row in data.iterrows():
imagebox = OffsetImage(image, zoom=0.05)
imagebox.image.axes = ax
xy = np.array([row['x'], row['y']])
xybox = np.array(coordianates[index])
ab = AnnotationBbox(imagebox, xy,
xycoords='data',
boxcoords="offset points",
xybox=xybox,
pad=0)
ax.add_artist(ab)
for the moment the output looks like this:enter image description here
Ideally I would like the output to look to something like this:
enter image description here
Many thanks in advance for your help
Not an answer but a long comment:
You can control the location of the arrows, but sometimes it is easier to export figures as SVGs and edit them in Adobe Illustrator or Inkscape.
R has a dodge argument which is really nice, but even then is not always perfect. Solutions in Python exist but are laborious.
The major issue is that this needs to be done last as alternations to the plot would make it problematic. A few points need mentioning.
Your figures will have to have a fixed size (57mm / 121mm / 184mm for Science, 83mm / 171mm for RSC, 83mm / 178mm for ACS etc.), if you need to scale the figure in Illustrator keep note of the scaling factor, adding it as a textbox outside of the canvas —as the underlying plot will need to be replaced at least once due to Murphy's law. Exporting at the right size the SVG is ideal. Sounds silly, but it helps. Likewise, make sure the font size does not go under the minimum spec (7-9 points).

what distance represent two adjacents pixels

I have a 3d point cloud. I used matplotlib to draw a scatterplot representing the point cloud viewed from above. The point cloud is stored as a list of coordinates in meters. The output of matplotlib.pyplot.scatter is a png image.
In addition to saving the image, I want to save the correspondence pixels <-> meters. How to do that?
Here the code I use to make my image with matplotlib. I use a dataframe to manipulate the point cloud.
colors = np.array((self.cloud["red"], self.cloud["green"], self.cloud["blue"])).T
dpi = 72
print("dpi: ",dpi)
fig = plt.figure(figsize=(18000/dpi, 18000/dpi), dpi=dpi)
ax = plt.axes(projection='3d')
ax.view_init(elev=90., azim = 0)
ax.set_snap(True)
ax.scatter(
self.cloud["x"],
self.cloud["y"],
self.cloud["z"],
marker=MarkerStyle('.', fillstyle = 'full'),
facecolors=colors / 255,
zdir="z",
#to set a point to 1 pixel we use the relation (dpi/fig.dpi) but
#the problem of the point cloud is the fact that we didn't have a point at each pixel so we increase the size of a point
#the size is empiric so need to be careful
s = (25)**2,
)
plt.axis('off')
self.set_proper_aspect_ratio(ax)
fig.tight_layout()
plt.savefig(file_name, orientation = 'portrait', transparent = True, dpi=fig.dpi)
To find this distance i use this code:
inv = ax.transData.inverted()
#center_image is in pixel
distance_x = abs(inv.transform((center_image[0],center_image[1]))[0])
distance_y = abs(inv.transform((center_image[0],center_image[1]))[1])

Plot 2D array data into figure centered at specific pixel

I have got a figure with with an axis object.
I would like to use ax.scatter to scatter something into the plot, which is no problem. On top I want to draw 2D array data into the same figure (using ax.imshow for example...):
import numpy as np
from matplotlib import pyplot as plt
vidRes = np.array([[-700, 700], [-500,500]])
dim = np.array([vidRes[0,1] - vidRes[0,0],vidRes[1,1] - vidRes[1,0]])
with plt.style.context('dark_background'):
fg = plt.figure()
fg.set_size_inches((10, 10*dim[1]/dim[0]))
ax = fg.add_subplot(111)
ax.set_aspect('equal')
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
ax.set_xlim(vidRes[0,0], vidRes[0,1])
ax.set_ylim(vidRes[1,0], vidRes[1,1])
random = np.random.random(size = (401, 401,),)
ax.imshow(random, cmap = 'hot')
The 2D array has 401x401 entries. Is there a straight forward way to move the imshow object to center it on a given pixel in my 1400x1000 pixel figure? Am I blind to not see it?
The image is drawn into the figure but it is always aligned with the lower left or upper left corner (depending on origin of ax.imshow) to the (0,0) coordinate at the center of my plot, I can't move it anywhere else.
You can use the extent argument. From the docs:
extent : scalars (left, right, bottom, top), optional, default: None
The location, in data-coordinates, of the lower-left and
upper-right corners. If None, the image is positioned such that
the pixel centers fall on zero-based (row, column) indices.
Changing your imshow call to the following line:
ax.imshow(random, cmap = 'hot', extent=[-200.5, 200.5, -200.5, 200.5])
yields:

How to remove white spaces in the graph plot in python?

I have a problem after plotting the graph with matplolib using the python. I got the figure but the figure is having the white spaces of which i don't require. I have read most of the links that were provided by stack overflow but none is regarding to my issue. Now, I want to remove white spaces and require the whole image with picture.
Actually, I am new to the plot in python. I have created a plot of which the black colour is box and the grey colour is the frame.
I created the top vie of the 3D plot this as an image(.png) using the following code.
def cuboid(center, size):
ox, oy, oz = center
l, w, h = size
###Added the fig in order to be able to plot it later
ax = fig.gca(projection='3d') ##plot the project cuboid
X=[ox-l/2,ox-l/2,ox-l/2,ox-l/2,ox+l/2,ox+l/2,ox+l/2,ox+l/2] ##corner points of the cuboid
Y=[oy+w/2,oy-w/2,oy-w/2,oy+w/2,oy+w/2,oy-w/2,oy-w/2,oy+w/2]
Z=[oz-h/2,oz-h/2,oz+h/2,oz+h/2,oz+h/2,oz+h/2,oz-h/2,oz-h/2]
# ax.scatter(X,Y,Z,c='g',marker='o') #the plot before rotated
X_new = ([]) #attaining new corner points after rotated
Y_new = ([])
Z_new = ([])
for i in range(0,8):
c=np.matrix([[X[i]], ##reading every corner points into matrix format
[Y[i]],
[Z[i]]])
u=Rot_Mat*c ##rotating every corner point with the rotation matrix
X_new = np.append(X_new, u.item(0)) ##appending the corner points with the neighbours
Y_new = np.append(Y_new, u.item(1))
Z_new = np.append(Z_new, u.item(2))
print('\nvertex=\n',c)
print('\nnew_vertex=\n',u)
###Doing a dot product between Rot_Mat and c as earlier but using np.dot as it is necessary with Numpy format, reshaping from(3,1) to (3)
side[i,:] = np.dot(Rot_Mat, c).reshape(3)
sides = [[side[0],side[1],side[2],side[3]], ##defining the 6 sides of cuboid
[side[4],side[5],side[6],side[7]],
[side[0],side[1],side[4],side[5]],
[side[2],side[3],side[4],side[5]],
[side[1],side[2],side[5],side[6]],
[side[4],side[7],side[0],side[3]]]
ax.scatter(X_new,Y_new,Z_new,c='blue',marker='') #the plot of corner points after rotated
ax.add_collection3d(Poly3DCollection(sides, facecolors='black', linewidths=1, edgecolors='black', alpha=.25)) ###This draw the plane sides as requred
fig.tight_layout()
# Hide grid lines
ax.grid(False)
# Hide axes ticks
ax.set_xticks([])
ax.set_yticks([])
ax.set_zticks([])
plt.axis('off') #removes the axes from grams
The initialisation data to create this cuboid plot is given as follows:
fig=plt.figure(figsize=(6,6)) ##to obtain figure and dimensions of graph
ax = fig.add_axes([0,0,1,1], projection='3d')
#plot planes
p = Rectangle((0,-0.7), 4.5,1.4, color="lightgrey", alpha=0.2) #plots the background frame
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
i=pd.read_excel('Bond0.dump.xlsx') ##to read the excel file format
X=i['x'] ## to import the variable on to axes from data set
Y=i['y']
Z=i['z']
j=pd.read_excel('paketone4000.dump.xlsx') ##to read the excel file format
X=j['x'] ## to import the variable on to axes from data set
Y=j['y']
Z=j['z']
a=j['x']##import centre of mass from excel file format
b=j['y']
c=j['z']
#cuboid initialising parameters
center = [a[0], b[0], c[0]] ##centre of the body
length = 0.3 ##defining length, breadth, height
width = 0.4
height = 0.1
side = np.zeros((8,3)) ###This numpy vector will be used to store the position of the sides
The expected outcome is that i have to remove the white spaces in the picture and form a picture with the grey frame (vertical dimensions=(0,4.5), horizontal dimention=(-0.7,0.7))

Matplotlib line width based on axis, not on points

If you set a line width in Matplotlib, you have to give the line width in points. In my case, I have two circles, both with radius R and I want to connect them with a line. I want this line to be 2*R wide in order to get a rod-shape. But when I say myLines[i].set_linewidth(2*R) this makes the lines always a specific thickness, regardless of how much I have zoomed in.
Is there a way to make lines a specific thickness not based on the number of pixels or points, but scaling with the axis? How can I make my line have the same width as the diameter of my circles?
I hope I explained myself well enough and I am looking forward to an answer.
Line in Data units
In order to draw a line with the linewidth in data units, you may want to have a look at this answer.
It uses a class data_linewidth_plot which closely resembles the plt.plot() command's signature.
l = data_linewidth_plot( x, y, ax=ax, label='some line', linewidth = 1, alpha = 0.4)
The linewidth argument is interpreted in (y-)data units.
Using this solution there is not even any need for drawing circles, since one may simply use the solid_capstyle="round" argument.
R=0.5
l = data_linewidth_plot( [0,3], [0.7,1.4], ax=ax, solid_capstyle="round",
linewidth = 2*R, alpha = 0.4)
Rod shape
A rod is much more easily produced using a rectange and two circles.
As you already figured out, linewidths are specified in axis space, not data space. To draw a line in data space, draw a rectangle instead:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Circle
r = 5 # rod radius
x1, y1 = (0,0) # left end of rod
x2, y2 = (10,0) # right end of rod
# create 2 circles and a joining rectangle
c1 = Circle((x1, y1), r, color='r')
c2 = Circle((x2, y2), r)
rect = Rectangle((x1, y1-r), width=x2-x1, height=2*r)
# plot artists
fig, ax = plt.subplots(1,1)
for artist in [c2, rect, c1]:
ax.add_artist(artist)
# need to set axis limits manually
ax.set_xlim(x1-r-1, x2+r+1)
ax.set_ylim(y1-r-1, y2+r+1)
# set aspect so circle don't become oval
ax.set_aspect('equal')
plt.show()

Categories

Resources