matplotlib 3d axes ticks, labels, and LaTeX - python

I am running this sample script, with the following modifications:
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, label='parametric curve')
ax.legend()
ax.set_xlabel('$X$', fontsize=20, rotation=150)
ax.set_ylabel('$Y$')
ax.set_zlabel(r'$\gamma$', fontsize=30, rotation=60)
ax.yaxis._axinfo['label']['space_factor'] = 3.0
plt.show()
How do I adjust the axis ticks to that of my choosing? I.e., how would I get the z-axis to only label 2, 0, and -2, and in the font size that I want? I know how to do this in 2D but not 3D.
The script above produces the following:
Why is the x-axis label distorted, which I wanted to do with this script, but not the z-axis label (gamma)? This does not make sense. I need this axis labeled in the Greek letter. How do I fix this?

How do I adjust the axis ticks to that of my choosing? I.e., how would
I get the z-axis to only label 2, 0, and -2, and in the font size that
I want? I know how to do this in 2D but not 3D.
You have to change properties of zticks.
Why is the x-axis label distorted, which I wanted to do with this
script, but not the z-axis label (gamma)? This does not make sense. I
need this axis labeled in the Greek letter. How do I fix this?
You have to disable autorotation for z axis labels. Look at the code below:
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, label='parametric curve')
ax.legend()
ax.set_xlabel('$X$', fontsize=20)
ax.set_ylabel('$Y$')
ax.yaxis._axinfo['label']['space_factor'] = 3.0
# set z ticks and labels
ax.set_zticks([-2, 0, 2])
# change fontsize
for t in ax.zaxis.get_major_ticks(): t.label.set_fontsize(10)
# disable auto rotation
ax.zaxis.set_rotate_label(False)
ax.set_zlabel('$\gamma$', fontsize=30, rotation = 0)
plt.show()

The for loop is not necessary, to change the size of your ticks you can use:
ax.zaxis.set_tick_params(labelsize=10)

Related

How to fix streched colorbar with Matplotlib's TwtoSlopeNorm

I have a function whose image goes from 0 to infinity, for example $f(x,y)=x^2 + y^2$. I would like to use a diverging colormap to highlight the region where the function equals 1 with a flexible colorbar. The colorbar should go from 0 to whatever vmax, white ("center") at 1, and the interval between colors should be proportional to numbers.
When plotting it with no constrains, the white region placement depends on the vmin-vmax range. I would like to have it fixed at 1, vmin cannot be less than 0. I partially solve the problem using Matplotloib's TwtoSlopeNorm setting the center to 1, whatever the vmin-vmax range is. But this causes the lower part of the colorbar to take as much space as the upper part, which is not correct. The colorbar is stretched. Trying spacing="proportional" does nothing. How can I have the colorbar use as much space for the 0-1 range as it does for the other unit intervals, while fixing the white to 1?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cbook as cbook
from matplotlib import cm
delta = 0.01
x = np.arange(0, 2.001, delta)
y = np.arange(0.0, 2.001, delta)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2
cmap = cm.seismic
fig = plt.figure(figsize=(16,5))
ax = fig.add_subplot(131)
plt.pcolormesh(Z, cmap=cmap, vmin=0, vmax=9)
plt.title('White position depends on vmin-vmax range')
plt.colorbar(extend='max')
ax = fig.add_subplot(132)
plt.pcolormesh(Z, cmap=cmap, norm=colors.TwoSlopeNorm(vmin=0, vmax=9, vcenter=1))
plt.title('White position is fixed, but colorbar is streched')
plt.colorbar(extend='max')
ax = fig.add_subplot(133)
plt.pcolormesh(Z, cmap=cmap, norm=colors.TwoSlopeNorm(vmin=0, vmax=9, vcenter=1))
plt.title('spacing="proportional" does not work')
plt.colorbar(extend='max', spacing='proportional')
plt.show()
Full answer is here
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
from matplotlib import cm
delta = 0.01
x = np.arange(0, 4.001, delta)
y = np.arange(0.0, 4.001, delta)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2
fig = plt.figure(figsize=(6,3))
ax = fig.add_subplot(121)
m1 = plt.contourf(Z, cmap=cm.seismic, levels=np.arange(0,33,1), norm=colors.TwoSlopeNorm(vmin=0, vmax=32, vcenter=1), extend='max')
plt.colorbar(m1)
ax = fig.add_subplot(122)
m1 = plt.pcolormesh(Z, cmap=cm.seismic, norm=colors.TwoSlopeNorm(vmin=0, vmax=32, vcenter=1))
cb = plt.colorbar(m1, extend='max', spacing='proportional')
cb.ax.set_yscale('linear')
plt.tight_layout()
plt.show()

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()

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:

matplotlib: apply marker only to start point or end point?

I am using matplotlib and I am struggling with style attributes.
How to add a marker only to the start point or end point of a 3D line and not on both sides?
Use the markevery parameter when plotting.
Example from the Parametric Curve example in the Gallery (version 2.2.5).
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
# Prepare arrays x, y, z
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
l = ax.plot(x, y, z, marker='o', label='parametric curve both ends', markevery=[0,-1])
l = ax.plot(x+1, y+1, z, 'r', marker='o', label='parametric curve one end', markevery=[0])
ax.legend()
plt.show()
plt.close()
I used the example from version 2.2.5 because I don't have 3.2 installed. Making a 3d axis changed in 3.something - 3.2 example link.
Axes.plot markevery parameter

How to draw a scatter map using customized colors [duplicate]

An image is worth a thousand words :
https://www.harrisgeospatial.com/docs/html/images/colorbars.png
I want to obtain the same color bar than the one on the right with matplotlib.
Default behavior use the same color for "upper"/"lower" and adjacent cell...
Thank you for your help!
Here is the code I have:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
N = 100
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
# even bounds gives a contour-like effect
bounds = np.linspace(-1, 1, 10)
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
pcm = ax.pcolormesh(X, Y, Z,
norm=norm,
cmap='RdBu_r')
fig.colorbar(pcm, ax=ax, extend='both', orientation='vertical')
In order to have the "over"/"under"-color of a colormap take the first/last color of that map but still be different from the last color inside the colormapped range you can get one more color from a colormap than you have boundaries in the BoundaryNorm and use the first and last color as the respective colors for the "over"/"under"-color.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
N = 100
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
# even bounds gives a contour-like effect
bounds = np.linspace(-1, 1, 11)
# get one more color than bounds from colormap
colors = plt.get_cmap('RdBu_r')(np.linspace(0,1,len(bounds)+1))
# create colormap without the outmost colors
cmap = mcolors.ListedColormap(colors[1:-1])
# set upper/lower color
cmap.set_over(colors[-1])
cmap.set_under(colors[0])
# create norm from bounds
norm = mcolors.BoundaryNorm(boundaries=bounds, ncolors=len(bounds)-1)
pcm = ax.pcolormesh(X, Y, Z, norm=norm, cmap=cmap)
fig.colorbar(pcm, ax=ax, extend='both', orientation='vertical')
plt.show()
As suggested in my comment you can change the color map with
pcm = ax.pcolormesh(X, Y, Z, norm=norm, cmap='rainbow_r')
That gives:
You can define your own color map as shown here: Create own colormap using matplotlib and plot color scale

Categories

Resources