Remove ticks from 3d plot - python

I made a plot, where I have two curves and some lines connecting them, then I tried to remove all ticks and labels, so that only the plane and the legend are visible but I did not manage to remove all, can someone help me?
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
fig = plt.figure()
ax = fig.gca(projection='3d')
# Plot curve and lines
x = [0,0.1,1,2,3,3.8,4,3.8,3,2,1,0.11,0]
y = [0,0.5,1,0.2,1,0.5,0,-0.5,-1,-0.7,-1,-0.5,0]
tck, u = interpolate.splprep([x, y], s=0)
unew = np.arange(0, 1.01, 0.01)
out = interpolate.splev(unew, tck)
ax.plot([x[1],x[1]+1],[y[1],y[1]],[0,4], color = 'red', label='vector e')
for (xi,yi) in zip(x[2:len(x)-1],y[2:len(y)-1]):
if (xi,yi) == (4,0):
continue
ax.plot([xi,xi+1],[yi,yi],[0,4], color = 'red')
ax.plot(out[0], out[1], zs=0, zdir='z', color = 'blue', label='curve c')
ax.plot(out[0]+1, out[1], zs=4, zdir='z', color = 'blue')
# Make legend, set axes limits and labels
ax.legend()
ax.set_xlim(-1, 6)
ax.set_ylim(-2, 2)
ax.set_zlim(0, 5)
ax.grid(False)
for line in ax.xaxis.get_ticklines():
line.set_visible(False)
for line in ax.yaxis.get_ticklines():
line.set_visible(False)
for line in ax.zaxis.get_ticklines():
line.set_visible(False)
color_tuple = (1.0, 1.0, 1.0, 0.0)
ax.w_xaxis.line.set_color(color_tuple)
ax.w_yaxis.line.set_color(color_tuple)
ax.w_zaxis.line.set_color(color_tuple)
ax.xaxis.set_ticklabels([])
ax.yaxis.set_ticklabels([])
ax.zaxis.set_ticklabels([])
plt.show()

As a minimal change to remove the ticks, you can add the ax.tick_params(color=color_tuple) before plt.show().
If you do ax.tick_params(color=color_tuple, labelcolor=color_tuple) you would no longer need the set_tick_labels([]) calls.

Related

Logarithmic Ticks on Top and Right Spine

I am trying to make a visualization with logarithmic ticks on all sides of the box.
import numpy as np
import matplotlib.pyplot as plt
x = np.logspace(2, 5, 5)
y = 0.5*x**(-1/2)
y2 = 0.01*x**(-1/2)
y3 = 0.05*x**(-1/3)
fig, ax = plt.subplots()
ax.plot(x, y, 'o-', label="One")
ax.plot(x, y2, '*-', label="Two")
ax.plot(x, y3, '--', label="Three")
ax.set(
xlabel='Input',
xlim=(1e2, 1e5),
xscale='log',
ylabel='Output',
ylim=(1e-5, 1e-1),
yscale='log',
)
ax.tick_params(top=True, right=True) # <-- This didn't work how I expected.
ax.legend(loc='lower left');
I would like the associated minor tick marks on the top and right spine.
Any advice on how to make that happen?
Use the which parameter of Axes.tick_params:
ax.tick_params(which='both', top=True, right=True)
Output:

Custom legend turn off marker facecolor

I am plotting some data where a line of best fit and the data itself need to have the same legend. The data points are plotted with hollow circles, so I wish to have a legend with a hollow circle with a line passing all the way through it. I have made this, but when I run it the legend still fills in the circle with color.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
#============================================
legend1 = mlines.Line2D([], [], color='m', markerfacecolor='none', markeredgecolor='m', markerfacecoloralt='none', marker='o',
markersize=10, label='data')
#============================================
x = np.random.randint(11, size=100)
y = np.random.randint(11, size=100)
#============================================
plt.plot(np.linspace(0, 10, 1000), np.linspace(0, 10, 1000), 'm-')
plt.scatter(x, y, s = 80, facecolors = 'none', edgecolors = 'm', marker = 'o')
plt.legend(handles = [legend1], loc = "upper left")
plt.show()
#============================================

Seaborn plot with second y axis

i wanted to know how to make a plot with two y-axis so that my plot that looks like this :
to something more like this by adding another y-axis :
i'm only using this line of code from my plot in order to get the top 10 EngineVersions from my data frame :
sns.countplot(x='EngineVersion', data=train, order=train.EngineVersion.value_counts().iloc[:10].index);
I think you are looking for something like:
import matplotlib.pyplot as plt
x = [1,2,3,4,5]
y = [1000,2000,500,8000,3000]
y1 = [1050,3000,2000,4000,6000]
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.bar(x, y)
ax2.plot(x, y1, 'o-', color="red" )
ax1.set_xlabel('X data')
ax1.set_ylabel('Counts', color='g')
ax2.set_ylabel('Detection Rates', color='b')
plt.show()
Output:
#gdubs If you want to do this with Seaborn's library, this code set up worked for me. Instead of setting the ax assignment "outside" of the plot function in matplotlib, you do it "inside" of the plot function in Seaborn, where ax is the variable that stores the plot.
import seaborn as sns # Calls in seaborn
# These lines generate the data to be plotted
x = [1,2,3,4,5]
y = [1000,2000,500,8000,3000]
y1 = [1050,3000,2000,4000,6000]
fig, ax1 = plt.subplots() # initializes figure and plots
ax2 = ax1.twinx() # applies twinx to ax2, which is the second y axis.
sns.barplot(x = x, y = y, ax = ax1, color = 'blue') # plots the first set of data, and sets it to ax1.
sns.lineplot(x = x, y = y1, marker = 'o', color = 'red', ax = ax2) # plots the second set, and sets to ax2.
# these lines add the annotations for the plot.
ax1.set_xlabel('X data')
ax1.set_ylabel('Counts', color='g')
ax2.set_ylabel('Detection Rates', color='b')
plt.show(); # shows the plot.
Output:
Seaborn output example
You could try this code to obtain a very similar image to what you originally wanted.
import seaborn as sb
from matplotlib.lines import Line2D
from matplotlib.patches import Rectangle
x = ['1.1','1.2','1.2.1','2.0','2.1(beta)']
y = [1000,2000,500,8000,3000]
y1 = [3,4,1,8,5]
g = sb.barplot(x=x, y=y, color='blue')
g2 = sb.lineplot(x=range(len(x)), y=y1, color='orange', marker='o', ax=g.axes.twinx())
g.set_xticklabels(g.get_xticklabels(), rotation=-30)
g.set_xlabel('EngineVersion')
g.set_ylabel('Counts')
g2.set_ylabel('Detections rate')
g.legend(handles=[Rectangle((0,0), 0, 0, color='blue', label='Nontouch device counts'), Line2D([], [], marker='o', color='orange', label='Detections rate for nontouch devices')], loc=(1.1,0.8))

Relocate colorbar

Is it possible to put the color diagram (which is now on the right side of the original figure) on the top of the figure?
My code:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D, get_test_data
from matplotlib import cm
import numpy as np
# set up a figure twice as wide as it is tall
fig = plt.figure(figsize=plt.figaspect(0.5))
#===============
# First subplot
#===============
# set up the axes for the first plot
ax = fig.add_subplot(1, 2, 1, projection='3d')
# plot a 3D surface like in the example mplot3d/surface3d_demo
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
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.coolwarm,
linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)
fig.colorbar(surf, shrink=0.5, aspect=10)
fig.savefig('64bit.png')
You have to add additional axes (add_axes) to put your colorbar at the desired position:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D, get_test_data
from matplotlib import cm
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
# set up a figure twice as wide as it is tall
fig = plt.figure(figsize=plt.figaspect(0.5))
#===============
# First subplot
#===============
# set up the axes for the first plot
ax = fig.add_subplot(1, 2, 1, projection='3d')
# plot a 3D surface like in the example mplot3d/surface3d_demo
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
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.coolwarm,
linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)
# position of colorbar
# where arg is [left, bottom, width, height]
cax = fig.add_axes([0.15, .87, 0.35, 0.03])
fig.colorbar(surf, orientation='horizontal', cax=cax)
plt.show()
Yes it is, there are multiple answers here in the site showing you how to move the colorbar around like this one: positioning the colorbar
In your case, you want to combine that with the orientation argument. As far as I know, there is no easy way of just placing the colorbar to the top of your figure automatically, you will have to place it manually. Here is my code that replaces your fig.colorbar(surf, shrink=0.5, aspect=10):
cbax = fig.add_axes([0.1, 0.89, 0.5, 0.05])
fig.colorbar(surf, orientation="horizontal", cax=cbax)
The numbers in the list describe some characteristics of the colorbar which are [left, bottom, width, height] as mentioned in the other answer that I have attached.
These numbers came out nicely for your plot, feel free to change them to your liking.
In order to get the colorbar on top of the plot you need to create some axes, designated to host the colorbar.
This can either be done manually by placing a new axes at some given position in figure coordinates,
cax = fig.add_axes([0.2,0.8,0.3,.05])
fig.colorbar(surf, cax=cax, orientation="horizontal")
or, by using a subplot grid (gridspec), which is shown in the following:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D
import matplotlib.gridspec as gridspec
import numpy as np
x = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(x,x)
Z = np.sin(np.sqrt(X**2 + Y**2))
gs = gridspec.GridSpec(2, 2, height_ratios=[0.05,1])
fig = plt.figure()
ax = fig.add_subplot(gs[1,0], projection='3d')
cax = fig.add_subplot(gs[0,0])
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap="coolwarm",
linewidth=0, antialiased=False, vmin=-1, vmax=1)
fig.colorbar(surf, cax=cax, orientation="horizontal", ticks=[-1,0,1])
plt.show()
For a method which avoids having to manually create new axes and instead allows us to keep the colorbar linked to an existing plot axis, we can use the location keyword (method adapted initially from here).
The location argument is meant to be used on colorbars which reference multiple axes in a list (and will throw an error if colorbar is given only one axis), but if you simply put your one axis in a list, it will allow you to use the argument. You can use the following code as an example:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
axp = ax.imshow(np.random.randint(0, 100, (100, 100)))
cb = plt.colorbar(axp,ax=[ax],location='top')
plt.show()
which yields this plot. From here, you can edit the colorbar using the typical methods (pad, shrink, etc.) to further tune the appearance of your plot.
Fair warning, I haven't seen this method used many other places and it could be less robust than going through the extra steps of creating a new axis for your colorbar.

Stacked 2D plots with interconnections in Matplotlib

I need to visualize some complex multivariate datasets and the preferrable choice is to use a modification of parallel axis visualization, using stacked 2D plots, where each plot maps a degree of freedom/model parameter and data points belonging to the same data sets should be interconnected across different plots. I am attaching a conceptual sketch. How could I implement it in matplotlib?
To have a rough idea, this could be a possible solution in matplotlib using Axes3D
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, PathPatch
import mpl_toolkits.mplot3d.art3d as art3d
x = np.array([1,2,3])
y = np.array([2,3,1])
z = np.array([1,1,1])
fig = plt.figure(figsize=(6,6))
ax = fig.add_axes([0,0,1,1], projection='3d')
#plot the points
ax.scatter(x,y,z*0.4, c="r", facecolor="r", s=60)
ax.scatter(y,x,z*0.9, c="b", facecolor="b", s=60)
ax.scatter(x,y,z*1.6, c="g", facecolor="g", s=60)
#plot connection lines
ax.plot([x[0],y[0],x[0]],[y[0],x[0],y[0]],[0.4,0.9,1.6], color="k")
ax.plot([x[2],y[2],x[2]],[y[2],x[2],y[2]],[0.4,0.9,1.6], color="k")
#plot planes
p = Rectangle((0,0), 4,4, color="r", alpha=0.2)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0.4, zdir="z")
p = Rectangle((0,0), 4,4, color="b", alpha=0.2)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0.9, zdir="z")
p = Rectangle((0,0), 4,4, color="g", alpha=0.2)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=1.6, zdir="z")
ax.set_aspect('equal')
ax.view_init(13,-63)
ax.set_xlim3d([0,4])
ax.set_ylim3d([0,4])
ax.set_zlim3d([0,2])
plt.savefig(__file__+".png")
plt.show()
Update
Creating three different axes is possible. One has to add the axes and make the upper ones transparent (ax2.patch.set_alpha(0.)). Then the grid has to be turned off (ax.grid(False)) and the panes and lines that we don't need set invisible.
However, I have no clue how to draw a connection with between the axes. The 2D approach of matplotlib.patches.ConnectionPatch does not work for 3D axes.
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import mpl_toolkits.mplot3d.art3d as art3d
x = np.array([1,2,3])
y = np.array([2,3,1])
z = np.array([0,0,0])
fig = plt.figure(figsize=(6,6))
ax = fig.add_axes([0,0,1,1], projection='3d')
ax2 = fig.add_axes([0.0,0.24,1,1], projection='3d')
ax2.patch.set_alpha(0.)
ax3 = fig.add_axes([0.0,0.48,1,1], projection='3d')
ax3.patch.set_alpha(0.)
#plot the points
ax.scatter(x,y,z, c="r", facecolor="r", s=60)
ax2.scatter(y*4,x*4,z, c="b", facecolor="b", s=60)
ax3.scatter(x*100,y*100,z, c="g", facecolor="g", s=60)
#plot connection lines
#ax.plot([x[0],y[0],x[0]],[y[0],x[0],y[0]],[0.4,0.9,1.6], color="k")
#ax.plot([x[2],y[2],x[2]],[y[2],x[2],y[2]],[0.4,0.9,1.6], color="k")
#plot planes
p = Rectangle((0,0), 4,4, color="r", alpha=0.2)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
p = Rectangle((0,0), 16,16, color="b", alpha=0.2)
ax2.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
p = Rectangle((0,0), 400,400, color="g", alpha=0.2)
ax3.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
ax.set_aspect('equal')
ax2.set_aspect('equal')
ax3.set_aspect('equal')
ax.view_init(13,-63)
ax2.view_init(10,-63)
ax3.view_init(8,-63)
ax.set_xlim3d([0,4])
ax.set_ylim3d([0,4])
ax.set_zlim3d([0,2])
ax2.set_xlim3d([0,16])
ax2.set_ylim3d([0,16])
ax2.set_zlim3d([0,2])
ax3.set_xlim3d([0,400])
ax3.set_ylim3d([0,400])
ax3.set_zlim3d([0,2])
ax.grid(False)
ax2.grid(False)
ax3.grid(False)
def axinvisible(ax):
for zax in (ax.w_zaxis, ax.w_xaxis, ax.w_yaxis):
zax.pane.set_visible(False)
if zax == ax.w_zaxis:
zax.line.set_visible(False)
for ll in zax.get_ticklines()+zax.get_ticklabels():
ll.set_visible(False)
axinvisible(ax)
axinvisible(ax2)
axinvisible(ax3)
# setting a ConnectionPatch does NOT work
from matplotlib.patches import ConnectionPatch
con = ConnectionPatch(xyA=(2,2), xyB=(2,2),
coordsA='data', coordsB='data',
axesA=ax, axesB=ax2,
arrowstyle='->', clip_on=True)
ax2.add_artist(con) # artist is not shown :-(
plt.show()
A solution could be based on matplotlib's 3D capabilities. You can use Axes3D.plot_surface to plot the axes, and user scatter and line plots for the rest.

Categories

Resources