Te doy la bienvenida a proyecto online, en este sitio hallarás la solucíon a lo que buscabas.
Solución:
Gran pregunta Tengis, a toda la gente de matemáticas le encanta mostrar los gráficos de superficie llamativos con funciones dadas, sin tener que lidiar con datos del mundo real. El código de muestra que proporcionó utiliza gradientes, ya que las relaciones de una variable se modelan mediante funciones. Para este ejemplo, generaré datos aleatorios usando una distribución normal estándar.
De todos modos, aquí es cómo puede trazar rápidamente datos aleatorios (arbitrarios) 4D con las primeras tres variables en el eje y la cuarta en color:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.random.standard_normal(100)
y = np.random.standard_normal(100)
z = np.random.standard_normal(100)
c = np.random.standard_normal(100)
img = ax.scatter(x, y, z, c=c, cmap=plt.hot())
fig.colorbar(img)
plt.show()
Nota: Se utilizó un mapa de calor con el esquema de colores calientes (amarillo a rojo) para la cuarta dimensión.
Resultado:
Sé que la pregunta es muy antigua, pero me gustaría presentar esta alternativa donde, en lugar de usar el “diagrama de dispersión”, tenemos un diagrama de superficie 3D donde los colores se basan en la 4ª dimensión. Personalmente, no veo realmente la relación espacial en el caso del “diagrama de dispersión”, por lo que el uso de la superficie 3D me ayuda a comprender más fácilmente el gráfico.
La idea principal es la misma que la respuesta aceptada, pero tenemos un gráfico 3D de la superficie que permite ver mejor visualmente la distancia entre los puntos. El siguiente código aquí se basa principalmente en la respuesta dada a esta pregunta.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
# The values related to each point. This can be a "Dataframe pandas"
# for example where each column is linked to a variable <-> 1 dimension.
# The idea is that each line = 1 pt in 4D.
do_random_pt_example = True;
index_x = 0; index_y = 1; index_z = 2; index_c = 3;
list_name_variables = ['x', 'y', 'z', 'c'];
name_color_map = 'seismic';
if do_random_pt_example:
number_of_points = 200;
x = np.random.rand(number_of_points);
y = np.random.rand(number_of_points);
z = np.random.rand(number_of_points);
c = np.random.rand(number_of_points);
else:
# Example where we have a "Pandas Dataframe" where each line = 1 pt in 4D.
# We assume here that the "data frame" "df" has already been loaded before.
x = df[list_name_variables[index_x]];
y = df[list_name_variables[index_y]];
z = df[list_name_variables[index_z]];
c = df[list_name_variables[index_c]];
#end
#-----
# We create triangles that join 3 pt at a time and where their colors will be
# determined by the values of their 4th dimension. Each triangle contains 3
# indexes corresponding to the line number of the points to be grouped.
# Therefore, different methods can be used to define the value that
# will represent the 3 grouped points and I put some examples.
triangles = mtri.Triangulation(x, y).triangles;
choice_calcuation_colors = 1;
if choice_calcuation_colors == 1: # Mean of the "c" values of the 3 pt of the triangle
colors = np.mean( [c[triangles[:,0]], c[triangles[:,1]], c[triangles[:,2]]], axis = 0);
elif choice_calcuation_colors == 2: # Mediane of the "c" values of the 3 pt of the triangle
colors = np.median( [c[triangles[:,0]], c[triangles[:,1]], c[triangles[:,2]]], axis = 0);
elif choice_calcuation_colors == 3: # Max of the "c" values of the 3 pt of the triangle
colors = np.max( [c[triangles[:,0]], c[triangles[:,1]], c[triangles[:,2]]], axis = 0);
#end
#----------
# Displays the 4D graphic.
fig = plt.figure();
ax = fig.gca(projection='3d');
triang = mtri.Triangulation(x, y, triangles);
surf = ax.plot_trisurf(triang, z, cmap = name_color_map, shade=False, linewidth=0.2);
surf.set_array(colors); surf.autoscale();
#Add a color bar with a title to explain which variable is represented by the color.
cbar = fig.colorbar(surf, shrink=0.5, aspect=5);
cbar.ax.get_yaxis().labelpad = 15; cbar.ax.set_ylabel(list_name_variables[index_c], rotation = 270);
# Add titles to the axes and a title in the figure.
ax.set_xlabel(list_name_variables[index_x]); ax.set_ylabel(list_name_variables[index_y]);
ax.set_zlabel(list_name_variables[index_z]);
plt.title('%s in function of %s, %s and %s' % (list_name_variables[index_c], list_name_variables[index_x], list_name_variables[index_y], list_name_variables[index_z]) );
plt.show();
Otra solución para el caso en el que queremos absolutamente tener los valores originales de la cuarta dimensión para cada punto es simplemente usar el “diagrama de dispersión” combinado con un diagrama de superficie 3D que simplemente los vinculará para ayudarlo a ver las distancias entre ellos.
name_color_map_surface = 'Greens'; # Colormap for the 3D surface only.
fig = plt.figure();
ax = fig.add_subplot(111, projection='3d');
ax.set_xlabel(list_name_variables[index_x]); ax.set_ylabel(list_name_variables[index_y]);
ax.set_zlabel(list_name_variables[index_z]);
plt.title('%s in fcn of %s, %s and %s' % (list_name_variables[index_c], list_name_variables[index_x], list_name_variables[index_y], list_name_variables[index_z]) );
# In this case, we will have 2 color bars: one for the surface and another for
# the "scatter plot".
# For example, we can place the second color bar under or to the left of the figure.
choice_pos_colorbar = 2;
#The scatter plot.
img = ax.scatter(x, y, z, c = c, cmap = name_color_map);
cbar = fig.colorbar(img, shrink=0.5, aspect=5); # Default location is at the 'right' of the figure.
cbar.ax.get_yaxis().labelpad = 15; cbar.ax.set_ylabel(list_name_variables[index_c], rotation = 270);
# The 3D surface that serves only to connect the points to help visualize
# the distances that separates them.
# The "alpha" is used to have some transparency in the surface.
surf = ax.plot_trisurf(x, y, z, cmap = name_color_map_surface, linewidth = 0.2, alpha = 0.25);
# The second color bar will be placed at the left of the figure.
if choice_pos_colorbar == 1:
#I am trying here to have the two color bars with the same size even if it
#is currently set manually.
cbaxes = fig.add_axes([1-0.78375-0.1, 0.3025, 0.0393823, 0.385]); # Case without tigh layout.
#cbaxes = fig.add_axes([1-0.844805-0.1, 0.25942, 0.0492187, 0.481161]); # Case with tigh layout.
cbar = plt.colorbar(surf, cax = cbaxes, shrink=0.5, aspect=5);
cbar.ax.get_yaxis().labelpad = 15; cbar.ax.set_ylabel(list_name_variables[index_z], rotation = 90);
# The second color bar will be placed under the figure.
elif choice_pos_colorbar == 2:
cbar = fig.colorbar(surf, shrink=0.75, aspect=20,pad = 0.05, orientation = 'horizontal');
cbar.ax.get_yaxis().labelpad = 15; cbar.ax.set_xlabel(list_name_variables[index_z], rotation = 0);
#end
plt.show();
Por último, también es posible utilizar “plot_surface” donde definimos el color que se utilizará para cada cara. En un caso como este, donde tenemos 1 vector de valores por dimensión, el problema es que tenemos que interpolar los valores para obtener cuadrículas 2D. En el caso de interpolación de la 4ª dimensión, se definirá únicamente según XY y no se tendrá en cuenta Z. Como resultado, los colores representan C (x, y) en lugar de C (x, y, z). El siguiente código se basa principalmente en las siguientes respuestas: plot_surface con un vector 1D para cada dimensión; plot_surface con un color seleccionado para cada superficie. Tenga en cuenta que el cálculo es bastante pesado en comparación con las soluciones anteriores y la visualización puede llevar un poco de tiempo.
import matplotlib
from scipy.interpolate import griddata
# X-Y are transformed into 2D grids. It's like a form of interpolation
x1 = np.linspace(x.min(), x.max(), len(np.unique(x)));
y1 = np.linspace(y.min(), y.max(), len(np.unique(y)));
x2, y2 = np.meshgrid(x1, y1);
# Interpolation of Z: old X-Y to the new X-Y grid.
# Note: Sometimes values can be < z.min and so it may be better to set
# the values too low to the true minimum value.
z2 = griddata( (x, y), z, (x2, y2), method='cubic', fill_value = 0);
z2[z2 < z.min()] = z.min();
# Interpolation of C: old X-Y on the new X-Y grid (as we did for Z)
# The only problem is the fact that the interpolation of C does not take
# into account Z and that, consequently, the representation is less
# valid compared to the previous solutions.
c2 = griddata( (x, y), c, (x2, y2), method='cubic', fill_value = 0);
c2[c2 < c.min()] = c.min();
#--------
color_dimension = c2; # It must be in 2D - as for "X, Y, Z".
minn, maxx = color_dimension.min(), color_dimension.max();
norm = matplotlib.colors.Normalize(minn, maxx);
m = plt.cm.ScalarMappable(norm=norm, cmap = name_color_map);
m.set_array([]);
fcolors = m.to_rgba(color_dimension);
# At this time, X-Y-Z-C are all 2D and we can use "plot_surface".
fig = plt.figure(); ax = fig.gca(projection='3d');
surf = ax.plot_surface(x2, y2, z2, facecolors = fcolors, linewidth=0, rstride=1, cstride=1,
antialiased=False);
cbar = fig.colorbar(m, shrink=0.5, aspect=5);
cbar.ax.get_yaxis().labelpad = 15; cbar.ax.set_ylabel(list_name_variables[index_c], rotation = 270);
ax.set_xlabel(list_name_variables[index_x]); ax.set_ylabel(list_name_variables[index_y]);
ax.set_zlabel(list_name_variables[index_z]);
plt.title('%s in fcn of %s, %s and %s' % (list_name_variables[index_c], list_name_variables[index_x], list_name_variables[index_y], list_name_variables[index_z]) );
plt.show();
Te mostramos comentarios y calificaciones
Tienes la opción de añadir valor a nuestro contenido informacional añadiendo tu experiencia en las ilustraciones.