Call Argument into other function Octave GNU? - arguments
I'm using Octave GNU for GUI Excel data.
I want to ask you guys how can I call defined argument in another function.
Here is my code.
%%First Function = pushbutton_Callback
function pushbutton_Callback(hObject, eventdata, handles)
fileName = uigetfile('*.xlsx')%%excel data import
handles.fileName=fileName;
guidata(hObject, handles)
endfunction
%%Second Function = popupmenuX_Callback
function popupmenuX_Callback(hObject, eventdata, handles)
fileName = fileName #pushbutton_Callback;
printf ("in popupmenuX_Callback, calling pushbutton_Callback\n");
%%To nested function to prevent (because in Octave nested function is not accepted), I used subfunction as alternative%%
handles.fileName=fileName; %% This argument fileName I want to bring from first function
[numbers, colNames]=xlsread(fileName); %%read columns of excel data in first function
set(hObject,'string',colNames);
endfunction
If I put my functions like this, always come these errors.
>> fileName = V8.xlsx
error: superclass calls can only occur in methods or constructors
error: called from
popupmenuX_Callback at line 61 column 10
So what I want to do is, I want to bring defined Argument "fileName" in first function (pushbutton_Callback) to second function (popupX_callback). But it can not be defined in second function.
I've heard that nested function in octave can be resolved with "foo", "foobar" or "ex_top", "ex_a" function. But I can't not resolve the problem with "ex_"function. Then should I have to use "foo", "foobar" function to call arguments into other function?
Best regards!
===========================================================================
I edited my questions with my full codes.
(Full codes below)
So what I want to do is, just like this video. But in Matlab like in video, it can be made with GUIDE or Application designer but in Octave there are no functions like that. So as a octave Beginner, it is hard for me to solve the problem.
%%Versuch
%% Diagramm zeichen
%%============================================================================
close all
clear h
graphics_toolkit qt
pkg load io
%%Uicontrols
%%Graph
h.ax = axes ("position", [0.3 0.25 0.6 0.5]);
%%Title
h.plot_title_label = uicontrol ("style", "text",
"units", "normalized",
"string", "Versuchsergebnis",
"horizontalalignment", "left",
"position", [0.03 0.9 0.25 0.08]);
%% Design for excel data import
h.print_pushbutton = uicontrol ("style", "pushbutton",
"units", "normalized",
"string", "Excel Datei mitbringen",
"callback", #pushbutton_Callback,
"position", [0.03 0.8 0.3 0.09]);
%% Drawing axis
h.popupmenuX = uicontrol("Style","popupmenu",
"units", "normalized",
"string","X Axis",...
"callback", #popupmenuX_Callback,
"Position",[0.7 0.04 0.2 0.05]);
h.popupmenuY = uicontrol("Style","popupmenu",
"units", "normalized",
"string","Y Axis",
"callback",#popupmenuY_Callback,
"Position",[0.03 0.5 0.2 0.05]);
%%=============================================================================
%% Functions
%%=============================================================================
%% 1. Excel Data import
function pushbutton_Callback(hObject, eventdata, handles)
fileName = uigetfile('*.xlsx')%%excel data import
handles.fileName = fileName;
guidata(hObject, handles)
endfunction
%% 2. X Axis Information from excel data import
function popupmenuX_Callback(hObject, eventdata, handles)
fileName = pushbutton_Callback(hObject, eventdata, handles)
%%This code fileName causes error, that 'handles' is not defined.%%
handles.fileName = fileName; %% This argument fileName I want to bring from first function
[numbers, colNames] = xlsread(fileName); %%read columns of excel data in first function
set(hObject,'string',colNames);
endfunction
%% 3. Y Axis Information from excel data import
function popupmenuY_Callback(hObject, eventdata, handles)
filename = pushbutton_Callback(hObject, eventdata, handles)
handles.fileName = fileName;
[numbers, colNames] = xlsread(fileName);
set(hObject,'string',colNames);
endfunction
%%%% Plot the graph
a = xlsread (fileName);
xColNum = get(popupmenuX_Callback,'value');
yColNum = get(popupmenuY_Callback,'value');
fileName = handles.fileName;
x = a(:,xColNum);
y = a(:,yColNum);
h.ax = plot(x,y);
Example of GUI which allows loading a .csv file, and populating two popupmenus based on the csv headers.
Example data.csv file:
Col1, Col2, Col3
1, 2, 3
2, 4, 8
3, 8, 9
Example myscript.m
pkg load io
% Create the Gui Window which will hold all controls and relevant data.
GuiWindow = figure()
% An 'axes' object for displaying plots in the Gui Window
axes ("position", [0.3 0.25 0.6 0.5], 'tag', 'plotarea' );
% Static text element used as a title
uicontrol ("style", "text", "units", "normalized", "string", "Fur Zoo Hair Geb knees.", "horizontalalignment", "left", "position", [0.03 0.9 0.3 0.08] );
% A button for importing (excel) data
uicontrol ("style", "pushbutton", "units", "normalized", "string", "CSV Dat Eye Meat Bringen", "callback", { #pushbutton_Callback, GuiWindow }, "position", [0.03 0.8 0.35 0.09], 'tag', 'button' );
% Popupmenus for selecting appropriate X and Y axis to display in plots
uicontrol("Style","popupmenu", "units", "normalized", "string","X Axis", "callback", { #popupmenuX_Callback, GuiWindow }, "Position",[0.7 0.04 0.2 0.05], 'tag', 'XAxisMenu' );
uicontrol("Style","popupmenu", "units", "normalized", "string","Y Axis", "callback", { #popupmenuY_Callback, GuiWindow }, "Position",[0.03 0.5 0.2 0.05], 'tag', 'YAxisMenu' );
%%=============================================================================
%% Functions (preferably placed in their own files!)
%%=============================================================================
function pushbutton_Callback(hObject, eventdata, GuiWindow)
% Read in data from file, graphically selected by user
fileName = uigetfile('*.csv');
CellCsv = csv2cell( fileName );
Header = CellCsv(1, :);
Data = CellCsv(2:end, :);
% Populate the menu items for the X and Y Axis from the csv header
XAxisMenu = findobj( 'tag', 'XAxisMenu' );
set( XAxisMenu, 'string', Header );
YAxisMenu = findobj( 'tag', 'YAxisMenu' );
set( YAxisMenu, 'string', Header );
% Also store headers and data as GuiWindow app data, in case we need them again later.
setappdata( GuiWindow, 'Header', Header );
setappdata( GuiWindow, 'Data' , Data );
% Plot a preliminary plot in the plot area
XData = [Data{:, 1}];
YData = [Data{:, 1}];
plot( XData, YData, 'bo-', 'tag', 'plotobject' );
endfunction
%% 2. X Axis Information from excel data import
function popupmenuX_Callback( hObject, eventdata, GuiWindow )
Axes = findobj( 'tag', 'plotarea' );
Selection = get( hObject, 'value' );
XData = [ getappdata( GuiWindow, 'Data' ){ :, Selection } ];
PlotObj = findobj( 'tag', 'plotobject' );
set( PlotObj, 'xdata', XData )
endfunction
%% 3. Y Axis Information from excel data import
function popupmenuY_Callback( hObject, eventdata, GuiWindow )
Axes = findobj( 'tag', 'plotarea' );
Selection = get( hObject, 'value' );
YData = [ getappdata( GuiWindow, 'Data' ){ :, Selection } ];
PlotObj = findobj( 'tag', 'plotobject' );
set( PlotObj, 'ydata', YData )
endfunction
This demonstrates two methods of accessing other graphical objects within callbacks. One is providing an object as an argument (e.g., GuiWindow), and the other is providing 'tags' that can be used to identify objects via the findobj function.
Note that I stored data in the GuiWindow object only, not to each individual graphical object (like buttons etc). Also, I preferred setappdata, because it allows to store multiple data under individual names (whereas guidata only stores a single object, although this can be a struct).
Above there is Tasos's answer (with csv file), I applied his answer to my code, which works with excel file. Because the code xlsread ignores the columns, users should have to care about that.
Thank you again Tasos!
pkg load io
% Create the Gui Window which will hold all controls and relevant data.
GuiWindow = figure()
% An 'axes' object for displaying plots in the Gui Window
axes ("position", [0.3 0.25 0.6 0.5], 'tag', 'plotarea' );
% Static text element used as a title
uicontrol ("style", "text", "units", "normalized", "string", "Versuchsergebnis",'ForegroundColor','w','BackgroundColor',[0 0.4470 0.7410],'Fontweight','bold', "horizontalalignment", "center", "position", [0.03 0.9 0.35 0.08] );
% A button for importing (excel) data
uicontrol ("style", "pushbutton", "units", "normalized", "string", "Datei(xlsx) mitbringen", "callback", { #pushbutton_Callback, GuiWindow }, "position", [0.03 0.8 0.35 0.09], 'tag', 'button' );
% Popupmenus for selecting appropriate X and Y axis to display in plots
uicontrol("Style","popupmenu", "units", "normalized", "string","X Axis", "callback", { #popupmenuX_Callback, GuiWindow }, "Position",[0.7 0.04 0.2 0.05], 'tag', 'XAxisMenu' );
uicontrol("Style","popupmenu", "units", "normalized", "string","Y Axis", "callback", { #popupmenuY_Callback, GuiWindow }, "Position",[0.03 0.5 0.2 0.05], 'tag', 'YAxisMenu' );
%%=============================================================================
%% Functions (preferably placed in their own files!)
%%=============================================================================
function pushbutton_Callback(hObject, eventdata, GuiWindow)
% Read in data from file, graphically selected by user
fileName = uigetfile('*.xlsx');
[num,txt,raw] = xlsread(fileName);
header = raw(1,:);
Data = xlsread(fileName);
% Show fileName
button = findobj('tag', 'button');
set( button, 'string', fileName)
% Populate the menu items for the X and Y Axis from the csv header
XAxisMenu = findobj( 'tag', 'XAxisMenu' );
set( XAxisMenu, 'string', header );
YAxisMenu = findobj( 'tag', 'YAxisMenu' );
set( YAxisMenu, 'string', header );
% Also store headers and data as GuiWindow app data, in case we need them again later.
setappdata( GuiWindow, 'header', header );
setappdata( GuiWindow, 'Data' , Data );
% Plot a preliminary plot in the plot area
XData = Data(:, 1);
YData = Data(:, 1);
plot( XData, YData, 'tag', 'plotobject' );
endfunction
%% 2. X Axis Information from excel data import
function popupmenuX_Callback( hObject, eventdata, GuiWindow )
Axes = findobj( 'tag', 'plotarea' );
Selection = get( hObject, 'value' );
XData = [ getappdata( GuiWindow, 'Data' )( :, Selection ) ];
PlotObj = findobj( 'tag', 'plotobject' );
set( PlotObj, 'xdata', XData )
endfunction
%% 3. Y Axis Information from excel data import
function popupmenuY_Callback( hObject, eventdata, GuiWindow )
Axes = findobj( 'tag', 'plotarea' );
Selection = get( hObject, 'value' );
YData = [ getappdata( GuiWindow, 'Data' )( :, Selection ) ];
PlotObj = findobj( 'tag', 'plotobject' );
set( PlotObj, 'ydata', YData )
endfunction
The line
fileName = fileName #pushbutton_Callback;
doesn't do what you think it does.
It's a bit complicated to explain the background, but basically in matlab, new-style classes created with the classdef keyword, which also allow inheritance, allow you to call a method of a 'parent' class (or "superclass") via the methodname#parentclassname(args) syntax. Octave has ported this system to octave too, for matlab compatibility. The error you get effectively says you're trying to call a superclass method, in a context where it doesn't make sense (which is true, since you're not inside a classdef block).
This explains why you get that error.
Now, in terms of what you're trying to do, I think you basically just want to call the pushbutton_Callback function from within your popupmenuX_Callback one, right? So just do that, with appropriate arguments, e.g.:
filename = pushbutton_Callback(hObject, eventdata, handles)
[numbers, colNames] = xlsread(fileName);
PS. I would recommend you always indent code inside functions. It looks clearer and helps catch bugs!
Related
how to use seaborn objects scale with two visualisations with same kwargs?
I'm trying to create bar plot with labels on bars. Position of labels and color of labels depends on column of dataframe. Also, I would like to color bars by column. My data: data = { 'Survived': ['0', '1'], 'count': [500, 100], 'label_position': ['R', 'L'] } df = pd.DataFrame(data) I tried to create following plot: import seaborn.objects as so p = ( so.Plot(df, x='count', y='Survived') .add(so.Bar(alpha=1), color='Survived') .add( so.Text({"fontweight": "bold"}), text='count', halign='label_position', color="label_position" ) .scale( halign={'L':'left', 'R':'right'}, color={'L':'black', 'R':'white'} ) ) p.plot() but this code raises following error: PlotSpecError: Scale setup failed for the `color` variable. See the traceback above for more information. because both visualizations have attribute color. I'm able co color bars, or the text, but not both at once. Colored bars: color the bars Colored text: color the text Is there any posibility to color both?
If we see the traceback above for more information as the exception message suggests, it says ValueError: No entry in color dictionary for '0', '1' So we could try adding entries for those keys: ( so.Plot(df, x='count', y='Survived') .add(so.Bar(alpha=1), color='Survived') .add( so.Text({"fontweight": "bold"}), text='count', halign='label_position', color="label_position", ) .scale( halign={'L':'left', 'R':'right'}, color={'L':'black', 'R':'white', '0': 'black', '1': 'white'}, # <----- ) ) That works but now we have some entries in the legend that we probably don't want. There's not in general a way to control what shows up in the legend independently of what actually gets mapped for Nominal scales, but for this particular plot the color encoding is redundant anyway so we don't actually need the legend: ( so.Plot(df, x='count', y='Survived') .add(so.Bar(alpha=1), color='Survived', legend=False) # <----- .add( so.Text({"fontweight": "bold"}), text='count', halign='label_position', color="label_position", ) .scale( halign={'L':'left', 'R':'right'}, color={'L':'black', 'R':'white', '0': 'black', '1': 'white'}, ) )
How to add control for single subplot in plotly?
In plotly I use a figure that contains several subplot. For the last subplot I want to be able to change the type with a dropdown menu. However, the "restyle" action of the dropdown seems to be applied to the whole figure? If I use the dropdown, the other subplots disapear: => How to add a plotly control for a specific subplot? or => How to tell a control do only influence the properties of a specific subplot? Read data import pandas as pd # read in volcano database data df = pd.read_csv( "https://raw.githubusercontent.com/plotly/datasets/master/volcano_db.csv", encoding="iso-8859-1", ) # frequency of Country freq = df freq = freq.Country.value_counts().reset_index().rename(columns={"index": "x"}) # read in 3d volcano surface data df_v = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/volcano.csv") Initialize figure with subplots from plotly.subplots import make_subplots import plotly.graph_objects as go fig = make_subplots( rows=3, cols=2, column_widths=[0.6, 0.4], row_heights=[0.4, 0.2, 0.4], specs=[ [{"type": "scattergeo", "rowspan": 2}, {"type": "bar"}], [None, None], [None, {"type": "surface"}] ] ) # Add scattergeo globe map of volcano locations scatter_geo = go.Scattergeo( lat=df["Latitude"], lon=df["Longitude"], mode="markers", hoverinfo="text", showlegend=False, marker=dict(color="crimson", size=4, opacity=0.8) ) fig.add_trace( scatter_geo, row=1, col=1 ) # Add locations bar chart bar = go.Bar( x=freq["x"][0:10], y=freq["Country"][0:10], marker=dict(color="crimson"), showlegend=False ) fig.add_trace( bar, row=1, col=2 ) # Add 3d surface of volcano surface_3d = go.Surface( z=df_v.values.tolist(), showscale=False ) fig.add_trace( surface_3d, row=3, col=2 ) fig Add controls # Add dropdown updatemenu = dict( buttons=list([ dict( args=["type", "surface"], label="3D Surface", method="restyle" ), dict( args=["type", "heatmap"], label="Heatmap", method="restyle" ) ]), direction="down", pad={"r": 10, "t": 10}, showactive=True, x=1, y=0.4 ) fig['layout'].update( updatemenus=[{}, {}, {}, {}, {}, updatemenu] ) #Add slider steps = [] for i in range(10): step = dict( method="update", args=[{"title": "Slider switched to step: " + str(i)}], # layout attribute ) steps.append(step) slider = dict( active=10, currentvalue={"prefix": "Frequency: "}, pad={"t": 50}, steps=steps ) fig.update_layout( sliders=[slider] ) Additional styling # Update geo subplot properties fig.update_geos( projection_type="orthographic", landcolor="white", oceancolor="MidnightBlue", showocean=True, lakecolor="LightBlue" ) # Rotate x-axis labels fig.update_xaxes(tickangle=45) # Set theme, margin, and annotation in layout fig.update_layout( autosize=False, width=800, height=500, template="plotly_dark", margin=dict(r=10, t=25, b=40, l=60), scene_camera_eye=dict(x=2, y=2, z=0.3), annotations=[ dict( text="Source: NOAA", showarrow=False, xref="paper", yref="paper", x=0, y=0) ] ) fig.show()
Unfortunately, this is not a complete answer. But hopefully, what I'm about to show you will help you on your way. You see, you can specify which subplot to edit by the traces contained in that subplot. You do so by adding an integer in args() like so: buttons=list([ dict( args=["type", "surface", [2]], label="3D Surface", method="restyle" ) And [2] references the position of your trace in fig.data: (Scattergeo({ 'geo': 'geo', 'hoverinfo': 'text', 'lat': array([ 34.5 , -23.3 , 14.501, ..., 15.05 , 14.02 , 34.8 ]), 'lon': array([ 131.6 , -67.62 , -90.876, ..., 42.18 , 42.75 , -108. ]), 'marker': {'color': 'crimson', 'opacity': 0.8, 'size': 4}, 'mode': 'markers', 'showlegend': False }), Bar({ 'marker': {'color': 'crimson'}, 'showlegend': False, 'x': array(['United States', 'Russia', 'Indonesia', 'Japan', 'Chile', 'Ethiopia', 'Papua New Guinea', 'Philippines', 'Mexico', 'Iceland'], dtype=object), 'xaxis': 'x', 'y': array([184, 169, 136, 111, 87, 57, 54, 49, 41, 38], dtype=int64), 'yaxis': 'y' }), Surface({ 'scene': 'scene', 'showscale': False, The problem is, that doing it this way in your case will trigger some very peculiar behavior: when the button is set to heatmap, the data becomes bart of the Bar figure: And what's even stranger, is that it looks the way it should when you select 3D Surface again: And I honestly have no idea what causes this. Take a look for yourself in the complete code snippet below and see what you can make of it. Maybe we'll be able to figure it out eventually... Complete code: from plotly.subplots import make_subplots import plotly.graph_objects as go import pandas as pd # read in volcano database data df = pd.read_csv( "https://raw.githubusercontent.com/plotly/datasets/master/volcano_db.csv", encoding="iso-8859-1", ) # frequency of Country freq = df freq = freq.Country.value_counts().reset_index().rename(columns={"index": "x"}) # read in 3d volcano surface data df_v = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/volcano.csv") df_v fig = make_subplots( rows=3, cols=2, column_widths=[0.6, 0.4], row_heights=[0.4, 0.2, 0.4], specs=[ [{"type": "scattergeo", "rowspan": 2}, {"type": "bar"}], [None, None], [None, {"type": "surface"}] ] ) # Add scattergeo globe map of volcano locations scatter_geo = go.Scattergeo( lat=df["Latitude"], lon=df["Longitude"], mode="markers", hoverinfo="text", showlegend=False, marker=dict(color="crimson", size=4, opacity=0.8) ) fig.add_trace( scatter_geo, row=1, col=1 ) # Add locations bar chart bar = go.Bar( x=freq["x"][0:10], y=freq["Country"][0:10], marker=dict(color="crimson"), showlegend=False ) fig.add_trace( bar, row=1, col=2 ) # Add 3d surface of volcano surface_3d = go.Surface( z=df_v.values.tolist(), showscale=False ) fig.add_trace( surface_3d, row=3, col=2 ) # Add dropdown updatemenu = dict( buttons=list([ dict( args=["type", "surface", [2]], label="3D Surface", method="restyle" ), dict( args=["type", "heatmap", [2]], label="Heatmap", method="restyle" ) ]), direction="down", pad={"r": 10, "t": 10}, showactive=True, x=1, y=0.4 ) fig['layout'].update( updatemenus=[{}, {}, {}, {}, {}, updatemenu] ) #Add slider steps = [] for i in range(10): step = dict( method="update", args=[{"title": "Slider switched to step: " + str(i)}], # layout attribute ) steps.append(step) slider = dict( active=10, currentvalue={"prefix": "Frequency: "}, pad={"t": 50}, steps=steps ) fig.update_layout( sliders=[slider] ) # Update geo subplot properties fig.update_geos( projection_type="orthographic", landcolor="white", oceancolor="MidnightBlue", showocean=True, lakecolor="LightBlue" ) # Rotate x-axis labels fig.update_xaxes(tickangle=45) # Set theme, margin, and annotation in layout fig.update_layout( autosize=False, width=800, height=500, template="plotly_dark", margin=dict(r=10, t=25, b=40, l=60), scene_camera_eye=dict(x=2, y=2, z=0.3), annotations=[ dict( text="Source: NOAA", showarrow=False, xref="paper", yref="paper", x=0, y=0) ] ) fig.show()
canvas.create_window not working?
I want to place a widget in my canvas. I have written the following function to create a button and display it. in the center of the x coordinate of my canvas. def Button_Placer(): label1=Label(canvas, width =20, height = 2, font = font2, text="") label1.pack() def Show_Name(): name=NameGenerator() label1.config(text=name) button1=Button(canvas, text="Generate Name", width=20, height=4, font=font1, command=Show_Name) button1=canvas.create_window(250, 300) I have also created a canvas at the top: canvas = Canvas(root, width=500, height = 500, bg="red") canvas.pack() Unfortunately the canvas.create_window does not work. .pack() works however is not what i need. I have looked at other examples however they are all off OOP and therefore do not find it relevant for my understanding.
As #CommonSense writes, try canvas.create_window(200, 200, window=button1). Also; you create label1 inside a function and when the functioin exits the name label1 will be garbage collected. When you create widgets on canvas the reference is an integer; the index of that widget on the canvas. If you use the widget name as reference for the canvas widget you lose the reference to the actual widget. Try the example below: from tkinter import * root = Tk() canvas = Canvas(root, width=500, height=500, bg="red") canvas.pack() def Show_Name(): name = 'A name' # No function NameGenerator() label1.config(text=name) button1 = Button(canvas, text="Generate Name", width=20, height=4, command=Show_Name) canvas_button1 = canvas.create_window(250, 300, window=button1) label1 = Label(canvas, width=20, height=2, text="") canvas_label1 = canvas.create_window(250, 200, window=label1)
Enable/disable clipping per material (r87)
I'm trying to work with THREE's clipping planes, I didn't read the description of Material.clipIntersection and just blindly took it to mean "is clipping enabled". After reading the description, playing with the example and digging through code I've concluded that there is no parameter to control wether the clipping is enabled or not. The only two interfaces are: .clippingPlanes[] .clipIntersection And perhaps Renderer.localClippingEnabled but i don't want to globally enable/disable the... local clipping. Ie. if i have two materials, i'd like to be able to control it on one. The problem seems to be that clippingPlanes defines NUM_CLIPPING_PLANES: '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes, And I can see that there is more stuff going on with WebGLClipping. Still i'm confused by the define and am wondering if i need to update the material every time i add/remove the clipping planes. tl:dr; Is there a built in way to easily add a toggle to enable/disable the clipping to this example: https://threejs.org/examples/#webgl_clipping_intersection, without recompiling the shader?
Probably not in the spirit of your question, but the easy solution is to replace the clippingPlanes property with an empty array. I changed/added the following code in the example: var params = { clipPlanesOn: true, clipIntersection: true, planeConstant: 0, showHelpers: false }; ... var clipPlanes = [ new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ), new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 0 ), new THREE.Plane( new THREE.Vector3( 0, 0, - 1 ), 0 ) ]; var clipPlanesOff = []; ... gui.add( params, 'clipPlanesOn' ).name( 'clip planes on' ).onChange( function ( value ) { var children = group.children; for ( var i = 0; i < children.length; i ++ ) { children[ i ].material.clippingPlanes = (value) ? clipPlanes : clipPlanesOff; } render(); } ); Checking the box turns the clipping on/off. Update with more info: AFAICT, it's all "automagic". Each render during setProgram, WebGLRenderer sets a variable called _clippingEnabled. This is set based on the return value from WebGLClipping.init, where one of the cases checks if the material has any values in its clippingPlanes property. WebGLClipping has the following line: uniform = { value: null, needsUpdate: false }; With _clippingEnabled set to true, and some values in the clippingPlanes property, the process makes its way into projectPlanes of WebGLClipping, which includes the line: uniform.needsUpdate = true; Boom. The uniform is flagged for automagic update.
THREE.js loading .OBJ files - why do some render flat?
I am using the same general purpose code to load basic mesh objects (no textures) from OBJ files (obtained free from sites on the web). Some objects render OK in that different faces reflect light with different intensities towards the camera. But other objects just render a uniform matt color and so their form cannot be seen. I have looked inside the files and noticed various differences. For example one successful file contains records with the following initial characters v, vt, vn, f, s (vertex, vertext texture, vertex normal, face, smooth). An example of an unsuccessful file has these initial characters: v, vt, f. Here is the code which I am using. function F_Load_OBJ_Model ( givenFilespec, givenName, givenScene, givenHexColorStr, posX, posY, posZ, rotX, rotY, rotZ, scaleX, scaleY, scaleZ ) { var OBJLoader = new THREE.OBJLoader(); OBJLoader.load( givenFilespec, F_make_LoadedOBJ_Handler ( givenName, givenScene, givenHexColorStr, posX, posY, posZ, rotX, rotY, rotZ, scaleX, scaleY, scaleZ ) ); } function F_make_LoadedOBJ_Handler( givenName, givenScene, givenHexColorStr, posX, posY, posZ, rotX, rotY, rotZ, scaleX, scaleY, scaleZ ) { //... See Tapio's answer (callback factory for use in loops) //... at http://stackoverflow.com/questions/10920372/associate-loaded-json-files-with-a-name-for-later-access //... This is useful in case have a loop loading multiple objects asynchronously. return function ( object ) { //... Note that <object> is a THREE Object3D which can have 1 or more child meshes. //... But I will assume that there is only one child mesh. //var material = new THREE.MeshBasicMaterial(); //eval( givenName + " = new THREE.Mesh( geometry, material );" ); //eval ( " var thisMeshOb =" + givenName ); //eval( givenName + " = object.children[0];" ); //....OK alias eval( givenName + " = object.children[0].clone();" );//... also OK //object.delete(); //... not possible or neccy, javascript will delete any object which cannot be referred to again. eval ( " var thisMeshOb =" + givenName );//... alias used for following common local commands thisMeshOb.position.set( posX, posY, posZ ); thisMeshOb.rotation.set( rotX, rotY, rotZ ); thisMeshOb.name = givenName; thisMeshOb.scale.set( scaleX, scaleY, scaleZ ); givenScene.add( thisMeshOb ); //xxx thisMeshOb.material.type = THREE.MeshLambertMaterial(); thisMeshOb.material.color.setHex( givenHexColorStr ) ;//...("0xff0000"); thisMeshOb.geometry.computeFaceNormals(); //...no effect thisMeshOb.geometry.normalsNeedUpdate = true; //... no effect //... for PHONG ... floorGeometry.computeVertexNormals(); thisMeshOb.updateMatrix(); //... without this the next is not effective!? xxx = SOW_F_grob_Add_to_Target_Set( thisMeshOb ); }; }//... EOF F_make_LoadedOBJ_Handler. I guessed that it might be something to do with missing vertex normals. But adding the code to update them had no effect on the end result. So is there a problem with the files or can I do something in THREE.js to make them render properly?
You've found correctly that the flat-looking files have no "vn" info. "vn" means "vertex normal" -- that is, the direction that the (smoothed) normal is facing. You can try calling something like thisMeshOb.geometry.computeFaceNormals(); and possibly follow it with thisMeshOb.geometry.computeVertexNormals(); -- then set thisMeshOb.geometry.normalsNeedUpdate = true; -- this will calculate a new set of normals directly inside THREE. You only need to call this once per session, at read-in time, btw -- no need to recalculate every frame.