How do I initiate a render from Python but still show progress bar and UI updates?
You can do this by passing the 'execution context'. By default the execute() function is run when calling an operator from a script. If you press the render button from within the UI the invoke() function is run. To do the same from a script you would pass 'INVOKE_DEFAULT' as execution context. So for example bpy.ops.render.render('INVOKE_DEFAULT', animation=False, write_still=True).

See also the Python API docs: https://docs.blender.org/api/blender_python_api_current/bpy.ops.html#execution-context

Or for 2.80 (which is basically the same at the time of writing): https://docs.blender.org/api/blender2.8/bpy.ops.html#execution-context