Ejemplo n.º 1
0
def get_data_source(user_id, data_id, tz_str=None):

    d = get_data_page(user_id, data_id)
    d.name = 'data'

    if tz_str is not None:
        offset_s = tz_offset_seconds(tz_str)
        log.debug("offseting date with {} seconds for  {}".format(
            offset_s, tz_str))
        d = d.tshift(offset_s, freq='s')

    source = ColumnDataSource(pd.DataFrame(d))

    def on_latest_change(attr, old, new):
        log.info('on_latest_change {}  old={} new={}'.format(attr, old, new))

    source.on_change('data', on_latest_change)

    return source
Ejemplo n.º 2
0
class Plot:

    WIDTH = 800
    HEIGHT = 600

    def __init__(self, shifts, multiplicities, deviations):

        self.shifts = shifts
        self.multiplicities = multiplicities
        self.deviations = deviations

        xr = Range1d(start=220, end=-20)

        self.plot = figure(x_axis_label="ppm", x_range=xr, tools="save,reset", plot_width=self.WIDTH, plot_height=self.HEIGHT)

        self.lineSource = ColumnDataSource(data=dict(x=[0], y=[0]))
        self.plot.line('x', 'y', source=self.lineSource, line_width=2)

        # Remove grid from plot
        self.plot.xgrid.grid_line_color = None
        self.plot.ygrid.grid_line_color = None

        # Remove bokeh logo
        self.plot.toolbar.logo = None

        horizontalBoxZoomTool = HorizontalBoxZoomTool()
        self.plot.add_tools(horizontalBoxZoomTool)

        fixedZoomOutTool = FixedZoomOutTool(factor=0.4)
        self.plot.add_tools(fixedZoomOutTool)

        self.plot.extra_y_ranges['box'] = Range1d(start=0, end=0.1)
        self.selectionSource = ColumnDataSource(data=dict(left=[], right=[]), callback=CustomJS(code="""
            if ('data' in this.selected) {
                window.top.location.href = "http://localhost:8080?" + this.selected.data.query + "style=plot";
            }
        """))
        self.selectionSource.on_change('selected', lambda attr, old, new: self.delete(new['1d']['indices']))
        rect = HBar(
            left='left',
            right='right',
            y=0.5,
            height=1,
            line_alpha=0.2,
            fill_alpha=0.2,
            line_color="red",
            fill_color="red"
        )
        renderer = self.plot.add_glyph(self.selectionSource, rect)
        renderer.y_range_name = "box"

        self.labelSource = ColumnDataSource(data=dict(x=[], y=[], text=[]))
        label = Text(
            x='x',
            y='y',
            text='text',
            text_align='center',
            text_font_size="10pt"
        )
        renderer = self.plot.add_glyph(self.labelSource, label)
        renderer.y_range_name = "box"

        removeTool = CustomTapTool()
        self.plot.add_tools(removeTool)
        self.plot.toolbar.active_tap = None

        callback = CustomJS(args=dict(), code="""
            /// get BoxSelectTool dimensions from cb_data parameter of Callback
            var geometry = cb_data['geometry'];

            var shift = (geometry['x0'] + geometry['x1']) / 2;
            var deviation = Math.abs(geometry['x1'] - shift);
            var query = cb_data['query'] + "shift%5B%5D=" + shift + '&multiplicity%5B%5D=any&deviation%5B%5D=' + deviation + '&style=plot';

            window.top.location.href = "http://localhost:8080?" + query;
        """)
        selectTool = CustomBoxSelectTool(
            tool_name="Select Area",
            dimensions = "width",
            callback = callback,
            query=self.paramsToQuery()
        )
        self.plot.add_tools(selectTool)

        self.initSelect()

        self.drawButton = CustomButton(id='myButton')
        self.drawButton.on_click(self.drawPlot)

        curdoc().add_root(
            row(
                column(row(self.plot)),
                column(CustomRow(column(self.drawButton), hide=True))
            )
        )

    def paramsToQuery(self):
        query = ""
        for (shift, multiplicity, deviation) in zip(self.shifts, self.multiplicities, self.deviations):
            query += "shift%5B%5D={}&multiplicity%5B%5D={}&deviation%5B%5D={}&".format(shift, multiplicity, deviation)
        return query

    def initSelect(self):
        left, right = [], []
        labelX, labelY, labelText = [], [], []
        for (shift, multiplicity, deviation) in zip(self.shifts, self.multiplicities, self.deviations):
            left.append(shift - deviation)
            right.append(shift + deviation)

            labelX.append(shift)
            labelY.append(0.08)
            labelText.append(multiplicity)

        self.selectionSource.stream({
            'left':  left,
            'right': right
        })

        self.labelSource.stream({
            'x':    labelX,
            'y':    labelY,
            'text': labelText
        })

    def drawPlot(self, data):
        dic, _ = ng.bruker.read("../data/{}".format(data['id']))
        _, pdata = ng.bruker.read_pdata("../data/{}/pdata/1/".format(data['id']))

        udic = ng.bruker.guess_udic(dic, pdata)
        uc = ng.fileiobase.uc_from_udic(udic)
        ppmScale = uc.ppm_scale()

        self.plot.y_range = None
        self.lineSource.data = {
            'x': ppmScale,
            'y': pdata
        }

    def delete(self, ids):
        if ids:
            left = list(self.selectionSource.data['left'])
            right = list(self.selectionSource.data['right'])

            for i in ids:
                left.pop(i)
                right.pop(i)

                self.shifts.pop(i)
                self.multiplicities.pop(i)
                self.deviations.pop(i)

            self.selectionSource.data = {
                'left': left,
                'right': right
            }

            # Deselect all
            self.selectionSource.selected = {
                '0d': {'glyph': None, 'indices': []},
                '1d': {'indices': []},
                '2d': {'indices': {}},
                'data': {'query': self.paramsToQuery()}
            }

    def selectArea(self, dimensions):
        patch = {
            'left': [dimensions['x0']],
            'right': [dimensions['x1']]
        }
        self.selectionSource.stream(patch)
Ejemplo n.º 3
0
class RDFToGeoJSON:
    def __init__(self, layout):
        self.__layout = layout
        self.__selected = []
        self.__file_list = self.__get_eurostats()

        self.__rdf_table_source = ColumnDataSource(
            dict(id=[f['id'] for f in self.__file_list]))
        self.__rdf_table_source.on_change('selected', self.__on_select)
        rdf_table_columns = [TableColumn(field='id', title='RDF ID')]
        self.rdf_table = DataTable(source=self.__rdf_table_source,
                                   columns=rdf_table_columns,
                                   width=300,
                                   height=500,
                                   selectable=True)

        geojson_data = {'id': [], 'lvl': []}
        for file in self.__file_list:
            if file['geojson']['nuts1']['exists']:
                geojson_data['id'].append(file['id'])
                geojson_data['lvl'].append(1)

            if file['geojson']['nuts2']['exists']:
                geojson_data['id'].append(file['id'])
                geojson_data['lvl'].append(2)

            if file['geojson']['nuts3']['exists']:
                geojson_data['id'].append(file['id'])
                geojson_data['lvl'].append(3)
        self.__geojson_table_source = ColumnDataSource(geojson_data)
        geojson_table_columns = [
            TableColumn(field='lvl', title='NUTS Level'),
            TableColumn(field='id', title='ID')
        ]
        self.geojson_table = DataTable(source=self.__geojson_table_source,
                                       columns=geojson_table_columns,
                                       width=300,
                                       height=500,
                                       selectable=True)
        convert_button = Button(label="Convert to GeoJSON",
                                button_type="success")
        convert_button.on_click(self.transform)
        # todo: creates bug - empty table
        #self.__layout.children[1] = column(widgetbox(self.rdf_table), convert_button)
        self.__layout.children[2] = column(self.geojson_table)

    def __on_select(self, attr, old, new):
        self.__selected = [
            self.__file_list[index] for index in new['1d']['indices']
        ]

    def transform(self):
        print("converting")
        for f in self.__selected:
            print(".")
            f['results'] = self.__extract_observations(f['rdf'])

        print("writing")
        self.__write_geojson(self.__selected)
        print("done converting")

        self.__file_list = self.__get_eurostats()
        geojson_data = {'id': [], 'lvl': []}
        for file in self.__file_list:
            if file['geojson']['nuts1']['exists']:
                geojson_data['id'].append(file['id'])
                geojson_data['lvl'].append(1)

            if file['geojson']['nuts2']['exists']:
                geojson_data['id'].append(file['id'])
                geojson_data['lvl'].append(2)

            if file['geojson']['nuts3']['exists']:
                geojson_data['id'].append(file['id'])
                geojson_data['lvl'].append(3)
        self.__geojson_table_source = ColumnDataSource(geojson_data)
        geojson_table_columns = [
            TableColumn(field='lvl', title='NUTS Level'),
            TableColumn(field='id', title='ID')
        ]
        self.geojson_table = DataTable(source=self.__geojson_table_source,
                                       columns=geojson_table_columns,
                                       width=300,
                                       height=500,
                                       selectable=True)
        self.__layout.children[2] = column(self.geojson_table)

    def __get_eurostats(self):
        """
        This function generates the file names for every RDF in the "data/rdf/eurostats" subdirectory.

        :return: A list of dictionaries containing the id and file names of the RDFs found.
        """
        rdf_path_prefix = "data/rdf/eurostats/"
        geojson_path_prefix = "data/geojson/eurostats/"
        observation_list = []

        nuts_files = [
            [
                str(os.path.basename(file).split('.')[0])
                for file in os.listdir(geojson_path_prefix + "nuts_1/")
            ],
            [
                str(os.path.basename(file).split('.')[0])
                for file in os.listdir(geojson_path_prefix + "nuts_2/")
            ],
            [
                str(os.path.basename(file).split('.')[0])
                for file in os.listdir(geojson_path_prefix + "nuts_3/")
            ]
        ]

        for file in os.listdir(rdf_path_prefix):
            observation = {}
            observation_name = str(os.path.basename(file).split('.')[0])
            observation['id'] = observation_name
            observation['rdf'] = rdf_path_prefix + file
            observation['geojson'] = {
                'nuts1': {
                    'path': geojson_path_prefix + "nuts_1/" +
                    observation_name + ".geojson",
                    'exists': observation_name in nuts_files[0]
                },
                'nuts2': {
                    'path': geojson_path_prefix + "nuts_2/" +
                    observation_name + ".geojson",
                    'exists': observation_name in nuts_files[1]
                },
                'nuts3': {
                    'path': geojson_path_prefix + "nuts_3/" +
                    observation_name + ".geojson",
                    'exists': observation_name in nuts_files[2]
                },
            }
            observation_list.append(observation)
        return observation_list

    def __extract_observations(self, file):
        g = rdf.Graph()
        g.parse(file, format="xml")

        return g.query("""
            prefix obs: <http://purl.org/linked-data/sdmx/2009/measure#>
            prefix prop: <http://eurostat.linked-statistics.org/property#>
            prefix qb: <http://purl.org/linked-data/cube#>
            prefix sdmx-dimension: <http://purl.org/linked-data/sdmx/2009/dimension#>

            select distinct ?designation ?time ?value ?unit
            where {
                ?observation a qb:Observation.
                ?observation prop:geo ?designation.
                ?observation prop:unit ?unit.
                ?observation sdmx-dimension:timePeriod ?time.
                ?observation obs:obsValue ?value.
            }
        """)

    def __write_geojson(self, file_list):

        with open(
                'data/geojson/eurostats/nuts_rg_60M_2013_lvl_3.geojson') as f:
            nuts3 = json.load(f)
        with open(
                'data/geojson/eurostats/nuts_rg_60M_2013_lvl_2.geojson') as f:
            nuts2 = json.load(f)
        with open(
                'data/geojson/eurostats/nuts_rg_60M_2013_lvl_1.geojson') as f:
            nuts1 = json.load(f)

        nuts = [nuts1, nuts2, nuts3]

        for file in file_list:
            geojson = copy.deepcopy(nuts)
            self.__process_file(file, geojson)

            for lvl in range(0, len(geojson)):
                with open(file['geojson']['nuts{}'.format(lvl + 1)]['path'],
                          'w') as outfile:
                    json.dump(geojson[lvl], fp=outfile, indent=4)

    def __process_file(self, file, nuts):
        for row in file['results']:
            # recover uncluttered information from the sparql result
            geo = row[0].split('#')[1]
            time = row[1]
            value = row[2]
            unit = row[3].split('#')[1]

            # search for the NUTS_ID (geo) in the NUTS level 1 to 3
            index = -1
            nuts_lvl = -1
            found = False
            while not found:
                index += 1
                done = []
                # prepare break condition
                for lvl in range(0, len(nuts)):
                    done.append(False)

                # check if the ID matches in any of the NUTS levels
                for lvl in range(0, len(nuts)):
                    if index < len(nuts[lvl]['features']):
                        if nuts[lvl]['features'][index]['properties'][
                                'NUTS_ID'] == geo:
                            nuts_lvl = lvl
                            found = True
                            break
                    else:
                        done[lvl] = True
                if all(done):
                    break

            if nuts_lvl != -1:
                observation = {'period': time, 'unit': unit, 'value': value}

                # check if any of the nested elements in the JSON already exist
                if 'OBSERVATIONS' in nuts[nuts_lvl]['features'][index][
                        'properties']:
                    if file['id'] in nuts[nuts_lvl]['features'][index][
                            'properties']['OBSERVATIONS']:
                        duplicate = False
                        for observations in nuts[nuts_lvl]['features'][index][
                                'properties']['OBSERVATIONS'][file['id']]:
                            if observations['period'] == observation['period']:
                                duplicate = True
                                break
                        if not duplicate:
                            nuts[nuts_lvl]['features'][index]['properties'][
                                'OBSERVATIONS'][file['id']].append(observation)
                    else:
                        nuts[nuts_lvl]['features'][index]['properties'][
                            'OBSERVATIONS'][file['id']] = [observation]
                else:
                    nuts[nuts_lvl]['features'][index]['properties'][
                        'OBSERVATIONS'] = {
                            file['id']: [observation]
                        }
Ejemplo n.º 4
0
from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.plotting import figure
from bokeh.models.callbacks import CustomJS
from bokeh.models.sources import ColumnDataSource
from bokeh.models.widgets import Slider

# this is the real callback that we want to happen on slider mouseup
def cb(attr, old, new):
    print("UPDATE", source.data['value'])
    #p.x_range=range(0, int(source.data['value']))

# This data source is just used to communicate / trigger the real callback
source = ColumnDataSource(data=dict(value=[]))
source.on_change('data', cb)

# a figure, just for example
p = figure(x_range=(0,1), y_range=(0,1))

# add a slider with a CustomJS callback and a mouseup policy to update the source
slider = Slider(start=1, end=10, value=1, step=0.1, callback_policy='mouseup')
slider.callback = CustomJS(args=dict(source=source), code="""
    source.data = { value: [cb_obj.value] }
""")

curdoc().add_root(column(slider, p))

# make sure to add the source explicitly
curdoc().add_root(source)