I've been searching high and low for a python script to select the highest or lowest vertex or vertices on the z axis in an object. I want to add these to a vertex group so I can use them in my code. Any help is appreciated.. thanks. enter image description here

import bpy

# get the object and its vertices
obj = bpy.context.object # edit: now gets the currently active object 

# edit: to select vertices we have to be in OBJ mode first:

verts = obj.data.vertices
# get the z-coordinates from each vertex and the maximum
z_coords = [v.co[2] for v in verts]
max_z_coord = max(z_coords)

# get list of all vertices that have the max. z-coordinate
max_verts = [vertex for vertex in obj.data.vertices if vertex.co[2] == max_z_coord]


To select vertices, one way is to change to OBJECT mode, select the vertices, and change back to EDIT mode. (Another one would be to use bmesh.)

Notice that I've also changed two lines in the original answer above: We have to work on the active object (obj = bpy.context.object) and we have to be in OBJECT mode (bpy.ops.object.mode_set(mode="OBJECT")).

The selection and switching to EDIT mode is done by appending these lines to the script:

# select the vertices: 
for v in verts: v.select = False
for v in max_verts: v.select = True
# set EDIT mode's select mode to "vertex select" 
bpy.context.tool_settings.mesh_select_mode = (True , False , False)
# change to EDIT mode
| improve this answer | |
  • 1
    $\begingroup$ I've tried, but nothing seems to happen. The cone, when I enter edit mode, does not select the top vertex. I'm using 2.8 $\endgroup$ – Michael Teiniker Apr 27 '19 at 21:53
  • $\begingroup$ I've edited my answer to select the vertices in edit mode as well. Let me know if it still doesn't work or if you don't understand something. $\endgroup$ – Benedikt Apr 28 '19 at 12:23

Edit BMesh version

An edit mode script to select the maximum z value vertices.

Uses local space, edit to space = 'GLOBAL' for global space.

Uses a tolerance of TOL = 0.0000001 to check between values. Edit to suit. Set to zero for no tolerance

Sorted the vertices in z order. This is less efficient than finding the max. If though you also want the min the median, the top 10 etc, will come down to simple list slicing.

import bpy
import bmesh
from mathutils import Matrix

space = 'LOCAL'  # or 'GLOBAL'
find = 'MAX' # or 'MIN'
TOL = 1e-7
ob = bpy.context.object
M = ob.matrix_world if space == 'GLOBAL' else Matrix()
me = ob.data

bm = bmesh.from_edit_mesh(me)
verts = sorted(bm.verts, key=lambda v: (M @ v.co).z)

z = (M @ verts[-1 if find == 'MAX' else 0].co).z
for v in verts:
    v.select = abs((M @ v.co).z - z) < TOL


For example to add the top 3 verts to a vertex group vg named "Group" Would need to do this in object mode

bm = bmesh.new()
verts = sorted(bm.verts, key=lambda v: (M @ v.co).z)
vg = ob.vertex_groups.new(name="Top 3")
vg.add([v.index for v in verts[:3], 1.0, 'REPLACE')
vg = ob.vertex_groups.new(name="Lowest 3")
vg.add([v.index for v in verts[-3:], 1.0, 'REPLACE')
| improve this answer | |
  • $\begingroup$ Would this work for 2.79 as well? $\endgroup$ – Michael Teiniker May 2 '19 at 8:04
  • $\begingroup$ Yes. Need to replace @ (at) with * (asterisk) Assumed 2.8 $\endgroup$ – batFINGER May 2 '19 at 10:35
  • $\begingroup$ In order to get the Y vertices, would you replace the "z" with "y"? $\endgroup$ – Michael Teiniker Jan 9 at 9:14
  • $\begingroup$ Yes that would work. $\endgroup$ – batFINGER Jan 9 at 9:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.