def test_plotting(self): # create a basic plot, request the layout and data, then create a plotly figure test = BasicPlot(x_label='Test', y_label='Test Y', graph_height=400, graph_width=400, marker_size=6.0, layout={'plot_bgcolor': '#fff'}, figure_border=1, x_min=0, x_max=2.0, y_min=0, y_max=2.0) # now add some data test.add_data(x_data=[0.1, 0.2], y_data=[0.5, 0.6], error_x={'type': 'data', 'array': [0.05, 0.05], 'visible': True}, mode='markers+lines', name='testing', text='testing_text') test_plot = test.get_plot(as_figure=True) # fig = go.Figure( # data=[go.Bar(y=[2, 1, 3])], # layout_title_text="A Figure Displayed with the 'png' Renderer" # ) # fig.show(renderer="png") # fig = go.Figure(data=test_plot['data'], layout=test_plot['layout']) test_plot.write_image('test.svg') # plot(fig) # fig.show(renderer='png') a = 5
def init_plot(self, x_label, y_label, x_scale, y_scale): self.plot = BasicPlot(x_label=x_label, y_label=y_label, x_scale=x_scale, y_scale=y_scale, graph_height=self.graph_height, graph_width=self.graph_width)
def init_plot(self, x_label, y_label, x_scale, y_scale): self.plot = BasicPlot(x_label=x_label, y_label=y_label, x_scale=x_scale, y_scale=y_scale, graph_height=self.graph_height, graph_width=self.graph_width, marker_shapes=('circle',)) # make the plot only have circles self.plot.marker['size'] = 8
def save_tlm_plots(self): """ Saves TLM plots for this TLM instance at all Vd values. This includes R vs. Length, Rc vs. n, Rsheet vs. n """ for i, vd in enumerate(self.vd_values): new_dataset = self.tlm_datasets[vd] # now we can start computing TLM properties n_full = new_dataset.get_column('n') # get the column with the lowest max min min_max_n_col = np.argmin(np.max(n_full, axis=1)) # get the min_max n value min_max_n = np.min(np.max(n_full, axis=1)) # now get the min n value from the column with the min_max_n. This is important to ensure we get a rectangular n array max_min_n = np.partition( n_full[min_max_n_col][np.where( n_full[min_max_n_col, :] >= 1.0)[0]], 2)[2] # value = 989429999999.9993 = 9.89e+11 # expr: np.where((n_full[1]>max_min_n) & (n_full[1]<min_max_n)) # looks like for n_full[1] range is 29-122 with gap 68-83 for total of 78 values # n_full[0]: 37-114, missing 75-76 for total 76 values # n_full[2]: 31-120, missing 68-83 for total 76 values n = new_dataset.get_column('n', master_independent_value_range=[ max_min_n, min_max_n.magnitude ]) # check to make sure the n values are close enough. If the Vg step is not fine enough and the device Vts are hihgly varied, the n values may not be close enough # to extract TLM data at a specific n max_n_varience = np.max(n[:, 1]) - np.min(n[:, 1]) assert max_n_varience < self.maximum_n_varience, 'Varience in carrier density between the devices is {0}, which is greater than {1}. As such,' \ 'accurate TLM extraction is not possible. This could be the result of too small a gate' \ 'voltage step and high varience between device threshold voltages. You can try to remove ' \ 'device data with high varience, or lower the maximum_n_varience value in the' \ 'TLMExtractor object.'.format(max_n_varience, self.maximum_n_varience) n_r = np.round(np.array(n, dtype=float) * 1e-12) r = new_dataset.get_column('r', master_independent_value_range=[ max_min_n, min_max_n.magnitude ]) l = new_dataset.get_column('l', master_independent_value_range=[ max_min_n, min_max_n.magnitude ]) n_units = '10<sup>12</sup> cm<sup>-2</sup>' r_units = '\u03A9\u2022\u03BCm' # ;×μm' l_units = '\u03BCm' # create_scatter_plot(l[:, 0], r[:, 0], scale='lin', show=True, autoscale=True) r_sheet, r_sheet_error, rc, rc_error = self.linear_regression(l, r) # now add r_sheet and rc to the dataset # new_dataset.add_column() max_l = float(max(l[:, 0])) r_plot = BasicPlot(x_label='length {0}'.format(l_units), y_label='total resistance {0}'.format(r_units), marker_size=8.0, x_min=0.0, x_max=max_l * 1.2) for i in range(0, len(n[0]), round(len(n[0]) / 5)): r_plot.add_data(x_data=l[:, i], y_data=r[:, i], mode='markers', name='n = {0} {1}'.format(n_r[0][i], n_units), text='n') r_plot.add_line(x_data=[0.0, max_l], y_data=[float(rc[i]), float(r[-1, i])], name=None) r_plot.save_plot(name='r_at_vd_{0}'.format(vd)) rc_plot = BasicPlot( x_label='carrier density {0}'.format(n_units), y_label='contact resistance {0}'.format(r_units), marker_size=8.0) rc_plot.add_data(x_data=n[0] * 1e-12, y_data=rc, error_y={ 'type': 'data', 'array': np.array(rc_error, dtype=float), 'visible': True }, mode='markers', name='n', text='n') rc_plot.save_plot(name='rc_at_vd_{0}'.format(vd)) rsheet_plot = BasicPlot( x_label='carrier density {0}'.format(n_units), y_label='sheet resistance', marker_size=8.0) rsheet_plot.add_data(x_data=n[0] * 1e-12, y_data=r_sheet, error_y={ 'type': 'data', 'array': np.array(r_sheet_error, dtype=float), 'visible': True }, mode='markers', name='n', text='n') rsheet_plot.save_plot(name='rsheet_at_vd_{0}'.format(vd))
def save_tlm_plots(self): """ Saves TLM plots for this TLM instance at all Vd values. This includes R vs. Length, Rc vs. n, Rsheet vs. n """ for i, vd in enumerate(self.vd_values): new_dataset = self.tlm_datasets[vd] # now we can start computing TLM properties n_full = new_dataset.get_column('n') # grab the min max of n and the max min of n min_max_n = np.min(np.max(n_full, axis=1)) max_min_n = np.max([ np.min(n_full[i][np.where(n_full[i, :] >= 1.0)[0]]) for i in range(n_full.shape[0]) ]) n = new_dataset.get_column( 'n', master_independent_value_range=[max_min_n, min_max_n.value]) n_r = np.round(np.array(n, dtype=float) * 1e-12) r = new_dataset.get_column( 'r', master_independent_value_range=[max_min_n, min_max_n.value]) l = new_dataset.get_column( 'l', master_independent_value_range=[max_min_n, min_max_n.value]) n_units = '10<sup>12</sup> cm<sup>-2</sup>' r_units = '\u03A9\u2022\u03BCm' # ;×μm' l_units = '\u03BCm' # create_scatter_plot(l[:, 0], r[:, 0], scale='lin', show=True, autoscale=True) r_sheet, r_sheet_error, rc, rc_error = self.linear_regression(l, r) # now add r_sheet and rc to the dataset # new_dataset.add_column() max_l = float(max(l[:, 0])) r_plot = BasicPlot(x_label='length {0}'.format(l_units), y_label='total resistance {0}'.format(r_units), marker_size=8.0, x_min=0.0, x_max=max_l * 1.2) for i in range(0, len(n[0]), round(len(n[0]) / 5)): r_plot.add_data(x_data=l[:, i], y_data=r[:, i], mode='markers', name='n = {0} {1}'.format(n_r[0][i], n_units), text='n') r_plot.add_line(x_data=[0.0, max_l], y_data=[float(rc[i]), float(r[-1, i])], name=None) r_plot.save_plot(name='r_at_vd_{0}'.format(vd)) rc_plot = BasicPlot( x_label='carrier density {0}'.format(n_units), y_label='contact resistance {0}'.format(r_units), marker_size=8.0) rc_plot.add_data(x_data=n[0] * 1e-12, y_data=rc, error_y={ 'type': 'data', 'array': np.array(rc_error, dtype=float), 'visible': True }, mode='markers', name='n', text='n') rc_plot.save_plot(name='rc_at_vd_{0}'.format(vd)) rsheet_plot = BasicPlot( x_label='carrier density {0}'.format(n_units), y_label='sheet resistance', marker_size=8.0) rsheet_plot.add_data(x_data=n[0] * 1e-12, y_data=r_sheet, error_y={ 'type': 'data', 'array': np.array(r_sheet_error, dtype=float), 'visible': True }, mode='markers', name='n', text='n') rsheet_plot.save_plot(name='rsheet_at_vd_{0}'.format(vd))
def save_plots(self): I_units = '\u03BCA/\u03BCm' if self.idvg is not None: vg = self.idvg.get_column('vg')[0] # first save the IdVg and IdVd plots rc_plot = BasicPlot(x_label='Vg (V)', y_label='Id ({0})'.format(I_units), marker_size=8.0) for vd, id in self.idvg.get_set_indexed_columns('id').items(): rc_plot.add_data(x_data=vg, y_data=id * 1e6, mode='markers', name='Vd = {0}'.format(vd), text='n') rc_plot.save_plot(name='IdVg_plot') if self.idvd is not None: vd = self.idvd.get_column('vd')[0] # first save the IdVg and IdVd plots rc_plot = BasicPlot(x_label='Vd (V)', y_label='Id ({0})'.format(I_units), marker_size=8.0) for vg, id in self.idvd.get_set_indexed_columns('id').items(): rc_plot.add_data(x_data=vd, y_data=id * 1e6, mode='markers', name='Vg = {0}'.format(vg), text='n') rc_plot.save_plot(name='IdVd_plot') # now save a CSV file of the FET properties self.FET.publish_csv('.')
class BasicApp(BaseApp): # external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css'] # app = dash.Dash(__name__, external_stylesheets=external_stylesheets) def __init__(self, x_label, y_label, x_scale='linear', y_scale='linear', hidden_update=True, graph_height=None, graph_width=None, upload_input=False, *args, **kwargs): super(BasicApp, self).__init__(*args, **kwargs) self.graph_height = graph_height self.graph_width = graph_width self.upload_input = upload_input self.init_plot(x_label=x_label, y_label=y_label, x_scale=x_scale, y_scale=y_scale) self.update_function = None # the callback options self.callback_inputs = [] self.callback_states = [] self.callback_outputs = [] # app layout self.app_layout = html.Div( style={'margin': '0 auto'}, children=[ dcc.Graph(self.name), html.Div(className='col-sm', style={'display': 'none'} if hidden_update else {}, children=[ html.Button('Update', name='update_' + self.name, id='update_' + self.name, className='alert') ]) ], ) def add_div(self, div, top=False, bottom=False): # assert not top or not bottom, 'You must choose to add to the top or the bottom' assert top or bottom, 'You must choose to add to the top or the bottom' assert isinstance(div, html.Div), 'The input must be of type Div' if top: self.app_layout.children = [div] + self.app_layout.children elif bottom: self.app_layout.children.append(div) def init_plot(self, x_label, y_label, x_scale, y_scale): self.plot = BasicPlot(x_label=x_label, y_label=y_label, x_scale=x_scale, y_scale=y_scale, graph_height=self.graph_height, graph_width=self.graph_width) def build_app(self): self.app.layout = self.app_layout self._update_graph_function() # if there is an upload data module, run the callback creator if self.upload_input: self._upload_input_callback() # @self.app.callback(Output(self.name, 'figure'), # [Input('blank', 'value'), Input('update_' + self.name, 'n_clicks')]) # def update_graph(x_value, update): # if self.update_function is not None: # new_data = self.update_function(update) # # print(new_data) # if new_data is not None: # return self.plot.get_plot(new_data=new_data) # else: # return self.plot.get_plot() def _update_graph_function(self): @self.app.callback( [Output(self.name, 'figure')] + self.callback_outputs, [Input('update_' + self.name, 'n_clicks')] + self.callback_inputs, self.callback_states) def update_graph(update_n, *args): # create the kwargs output_callbacks = tuple([None for i in self.callback_outputs]) callbacks = self.callback_inputs + self.callback_states kwargs = { callback.component_id: _input for _input, callback in zip(args, callbacks) } # if data was uploaded to through an upload module, then convert the json to a dataframe if self.upload_input: kwargs['uploaded-data'] = self._read_df_from_json( kwargs['uploaded-data']) if self.update_function is not None: new_data = self.update_function(update_n, **kwargs) # print(new_data) if new_data is not None: # if new data is a dict, then extract the plot and callback data if isinstance(new_data, dict): callback_data = new_data['callback_data'] new_data = new_data['plot_data'] # look through the new data for any outputs that match the callback_outputs callback_outputs = [ callback_data.get(callback.component_id, None) for callback in self.callback_outputs ] else: callback_outputs = output_callbacks return (self.plot.get_plot( new_data=new_data), ) + tuple(callback_outputs) return (self.plot.get_plot(), ) + output_callbacks return update_graph def add_data(self, x, y, text, name, mode='markers'): self.plot.add_data(x, y, text, name, mode=mode) def _upload_input_callback(self): """ Create the callback for uploading data Returns: """ @self.app.callback(Output('uploaded-data', 'children'), [Input('upload-data', 'contents')], [State('upload-data', 'filename')]) def process_uploaded_data(contents, names): if contents is None: return None else: cleaned_data = load_csv_or_xls(contents, names) # now return the data as json return cleaned_data.to_json(orient='split') return process_uploaded_data @staticmethod def _read_df_from_json(json_data): """ Simply read read json data and output a pandas dataframe Args: json_data (str): Json string of data to be read Returns: pd.DataFrame or None if json_data was None """ if json_data is None: return json_data return pd.read_json(json_data, orient='split') def add_update_graph(self, update_function): """ Add a function that will be run for updating the graph Args: update_function: Function to run Returns: """ self.update_function = update_function