I wish to export NDVI layer as image to my Google Drive. I can run the code seamlessly but nothing is exported into my drive after the code is executed.
Here is my code:
import ee
import ee.mapclient
import datetime
import ee.batch as batch
ee.Initialize()
roi_lat = 14.82762
roi_lon = 101.079659
ullat = roi_lat + 0.01
ullon = roi_lon - 0.01
lrlat = roi_lat - 0.01
lrlon = roi_lon + 0.01
geometry = ([ullon,ullat], [lrlon, ullat],[lrlon, lrlat],[ullon, lrlat])
l8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
image = ee.Image(
(l8.filterBounds(point)
.filterDate(datetime.datetime(2018, 1, 1), datetime.datetime(2018, 12, 31))
.sort('CLOUD_COVER')
.first()
)
)
def NDVI(image):
return image.expression('float(b("B5") - b("B4")) / (b("B5") + b("B4"))')
ndvi = l8.map(NDVI).mean()
visualization = ndvi.visualize({
'min': 0,
'max': 1,
'palette': ['FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163',
'99B718', '74A901', '66A000', '529400', '3E8601',
'207401', '056201', '004C00', '023B01', '012E01',
'011D01', '011301']
})
task_config = {
'description': 'NDVI',
'scale': 30,
'region':geometry
}
print("Starting to create a image")
out = ee.batch.Export.image(visualization,'l8_ndvi', task_config)
process = batch.Task.start(out)
print("Process sent to cloud")
If anyone has any knowledge. Please enlighten me where did I go wrong?
Thanks.
What you want is out = ee.batch.Export.image.toDrive(...). You can start that with out.start(). You can monitor tasks with ee.batch.Task.list() or use the Tasks tab of the Code Editor.
Related
I want to create a graphical terminal like a tradingview. For this, I use plotly dash to make the display as comfortable as possible. But a situation arose that I have been unable to resolve for several days now.
Now my code looks like this:
import asyncio import datetime as DT from threading import Thread
import dash import numpy as np import plotly.graph_objs as go from dash import dcc, html from dash.dependencies import Input, Output
# ======================================================================================================================
# === Create DATA ======================================================================================================
# ======================================================================================================================
Start_Time = DT.datetime.timestamp(DT.datetime.now().replace(second=0, microsecond=0)) * 1000 X_time = np.array([]) Y_one = np.array([]) Y_two = np.array([]) Y_three = np.array([])
async def create_connection():
from random import randrange
import time
count = 0
global X_time
global Y_one
global Y_two
global Y_three
while count < 1000000:
X_time = np.append(X_time, count)
Y_one = np.append(Y_one, randrange(10000))
Y_two = np.append(Y_two, randrange(10000))
Y_three = np.append(Y_three, randrange(10000))
count += 1
time.sleep(1)
def async_main_wrapper():
"""Not async Wrapper around async_main to run it as target function of Thread"""
asyncio.run(create_connection())
# ======================================================================================================================
# === Create DASH ======================================================================================================
# ======================================================================================================================
X = np.array([0]) Y = np.array([0])
external_stylesheets = ['https://fonts.googleapis.com/css2?family=Montserrat+Alternates:wght#400;600&display=swap'] app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
colors = {
'background': '#FDFEFE',
'text': '#424242' }
app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[
html.H1(
children='Main graph',
style={
'textAlign': 'left',
"fontFamily": "Montserrat Alternates",
"fontWeight": "600",
'color': colors['text']
}),
dcc.Graph(id='live_graph', style={'height': '700px', 'width': '100%'}, animate=True, config={'scrollZoom':True}),
dcc.Interval(
id='graph_update',
interval=1000 * 1
), ] )
def create_area(line_Y_one, line_Y_two, line_Y_three, X_time):
fig = {'data': [line_Y_one, line_Y_two, line_Y_three],
'layout': go.Layout(xaxis=dict(range=[min(X_time), max(X_time)], rangeslider=dict(visible=True)),
yaxis=dict(tickfont=dict(color='rgba(0, 188, 212, 0.0)')),
yaxis2=dict(overlaying="y", tickfont=dict(color='rgba(0, 188, 212, 0.0)')),
yaxis3=dict(overlaying="y"),
)}
return fig
#app.callback(Output('live_graph', 'figure'),
Input('graph_update', 'n_intervals')) def update_graph_scatter(graph_update):
global X_time
global Y_one
global Y_two
global Y_three
clr_green = 'rgba(139, 195, 74, '
clr_red = 'rgba(220, 20, 60, '
clr_brown = 'rgba(93, 64, 55, 1.0)'
line_Y_one = go.Scatter(
x=X_time,
y=Y_one,
name='Y_one',
line=dict(color=clr_green + '0.0)'),
fillcolor=clr_green + '0.3)',
fill='tozeroy',
yaxis='y1'
)
line_Y_two = go.Scatter(
x=X_time,
y=Y_two,
name='Y_two',
line=dict(color=clr_red + '0.0)'),
fillcolor=clr_red + '0.3)',
fill='tozeroy',
yaxis='y1'
)
line_Y_three = go.Scatter(
name='Y_three',
x=X_time,
y=Y_three,
line=dict(color=clr_brown),
yaxis='y3'
)
return create_area(line_Y_one, line_Y_two, line_Y_three, X_time)
# ======================================================================================================================
# === Start ===========================================================================================================
# ======================================================================================================================
if __name__ == '__main__':
th = Thread(target=async_main_wrapper)
th.start()
app.run_server(host='localhost', port=8080, debug=True, use_reloader=False)
th.join()
When starting the graph, everything goes well, it is updated once a second, as specified in the settings:
https://i.postimg.cc/L8yCj6Dw/normal.gif
But if I switch to another tab or window (i.e. I don't look at the chart), then when I return, the chart starts to update quickly, compressing and decompressing like a spring:
https://i.postimg.cc/BvXhp9w6/glitch.gif
How can I solve this situation?
And as an addition: could you recommend a good raftly dash guide that
will show solutions to similar problems?
so I am working with relatively large arrays (size (13, 8192)) to plot some Figures on a website. It has already been implemented like this, so changes are difficult to make.
As I am running out of memory using the local storage of the browser, I have to use directly a given complex NumPy array and then split it into the real and imaginary parts in another Callback. The problem is that I can't JSON serialize complex-like arrays. Does someone know what can I do to "save" this sort of array using the dcc.Store component of Dash? Thanks in advance.
Here is an example of the code (it is a really short version of it).
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
import numpy as np
app = dash.Dash(__name__)
T0 = 1E-12 # duration of input
N = 8192 # number of points
dt = 750*T0/N
T = np.arange(-N/2, N/2)*dt
m = 1
C = 0
def envelopef(T,T0,C,m):
U = (np.exp(-((1+1j*C)/2)*((T/T0)**(2*m)))).astype(complex)
UI = np.absolute(U)**2
return U, UI
z = np.arange(-10,10)
U, UI = envelopef(T,T0,C,m)
scatter1 = go.Scatter(x=T/T0,y=UI)
figure1 = go.Figure(data=[scatter1]).update_layout( )
env_graph = dcc.Graph(id='envelopesss',
animate=True,
figure=figure1.update_layout(width=600, height=600,
xaxis = dict(range = [-8, 8])))
M_slider = dcc.Slider(
id='m_slider',
min=1,
max=10,
step=1,
value=m,
marks={
1: {'label': '1'},
10: {'label': '10'}},
)
app.layout = html.Div([
M_slider,
dcc.Store(id='session', storage_type='local'),
dcc.Loading(id="loading1",children=[html.Div([env_graph]) ],type="circle",),
])
#app.callback(
Output("loading1", "children"),
Output("session", "data"),
[Input("m_slider", "value")])
def update_bar_chart(mn):
U, UI = envelopef(T,T0,C,mn)
phase = np.angle(U)
scatter1 = go.Scatter(x=T/T0,y=UI)
figure1 = go.Figure(data=[scatter1]).update_layout(width=600, height=600,
xaxis = dict(range = [-8, 8]))
data = {'u': U , 'ui':UI, 'up': phase}
env_graph = dcc.Graph(figure=figure1)
return env_graph, data
app.run_server(debug=True)
You might want to take a look at the ServersideOutput component from dash-extensions. It keeps the data server side (which should improve the performance of your app), and since the default serializer is pickle, complex-valued arrays work out of the box. You can install it via pip,
pip install dash-extensions==0.0.66
To enable use of serverside outputs, replace the app initialization code by
from dash_extensions.enrich import DashProxy, html, dcc, Input, Output, ServersideOutput, ServersideOutputTransform
app = DashProxy(__name__, transforms=[ServersideOutputTransform()])
Next, replace the Output by a ServersideOutput,
#app.callback(
Output("loading1", "children"),
ServersideOutput("session", "data"),
[Input("m_slider", "value")])
That's it. Your app should now work. For completeness, here is the full app code,
import plotly.graph_objects as go
import numpy as np
from dash_extensions.enrich import DashProxy, html, dcc, Input, Output, ServersideOutput, ServersideOutputTransform
app = DashProxy(__name__, transforms=[ServersideOutputTransform()])
T0 = 1E-12 # duration of input
N = 8192 # number of points
dt = 750 * T0 / N
T = np.arange(-N / 2, N / 2) * dt
m = 1
C = 0
def envelopef(T, T0, C, m):
U = (np.exp(-((1 + 1j * C) / 2) * ((T / T0) ** (2 * m)))).astype(complex)
UI = np.absolute(U) ** 2
return U, UI
z = np.arange(-10, 10)
U, UI = envelopef(T, T0, C, m)
scatter1 = go.Scatter(x=T / T0, y=UI)
figure1 = go.Figure(data=[scatter1]).update_layout()
env_graph = dcc.Graph(id='envelopesss',
animate=True,
figure=figure1.update_layout(width=600, height=600,
xaxis=dict(range=[-8, 8])))
M_slider = dcc.Slider(
id='m_slider',
min=1,
max=10,
step=1,
value=m,
marks={
1: {'label': '1'},
10: {'label': '10'}},
)
app.layout = html.Div([
M_slider,
dcc.Store(id='session', storage_type='local'),
dcc.Loading(id="loading1", children=[html.Div([env_graph])], type="circle", ),
])
#app.callback(
Output("loading1", "children"),
ServersideOutput("session", "data"),
[Input("m_slider", "value")])
def update_bar_chart(mn):
U, UI = envelopef(T, T0, C, mn)
phase = np.angle(U)
scatter1 = go.Scatter(x=T / T0, y=UI)
figure1 = go.Figure(data=[scatter1]).update_layout(width=600, height=600,
xaxis=dict(range=[-8, 8]))
data = {'u': U, 'ui': UI, 'up': phase}
env_graph = dcc.Graph(figure=figure1)
return env_graph, data
app.run_server(port=7777)
To explain my problem, I'm a beginner in Python and I've got to do a loop in Python to make an automatic map production in Qgis.
There are 2 facts. The first is that I'm using the French Government's API called "Addresses" that return addresses (and many data linked to this address) from geographic coordinates. When I run my code in the Qgis python console, the response is 200 but I don't see anything appearing. This is a real problem for me because I want to import those pieces of information into my Layout and I don't know how to do this too (this is the second fact).
Here I show you the code I have with the API :
for feat in mylayer.getFeatures():
Shops_name = feat['nom_sho']
x = feat['x'] #x and Y stands for longitude and latitude
y = feat['y']
x = str(x)
y = str(y)
date = datetime.date.today()
today = str(date)
expr = u"nom_sho = '{}'".format(Shops_name)
myselect = mylayer.getFeatures( QgsFeatureRequest().setFilterExpression ( expr ))
iface.mapCanvas().zoomToSelected(mylayer)
iface.mapCanvas().zoomScale(1625)
print(f"Voici {Shops_name}" )
mylayer.selectByIds( [ f.id() for f in myselect ] )
project = QgsProject.instance()
manager = project.layoutManager()
layoutName = str(Shops_name)
#layout
layouts_list = manager.printLayouts()
for layout in layouts_list:
if layout.name() == layoutName:
manager.removeLayout(layout)
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName(layoutName)
manager.addLayout(layout)
#symbology
symbol_shop = QgsMarkerSymbol.createSimple({'name': 'Triangle', 'color': '#0088CC', 'outline_color': 'black', 'size': '4'})
symbol_shop_selected = QgsMarkerSymbol.createSimple({'name': 'Triangle', 'color': 'blue', 'outline_color': 'black', 'size': '7'})
color_shop = QgsRendererCategory(None,symbol_shop,"Other shops",True)
color_shop_selected = QgsRendererCategory(layoutName,symbol_shop_selected,layoutName,True)
renderer = QgsCategorizedSymbolRenderer("nom_sho", [color_shop,color_shop_selected])
mylayer.setRenderer(renderer)
mylayer.triggerRepaint()
# empty map
map = QgsLayoutItemMap(layout)
map.setRect(20, 20, 20, 20)
# layout2
rectangle = QgsRectangle(1355502, -46398, 1734534, 137094)
map.setExtent(rectangle)
layout.addLayoutItem(map)
# Canva update
canvas = iface.mapCanvas()
map.setExtent(canvas.extent())
layout.addLayoutItem(map)
# Resize map
map.attemptMove(QgsLayoutPoint(5, 27, QgsUnitTypes.LayoutMillimeters))
map.attemptResize(QgsLayoutSize(220, 178, QgsUnitTypes.LayoutMillimeters))
# Legende
tree_layers = project.layerTreeRoot().children()
checked_layers = [layer.name() for layer in tree_layers if layer.isVisible()]
layers_to_remove = [layer for layer in project.mapLayers().values() if layer.name() not in checked_layers]
legend = QgsLayoutItemLegend(layout)
legend.setTitle(html.unescape("Légende"))
legend.setStyleFont(QgsLegendStyle.Title, myBoldFont)
layout.addLayoutItem(legend)
legend.attemptMove(QgsLayoutPoint(230, 24, QgsUnitTypes.LayoutMillimeters))
legend.setAutoUpdateModel(False)
m = legend.model()
g = m.rootGroup()
for l in layers_to_remove:
g.removeLayer(l)
g.removeLayer(osm)
legend.adjustBoxSize()
#api
r = requests.get("https://api-adresse.data.gouv.fr/reverse/?lon="+x+"&lat="+y+"")
r.json()
print(r)
# Title
title = QgsLayoutItemLabel(layout)
title.setText(layoutName)
title.setFont(myTitleBoldFont)
title.adjustSizeToText()
layout.addLayoutItem(title)
title.attemptMove(QgsLayoutPoint(5, 4, QgsUnitTypes.LayoutMillimeters))
# Subtitle
subtitle = QgsLayoutItemLabel(layout)
subtitle.setFont(QFont("Verdana", 18))
subtitle.adjustSizeToText()
layout.addLayoutItem(subtitle)
subtitle.attemptMove(QgsLayoutPoint(5, 18, QgsUnitTypes.LayoutMillimeters))
# Scale
scalebar = QgsLayoutItemScaleBar(layout)
scalebar.setStyle('Single Box')
scalebar.setUnits(QgsUnitTypes.DistanceMeters)
scalebar.setNumberOfSegments(2)
scalebar.setNumberOfSegmentsLeft(0)
scalebar.setUnitsPerSegment(25)
scalebar.setLinkedMap(map)
scalebar.setUnitLabel('km')
scalebar.setFont(QFont('Verdana', 20))
scalebar.update()
layout.addLayoutItem(scalebar)
scalebar.attemptMove(QgsLayoutPoint(10, 185, QgsUnitTypes.LayoutMillimeters))
Thank you for your help.
Use r.json() to print in json format.
can use r.text r.content as well
Here is a good source of information about the get request response.
https://www.w3schools.com/python/ref_requests_response.asp
What you want to do is get the body of the response. You will probably want to use r.json().
I have a google earth engine javascript code to detect water pixel in the closest date SAR imagery. Link of the code: https://code.earthengine.google.com/0a35eea49123a5390b822bac7afc1b0c. I can run the code in GEE and returning exactly what I required (1 if the location is above water and 0 when it above land).
I have tried to develop the following code which is returning the dictionary, not the single expected output.
import ee, datetime
ee.Initialize()
waterThresh = -16;
angle_threshold_1 = ee.Number(45.4);
angle_threshold_2 = ee.Number(31.66);
class AltimeterExtraction(object):
def __init__(self, locationfile = './Bin/Location_Data.txt'):
filecontent = open(locationfile, 'r')
content = csv.DictReader(filecontent, delimiter='\t')
def watertestpoint(self, lat=10.55587,lon=89.89789, date1='2019-04-05'):
lat = ee.Number(lat)
lon = ee.Number(lon)
datep = datetime.datetime.strptime(date1, "%Y-%m-%d")
date2 = datep + datetime.timedelta(days = -10)
point = ee.Geometry.Point([lon,lat])
S1 = ee.ImageCollection('COPERNICUS/S1_GRD').filterBounds(point).filterDate(date2, date1)
S1 = S1.map(self.maskByAngle)
S1 = S1.select('VV').median().rename('VV')
S1 = S1.focal_median(50,'circle','meters').rename('VV')
WaterMask = S1.lt(waterThresh)
flag = WaterMask.reduceRegion(**{
'reducer': ee.Reducer.mean(),
'geometry': point,
'scale': 10
});
return flag.get('VV')
def maskByAngle(self, img):
I = ee.Image(img)
angle = I.select('angle')
mask1 = angle.lt(angle_threshold_1)
mask2 = angle.gt(angle_threshold_2)
I = I.updateMask(mask1)
return I.updateMask(mask2)
P = AltimeterExtraction()
x= P.watertestpoint()
print x
Are there any ways to get the single value instead of the dictionary from python? I need the binary output (0 or 1) from the function.
You should add .getInfo() while printing to get the actual value from that point. Earth Engine process all of the data on the server side so you have to explicitly call .getInfo() to return the information.
Here is an example I used:
P = AltimeterExtraction()
x= P.watertestpoint(lat=20.5564,lon=94.818,date1='2019-03-30')
print(x.getInfo())
I'm trying to display further images (ct-scan) using numpy/vtk as describe in this sample code (http://www.vtk.org/Wiki/VTK/Examples/Python/vtkWithNumpy) but I don't get it and don't know why.
If someone could help me it would be kind.
Here's my code :
import vtk
import numpy as np
import os
import cv, cv2
import matplotlib.pyplot as plt
import PIL
import Image
DEBUG =True
directory="splitted_mri/"
w = 226
h = 186
d = 27
stack = np.zeros((w,d,h))
k=-1 #add the next picture in a differente level of depth/z-positions
for file in os.listdir(directory):
k+=1
img = directory + file
im = Image.open(img)
temp = np.asarray(im, dtype=int)
stack[:,k,:]= temp
print stack.shape
#~ plt.imshow(test)
#~ plt.show()
print type(stack[10,10,15])
res = np.amax(stack)
res1 = np.amin(stack)
print res, type(res)
print res1, type(res1)
#~ for (x,y,z), value in np.ndenumerate(stack):
#~ stack[x,y,z]=np.require(stack[x,y,z],dtype=np.int16)
#~ print type(stack[x,y,z])
stack = np.require(stack,dtype=np.uint16)
print stack.dtype
if DEBUG : print stack.shape
dataImporter = vtk.vtkImageImport()
data_string = stack.tostring()
dataImporter.CopyImportVoidPointer(data_string, len(data_string))
dataImporter.SetDataScalarTypeToUnsignedChar()
dataImporter.SetNumberOfScalarComponents(1)
dataImporter.SetDataExtent(0, w-1, 0, 1, 0, h-1)
dataImporter.SetWholeExtent(0, w-1, 0, 1, 0, h-1)
essai = raw_input()
alphaChannelFunc = vtk.vtkPiecewiseFunction()
colorFunc = vtk.vtkColorTransferFunction()
for i in range (0,255):
alphaChannelFunc.AddPoint(i, 0.9)
colorFunc.AddRGBPoint(i,i,i,i)
volumeProperty = vtk.vtkVolumeProperty()
volumeProperty.SetColor(colorFunc)
#volumeProperty.ShadeOn()
volumeProperty.SetScalarOpacity(alphaChannelFunc)
# This class describes how the volume is rendered (through ray tracing).
compositeFunction = vtk.vtkVolumeRayCastCompositeFunction()
# We can finally create our volume. We also have to specify the data for it, as well as how the data will be rendered.
volumeMapper = vtk.vtkVolumeRayCastMapper()
volumeMapper.SetVolumeRayCastFunction(compositeFunction)
volumeMapper.SetInputConnection(dataImporter.GetOutputPort())
# The class vtkVolume is used to pair the preaviusly declared volume as well as the properties to be used when rendering that volume.
volume = vtk.vtkVolume()
volume.SetMapper(volumeMapper)
volume.SetProperty(volumeProperty)
# With almost everything else ready, its time to initialize the renderer and window, as well as creating a method for exiting the application
renderer = vtk.vtkRenderer()
renderWin = vtk.vtkRenderWindow()
renderWin.AddRenderer(renderer)
renderInteractor = vtk.vtkRenderWindowInteractor()
renderInteractor.SetRenderWindow(renderWin)
# We add the volume to the renderer ...
renderer.AddVolume(volume)
# ... set background color to white ...
renderer.SetBackground(1, 1, 1)
# ... and set window size.
renderWin.SetSize(400, 400)
# A simple function to be called when the user decides to quit the application.
def exitCheck(obj, event):
if obj.GetEventPending() != 0:
obj.SetAbortRender(1)
# Tell the application to use the function as an exit check.
renderWin.AddObserver("AbortCheckEvent", exitCheck)
#to quit, press q
renderInteractor.Initialize()
# Because nothing will be rendered without any input, we order the first render manually before control is handed over to the main-loop.
renderWin.Render()
renderInteractor.Start()
I finally find out what was wrong
here's my new code
import vtk
import numpy as np
import os
import matplotlib.pyplot as plt
import PIL
import Image
DEBUG =False
directory="splitted_mri/"
l = []
k=0 #add the next picture in a differente level of depth/z-positions
for file in os.listdir(directory):
img = directory + file
if DEBUG : print img
l.append(img)
# the os.listdir function do not give the files in the right order
#so we need to sort them
l=sorted(l)
temp = Image.open(l[0])
h, w = temp.size
d = len(l)*5 #with our sample each images will be displayed 5times to get a better view
if DEBUG : print 'width, height, depth : ',w,h,d
stack = np.zeros((w,d,h),dtype=np.uint8)
for i in l:
im = Image.open(i)
temp = np.asarray(im, dtype=int)
for i in range(5):
stack[:,k+i,:]= temp
k+=5
#~ stack[:,k,:]= temp
#~ k+=1
if DEBUG :
res = np.amax(stack)
print 'max value',res
res1 = np.amin(stack)
print 'min value',res1
#convert the stack in the right dtype
stack = np.require(stack,dtype=np.uint8)
if DEBUG :#check if the image have not been modified
test = stack [:,0,:]
plt.imshow(test,cmap='gray')
plt.show()
if DEBUG : print 'stack shape & dtype' ,stack.shape,',',stack.dtype
dataImporter = vtk.vtkImageImport()
data_string = stack.tostring()
dataImporter.CopyImportVoidPointer(data_string, len(data_string))
dataImporter.SetDataScalarTypeToUnsignedChar()
dataImporter.SetNumberOfScalarComponents(1)
#vtk uses an array in the order : height, depth, width which is
#different of numpy (w,h,d)
w, d, h = stack.shape
dataImporter.SetDataExtent(0, h-1, 0, d-1, 0, w-1)
dataImporter.SetWholeExtent(0, h-1, 0, d-1, 0, w-1)
alphaChannelFunc = vtk.vtkPiecewiseFunction()
colorFunc = vtk.vtkColorTransferFunction()
for i in range(256):
alphaChannelFunc.AddPoint(i, 0.2)
colorFunc.AddRGBPoint(i,i/255.0,i/255.0,i/255.0)
# for our test sample, we set the black opacity to 0 (transparent) so as
#to see the sample
alphaChannelFunc.AddPoint(0, 0.0)
colorFunc.AddRGBPoint(0,0,0,0)
volumeProperty = vtk.vtkVolumeProperty()
volumeProperty.SetColor(colorFunc)
#volumeProperty.ShadeOn()
volumeProperty.SetScalarOpacity(alphaChannelFunc)
# This class describes how the volume is rendered (through ray tracing).
compositeFunction = vtk.vtkVolumeRayCastCompositeFunction()
# We can finally create our volume. We also have to specify the data for
# it, as well as how the data will be rendered.
volumeMapper = vtk.vtkVolumeRayCastMapper()
# function to reduce the spacing between each image
volumeMapper.SetMaximumImageSampleDistance(0.01)
volumeMapper.SetVolumeRayCastFunction(compositeFunction)
volumeMapper.SetInputConnection(dataImporter.GetOutputPort())
# The class vtkVolume is used to pair the preaviusly declared volume as
#well as the properties to be used when rendering that volume.
volume = vtk.vtkVolume()
volume.SetMapper(volumeMapper)
volume.SetProperty(volumeProperty)
# With almost everything else ready, its time to initialize the renderer and window,
# as well as creating a method for exiting the application
renderer = vtk.vtkRenderer()
renderWin = vtk.vtkRenderWindow()
renderWin.AddRenderer(renderer)
renderInteractor = vtk.vtkRenderWindowInteractor()
renderInteractor.SetRenderWindow(renderWin)
# We add the volume to the renderer ...
renderer.AddVolume(volume)
# ... set background color to white ...
renderer.SetBackground(1, 1, 1)
# ... and set window size.
renderWin.SetSize(550, 550)
renderWin.SetMultiSamples(4)
# A simple function to be called when the user decides to quit the application.
def exitCheck(obj, event):
if obj.GetEventPending() != 0:
obj.SetAbortRender(1)
# Tell the application to use the function as an exit check.
renderWin.AddObserver("AbortCheckEvent", exitCheck)
#to auit, press q
renderInteractor.Initialize()
# Because nothing will be rendered without any input, we order the first
# render manually before control is handed over to the main-loop.
renderWin.Render()
renderInteractor.Start()
If you are ok with a solution not using VTK, you could use Matplotlib imshow and interactive navigation with keys.
This tutorial shows how:
https://www.datacamp.com/community/tutorials/matplotlib-3d-volumetric-data
https://github.com/jni/mpl-volume-viewer
and here an implementation for viewing RTdose files:
https://github.com/pydicom/contrib-pydicom/pull/19
See also:
https://github.com/napari/napari