Setting the labels of a chart - python

I copy this example from matplotlib site and now I want to change the font, color and size of the labels, but not the numbers size. And there is a possiblity to just see the numbers that are in the middle and at the end of each side?
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y = np.mgrid[0:6*np.pi:0.25, 0:4*np.pi:0.25]
Z = np.sqrt(np.abs(np.cos(X) + np.cos(Y)))
surf = ax.plot_surface(X + 1e5, Y + 1e5, Z, cmap='autumn', cstride=2, rstride=2)
ax.set_xlabel("X-Label")
ax.set_ylabel("Y-Label")
ax.set_zlabel("Z-Label")
ax.set_zlim(0, 2)
plt.show()
Thank you

You can change the font size, color and type by setting text properties when you create the label like this:
ax.set_xlabel("X-Label", size = 40, color = 'r', family = 'fantasy')
You can control which tick marks are displayed using ax.set_xticks.

Related

Assigned 3 colors to 3D plot based on Z value python

I am trying to get my 3D python plot into 3 different colors based on the value of Z from a CSV file. I am trying to color a point one specific color, and then points below one color and points above one color. I can get the plot into a color above and below the point, but I can't seem to figure out how to get it into 3 colors.
I have tried to split the Z value into 3 different 3 subsets, but when I tried to plot the plot was just empty. I also tried to write it through an if statement assigning Z to the color but that did not work either. This is the code that works for the 2 color:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import pandas as pd
headers = ['name','ra','x rads','x par','dec','y rads','Parallax','Parallax Error','central distance','Z Max','Z Min']
mergeddata = pd.read_csv(r'C:\Users\GregL\Downloads\mergedata - no neg parallax #s (2).csv')
mergeddata.z = mergeddata['central distance']
mergeddata.x = mergeddata['x par']
mergeddata.y = mergeddata['y rads']
x= mergeddata.x
y= mergeddata.y
z = mergeddata.z
colors = [z <= 1956.783590]
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
surf=ax.scatter3D(x,y,z,c=colors, cmap='coolwarm',s=.5,marker='^')
ax.set_title('3D Data Distance Plot')
ax.set_zlim(-100,10000)
ax.set_xlim(-50,50)
ax.set_ylim(-50,50)
ax.set_xlabel('RA')
ax.set_ylabel('DEC')
ax.set_zlabel('CENTRAL DISTANCE')
plt.show()
Which gives me this plot
As mentioned by Claudio on the comment, you can create a color value and then assign a proper colormap. Here, I'm going to create a discrete color map based on Matplotlib's Tab10:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.colors as col
fig = plt.figure()
ax = plt.axes(projection ='3d')
z = np.linspace(0, 1, 100)
x = z * np.sin(25 * z)
y = z * np.cos(25 * z)
# values for color
c = [int(zv / 0.4) for zv in z]
# discrete colormap with 3 colors
cmap=col.ListedColormap(cm.tab10.colors[:len(np.unique(c))])
ax.scatter(x, y, z, c=c, cmap=cmap)
plt.show()
Alternatively, you can create multiple ax.scatter commands, each one plotting a subset. The advantage of this approach is that you can set custom labels or rendering properties to each subset:
fig = plt.figure()
ax = plt.axes(projection ='3d')
i1 = z < 0.3
i2 = (z >= 0.3) & (z < 0.6)
i3 = z >= 0.6
ax.scatter(x[i1], y[i1], z[i1], label="a")
ax.scatter(x[i2], y[i2], z[i2], label="b")
ax.scatter(x[i3], y[i3], z[i3], label="c")
ax.legend()
plt.show()

Why is a surface plot of integers not displaying properly using matplotlib plot_surface?

I was trying to replicate the answer found here with my own data, which happens to be a 3D numpy array of integers. I got close with the following code:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
data = np.random.randint(0,6,size=(49,512,512))
x = y = np.arange(0, 512, 1)
z = 20
i = data[z,:,:]
z1 = 21
i1 = data[z1,:,:]
z2 = 22
i2 = data[z2,:,:]
# here are the x,y and respective z values
X, Y = np.meshgrid(x, y)
Z = z*np.ones(X.shape)
Z1 = z1*np.ones(X.shape)
Z2 = z2*np.ones(X.shape)
# create the figure, add a 3d axis, set the viewing angle
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.view_init(10,60)
# here we create the surface plot, but pass V through a colormap
# to create a different color for each patch
im = ax.plot_surface(X, Y, Z, facecolors=cm.viridis(i))
ax.plot_surface(X, Y, Z1, facecolors=cm.viridis(i1))
ax.plot_surface(X, Y, Z2, facecolors=cm.viridis(i2))
But this produces the plot below.
There are two things wrong with this plot: (1) the surfaces are a constant color and (2) the color bar doesn't seem to be referencing the data.
Following the advice here, I found that (1) can be solved by replacing data with a set of random numbers data = np.random.random(size=(49,512,512)), which produces the below image.
I think this suggests the integer data in the first image needs to be normalized before displaying properly, but, if it's possible, I would really like to make this plot without normalization; I want integer values to display like the second image. Also, I'm not sure why the color bar isn't connected to the color scale of the images themselves and could use advice on how to fix that. Ideally, the color bar to be connected to all three surfaces, not just the im surface.
Thanks in advance!
First, you have to normalize your data. Then, you pass the normalized data into the colormap to create the face colors:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import matplotlib.colors as colors
data = np.random.randint(0,6,size=(49,512,512))
# create a Normalize object with the correct range
norm = colors.Normalize(vmin=data.min(), vmax=data.max())
# normalized_data contains values between 0 and 1
normalized_data = norm(data)
# extract the appropriate values
z = 20
z1 = 21
z2 = 22
i = normalized_data[z,:,:]
i1 = normalized_data[z1,:,:]
i2 = normalized_data[z2,:,:]
x = y = np.arange(0, 512, 1)
# here are the x,y and respective z values
X, Y = np.meshgrid(x, y)
Z = z*np.ones(X.shape)
Z1 = z1*np.ones(X.shape)
Z2 = z2*np.ones(X.shape)
# create the figure, add a 3d axis, set the viewing angle
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.view_init(10,60)
# here we create the surface plot, but pass V through a colormap
# to create a different color for each patch
im = ax.plot_surface(X, Y, Z, facecolors=cm.viridis(i))
ax.plot_surface(X, Y, Z1, facecolors=cm.viridis(i1))
ax.plot_surface(X, Y, Z2, facecolors=cm.viridis(i2))
# create a scalar mappable to create an appropriate colorbar
sm = cm.ScalarMappable(cmap=cm.viridis, norm=norm)
fig.colorbar(sm)

Colorbars for 2D plots using Numpy, Matplotlib and os (rendering probelm)?

I have multiple .plx files that contain two column of numbers formatted as strings (1.plx , 2.plx...)
I managed to modify a code to load the data, convert it to floats, and plot it with the appropriate colorbar, but there are two issues I couldn't solve:
The color of the lines does not update
The lines rendering looks wrong (probably due to duplicates)
I want to try to avoid that rendering problem by plotting a numpy matrix, so I want to :
Load the data
store it in a numpy matrix (outside the loop so that I can do other data processing stuff)
create a 2D plot with the colorbar
Here is my attempt and the result:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import os
IdVg = [IdVg for IdVg in os.listdir() if IdVg.endswith(".plx")]
n_lines = 20
steps = np.linspace(0.1, 50, 20)
norm = mpl.colors.Normalize(vmin=steps.min(), vmax=steps.max())
cmap = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.BuPu)
cmap.set_array([])
for i in IdVg:
x, y = np.loadtxt(i, delimiter=' ', unpack=True, skiprows= 1, dtype=str)
x = x.astype(np.float64)
y = y.astype(np.float64)
for z, ai in enumerate(steps.T): # Problem here, I want to store x, y values in a 40XN matrix
# (x1, y1, x2, y2...x20, y20) and find a way to plot them
# using Matplotlib and numpy
plt.plot(x, y, c=cmap.to_rgba(z+1))
plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
plt.xlabel('$V_{GS}$ (V)', fontsize=14)
plt.ylabel('$I_{DS}$ (A)', fontsize=14)
plt.tick_params(axis='both', labelsize='12')
plt.grid(True, which="both", ls="-")
plt.colorbar(cmap, ticks=steps)
plt.show()
Thanks !
Since you didn't provide data, I'm going to generate my own. I assume you want to obtain the following result:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import os
n_lines = 20
steps = np.linspace(0.1, 50, 20)
norm = mpl.colors.Normalize(vmin=steps.min(), vmax=steps.max())
norm_steps = norm(steps)
cmap = mpl.cm.BuPu
plt.figure()
x = np.linspace(0, np.pi / 2)
for i in range(n_lines):
y = i / n_lines * np.sin(x)
plt.plot(x, y, c=cmap(norm_steps[i]))
plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
plt.xlabel('$V_{GS}$ (V)', fontsize=14)
plt.ylabel('$I_{DS}$ (A)', fontsize=14)
plt.tick_params(axis='both', labelsize='12')
plt.grid(True, which="both", ls="-")
plt.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.BuPu), ticks=steps)
plt.show()
Obviously, you would have to change the colormap to something more readable in the lower values!

Edit axes appearance on surface plot

My code plots a surface plot for the below data. I want to change the appearance of X and Y axis. Right now it displays only 10 and 100. How can I edit it so that it displays values between them as well? I haven't understood the use of tickformatter in the code, I had received the suggestion from one of the member on the forum for my previous question.
(Please note: Image for reresentation purposes, the below data gives similar image but with different values)
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter, FuncFormatter
from mpl_toolkits.mplot3d import axes3d
import numpy as np
def format_log(x, pos=None):
x1 = 10**x
s = "%.3f" % x1
return s[:-4] if s[-3:]=="000" else " "
fig = plt.figure()
ax = fig.gca(projection='3d')
X=[2,3,5,8,20,30,50,80,100,150,175,200,250,300]
Y=[2,3,4,5,10,15,20,30,40,50,80,100,125,150,175,200]
X = np.log10(np.array(X))
Y = np.log10(np.array(Y))
Y,X=np.meshgrid(Y,X)
Z=np.array([
[0.2885307,0.269452,0.259193,0.2548041,0.2731868,0.4801551,0.7992361,1.7577641,3.2611327,5.428839,19.647976,37.59729,78.0871,152.21466,268.14572,0],
[0.2677955,0.2538363,0.2380033,0.2306999,0.4779794,0.9251045,1.5448972,3.508644,6.4968576,11.252151,0,0,0,0,0,0],
[0.2432982,0.2283371,0.2514196,0.3392502,0,0,0,0,0,0,0,0,0,0,0,0],
[0.2342575,0.3158406,0.4770729, 0.6795485,2.353042, 5.260077,9.78172,25.87004,59.52568, 0,0,0,0,0,0,0],
[0.6735384, 1.3873291,2.346506, 3.5654,0,0,0,0,0,0,0,0,0,0,0,0],
[1.3584715, 2.9405127,5.096819,8.155857,0,0,0,0,0,0,0,0,0,0,0,0],
[3.558062,8.216592,15.768077,27.386694,0,0,0,0,0,0,0,0,0,0,0,0],
[9.537899,25.202589,58.20041,0,0,0,0,0,0,0,0,0,0,0,0,0],
[16.083374,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[54.936775,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[89.185974,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]])
my_col = cm.jet(Z/np.amax(Z))
surf = ax.plot_surface(X, Y, Z,cmap=cm.coolwarm)
ax.set_zlim(0, 300)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
ax.xaxis.set_major_formatter(FuncFormatter(format_log))
ax.yaxis.set_major_formatter(FuncFormatter(format_log))
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
If you are fine with specifying all ticks manually, you can just add something like
ax.set_xticks([np.log10(x) for x in [10, 20, 60, 100]])
ax.set_yticks([np.log10(y) for y in [10, 30, 60, 100]])
Besides, you can follow the "progress" on the 3D-log scale issue here.

Line plot that continuously varies transparency - Matplotlib

I wish to produce a single line plot in Matplotlib that has variable transparency, i.e. it starts from solid color to full transparent color.
I tried this but it didn't work.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 500)
y = np.sin(x)
alphas = np.linspace(1, 0, 500)
fig, ax = plt.subplots(1, 1)
ax.plot(x, y, alpha=alphas)
Matplotlib's "LineCollection" allows you to split the line to be plotted into individual line segments and you can assign a color to each segment. The code example below shows how each horizontal "x" value can be assigned an alpha (transparency) value that indexes into a sequential colormap that runs from transparent to a given color. A suitable colormap "myred" was created using Matplotlib's "colors" module.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import matplotlib.colors as colors
redfade = colors.to_rgb("red") + (0.0,)
myred = colors.LinearSegmentedColormap.from_list('my',[redfade, "red"])
x = np.linspace(0,1, 1000)
y = np.sin(x * 4 * np.pi)
alphas = x * 4 % 1
points = np.vstack((x, y)).T.reshape(-1, 1, 2)
segments = np.hstack((points[:-1], points[1:]))
fig, ax = plt.subplots()
lc = LineCollection(segments, array=alphas, cmap=myred, lw=3)
line = ax.add_collection(lc)
ax.autoscale()
plt.show()
If you are using the standard white background then you can save a few lines by using one of Matplotlib's builtin sequential colormaps that runs from white to a given color. If you remove the lines that created the colormap above and just put the agument cmap="Reds" in the LineCollection function, it creates a visually similar result.
The only solution I found was to plot each segment independently with varying transparency
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 500)
y = np.sin(x)
alphas = np.linspace(1, 0, 499)
fig, ax = plt.subplots(1, 1)
for i in range(499):
ax.plot(x[i:i+2], y[i:i+2], 'k', alpha=alphas[i])
But I don't like it... Maybe this is enough for someone
I don't know how to do this in matplotlib, but it's possible in Altair:
import numpy as np
import pandas as pd
import altair as alt
x = np.linspace(0, 2 * np.pi, 500)
y = np.sin(x)
alt.Chart(
pd.DataFrame({"x": x, "y": y, "o": np.linspace(0, 1, len(x))}),
).mark_point(
).encode(
alt.X("x"),
alt.Y("y"),
alt.Opacity(field="x", type="quantitative", scale=alt.Scale(range=[1, 0]), legend=None),
)
Result:

Categories

Resources