From 42e61e7ce5b39c1a784b5f029f3661a95f5a4955 2019-05-31 16:57:44 From: Alexis Jeandet Date: 2019-05-31 16:57:44 Subject: [PATCH] Mostly working Spectrograms Signed-off-by: Alexis Jeandet --- diff --git a/core b/core index 698d7cf..483146a 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 698d7cfa01b05427c2377ce2799f1290b9eab2ca +Subproject commit 483146a07a5ffeec8f0a2d61459e94d95e851572 diff --git a/gui/src/Visualization/VisualizationGraphHelper.cpp b/gui/src/Visualization/VisualizationGraphHelper.cpp index 2039998..1790733 100644 --- a/gui/src/Visualization/VisualizationGraphHelper.cpp +++ b/gui/src/Visualization/VisualizationGraphHelper.cpp @@ -3,9 +3,12 @@ #include #include +#include #include +#include #include +#include Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper") @@ -321,31 +324,14 @@ struct PlottablesUpdatersetRange(QCPRange { min, max }); - // } - double minValue = 0., maxValue = 0.; - if (auto serie = dynamic_cast(&dataSeries)) - { - auto& yAxis = serie->axis(1); - if (yAxis.size()) - { - minValue = *std::min_element(std::cbegin(yAxis), std::cend(yAxis)); - maxValue = *std::max_element(std::cbegin(yAxis), std::cend(yAxis)); - } - } + auto [minValue, maxValue] = dataSeries.axis_range(1); + std::cout << "min=" << minValue << " max=" << maxValue << std::endl; plot.yAxis->setRange(QCPRange { minValue, maxValue }); } static void updatePlottables( T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) { - // TODO if (plottables.empty()) { qCDebug(LOG_VisualizationGraphHelper()) @@ -353,80 +339,82 @@ struct PlottablesUpdater(plottables.at(0)); Q_ASSERT(colormap != nullptr); + auto plot = colormap->parentPlot(); + auto [minValue, maxValue] = dataSeries.axis_range(1); + plot->yAxis->setRange(QCPRange { minValue, maxValue }); if (auto serie = dynamic_cast(&dataSeries)) { - colormap->data()->setSize(serie->shape()[0], serie->shape()[1]); - if (serie->size(0)) + if (serie->size(0) > 2) { + const auto& xAxis = serie->axis(0); + auto yAxis = serie->axis(1); // copy for in place reverse order + std::reverse(std::begin(yAxis), std::end(yAxis)); + auto xAxisProperties = TimeSeriesUtils::axis_analysis(xAxis); + auto yAxisProperties = TimeSeriesUtils::axis_analysis(yAxis); + + int colormap_h_size = std::min(32000, + static_cast(xAxisProperties.range / xAxisProperties.max_resolution)); + auto colormap_v_size + = static_cast(yAxisProperties.range / yAxisProperties.max_resolution); + + colormap->data()->setSize(colormap_h_size, colormap_v_size); colormap->data()->setRange( QCPRange { serie->begin()->t(), (serie->end() - 1)->t() }, - QCPRange { 1., 1000. }); - for (int x_index = 0; x_index < serie->shape()[0]; x_index++) + { minValue, maxValue }); + + std::vector> y_access_pattern; + for (int y_index = 0, cel_index = 0; y_index < colormap_v_size; y_index++) { - auto pixline = (*serie)[x_index]; - for (int y_index = 0; y_index < serie->shape()[1]; y_index++) + double current_y = pow( + 10., (yAxisProperties.max_resolution * y_index) + std::log10(minValue)); + if (current_y > yAxis[cel_index]) + cel_index++; + y_access_pattern.push_back({ y_index, yAxis.size() - 1 - cel_index }); + } + + auto line = serie->begin(); + double current_time = xAxis[0]; + int x_index = 0; + + while (x_index < colormap_h_size) + { + if (current_time > (line + 1)->t()) { - auto value = pixline[y_index]; - colormap->data()->setCell(x_index, y_index, value); - if (std::isnan(value)) + line++; + } + if ((current_time - xAxis[0]) + > (x_index * xAxisProperties.range / colormap_h_size)) + { + x_index++; + } + if (line->t() <= (current_time + xAxisProperties.max_resolution)) + { + std::for_each(std::cbegin(y_access_pattern), std::cend(y_access_pattern), + [&colormap, &line, x_index](const auto& acc) { + colormap->data()->setCell(x_index, acc.first, (*line)[acc.second]); + }); + } + else + { + for (int y_index = 0; y_index < colormap_v_size; y_index++) { - colormap->data()->setAlpha(x_index, y_index, 0); + colormap->data()->setCell(x_index, y_index, std::nan("")); } } + current_time += xAxisProperties.max_resolution; } } - } - // dataSeries.lockRead(); - - // // Processing spectrogram data for display in QCustomPlot - // auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd); - - // // Computes logarithmic y-axis resolution for the spectrogram - // auto yData = its.first->y(); - // auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true); - - // // Generates mesh for colormap - // auto mesh = DataSeriesUtils::regularMesh(its.first, its.second, - // DataSeriesUtils::Resolution { dataSeries.xResolution() }, yResolution); - - // dataSeries.unlock(); - - // colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY); - // if (!mesh.isEmpty()) - // { - // colormap->data()->setRange(QCPRange { mesh.m_XMin, mesh.xMax() }, - // // y-axis range is converted to linear values - // QCPRange { std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax()) }); - - // // Sets values - // auto index = 0; - // for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, - // ++index) - // { - // auto xIndex = index % mesh.m_NbX; - // auto yIndex = index / mesh.m_NbX; - - // colormap->data()->setCell(xIndex, yIndex, *it); - - // // Makes the NaN values to be transparent in the colormap - // if (std::isnan(*it)) - // { - // colormap->data()->setAlpha(xIndex, yIndex, 0); - // } - // } - // } - - // // Rescales axes - auto plot = colormap->parentPlot(); - setPlotYAxisRange(dataSeries, {}, *plot); - if (rescaleAxes) - { - plot->rescaleAxes(); + + if (rescaleAxes) + { + plot->rescaleAxes(); + } } } }; @@ -444,7 +432,8 @@ struct IPlottablesHelper }; /** - * Default implementation of IPlottablesHelper, which takes data series to create/update plottables + * Default implementation of IPlottablesHelper, which takes data series to create/update + * plottables * @tparam T the data series' type */ template diff --git a/plugins/python_providers/resources/amda.py b/plugins/python_providers/resources/amda.py index 5f83387..1f85f70 100644 --- a/plugins/python_providers/resources/amda.py +++ b/plugins/python_providers/resources/amda.py @@ -10,9 +10,42 @@ from spwc.amda import AMDA amda = AMDA() -def get_sample(metadata,start,stop): - ts_type = pysciqlopcore.ScalarTimeSerie - default_ctor_args = 1 +def amda_make_scalar(var=None): + if var is None: + return pysciqlopcore.ScalarTimeSerie(1) + else: + return pysciqlopcore.ScalarTimeSerie(var.time,var.data) + +def amda_make_vector(var=None): + if var is None: + return pysciqlopcore.VectorTimeSerie(1) + else: + return pysciqlopcore.VectorTimeSerie(var.time,var.data) + +def amda_make_multi_comp(var=None): + if var is None: + return pysciqlopcore.MultiComponentTimeSerie((0,2)) + else: + return pysciqlopcore.MultiComponentTimeSerie(var.time,var.data) + +def amda_make_spectro(var=None): + if var is None: + return pysciqlopcore.SpectrogramTimeSerie((0,2)) + else: + if "PARAMETER_TABLE_MIN_VALUES[1]" in var.meta: + min_v = np.array([ float(v) for v in var.meta["PARAMETER_TABLE_MIN_VALUES[1]"].split(',') ]) + max_v = np.array([ float(v) for v in var.meta["PARAMETER_TABLE_MAX_VALUES[1]"].split(',') ]) + y = (max_v + min_v)/2. + elif "PARAMETER_TABLE_MIN_VALUES[0]" in var.meta: + min_v = np.array([ float(v) for v in var.meta["PARAMETER_TABLE_MIN_VALUES[0]"].split(',') ]) + max_v = np.array([ float(v) for v in var.meta["PARAMETER_TABLE_MAX_VALUES[0]"].split(',') ]) + y = (max_v + min_v)/2. + else: + y = np.logspace(1,3,var.data.shape[1])[::-1] + return pysciqlopcore.SpectrogramTimeSerie(var.time,y,var.data) + +def amda_get_sample(metadata,start,stop): + ts_type = amda_make_scalar try: param_id = None for key,value in metadata: @@ -20,18 +53,19 @@ def get_sample(metadata,start,stop): param_id = value elif key == 'type': if value == 'vector': - ts_type = pysciqlopcore.VectorTimeSerie + ts_type = amda_make_vector elif value == 'multicomponent': - ts_type = pysciqlopcore.MultiComponentTimeSerie - default_ctor_args = (0,2) + ts_type = amda_make_multi_comp + elif value == 'spectrogram': + ts_type = amda_make_spectro tstart=datetime.fromtimestamp(start, tz=timezone.utc) tend=datetime.fromtimestamp(stop, tz=timezone.utc) var = amda.get_parameter(start_time=tstart, stop_time=tend, parameter_id=param_id, method="REST") - return ts_type(var.time,var.data) + return ts_type(var) except Exception as e: print(traceback.format_exc()) print("Error in amda.py ",str(e)) - return ts_type(default_ctor_args) + return ts_type() if len(amda.component) is 0: @@ -49,17 +83,16 @@ for key,parameter in parameters.items(): components = [component['name'] for component in parameter.get('components',[])] metadata = [ (key,item) for key,item in parameter.items() if key is not 'components' ] n_components = parameter.get('size',0) - if n_components is '3': + if n_components == '3': metadata.append(("type","vector")) + elif parameter.get('display_type','')=="spectrogram": + metadata.append(("type","spectrogram")) elif n_components !=0: - if parameter.get('display_type','')=="spectrogram": - metadata.append(("type","spectrogram")) - else: - metadata.append(("type","multicomponent")) + metadata.append(("type","multicomponent")) else: metadata.append(("type","scalar")) products.append( (path, components, metadata)) -PythonProviders.register_product(products, get_sample) +PythonProviders.register_product(products, amda_get_sample) diff --git a/plugins/python_providers/resources/test.py b/plugins/python_providers/resources/test.py index 8bb1bf6..53a0c55 100644 --- a/plugins/python_providers/resources/test.py +++ b/plugins/python_providers/resources/test.py @@ -64,7 +64,7 @@ def get_data(metadata,start,stop): ts_type = pysciqlopcore.MultiComponentTimeSerie default_ctor_args = (0,2) elif value == 'spectrogram': - ts_type = lambda t,values: pysciqlopcore.SpectrogramTimeSerie(t,np.logspace(1,3,32),values) + ts_type = lambda t,values: pysciqlopcore.SpectrogramTimeSerie(t,np.logspace(1,3,32)[::-1],values) default_ctor_args = (0,2) if key == 'cache' and value == 'true': use_cache = True