예제 #1
0
 def __init__(
         self,
         children: ChildrenType = None,
         show: PropValueType[bool] = None,
         hide_on_scroll: bool = None,  # this is the reveal prop
         elevated: bool = None,
         bordered: bool = None,
         classes: ClassesType = None,
         styles: StylesType = None,
         props: PropsType = None,
         events: EventsType = None):
     props = build_props(
         self.defaults['props'], props, {
             'reveal': hide_on_scroll,
             'elevated': elevated,
             'bordered': bordered,
             'show': show,
         })
     show = props['show']
     model = show if isinstance(show, Reactive) else Model(show)
     super().__init__(model=model,
                      children=children,
                      classes=classes,
                      styles=styles,
                      props=props,
                      events=events)
예제 #2
0
 def __init__(self,
              children: ChildrenType = None,
              menu_in_header: bool = True,
              side: str = None,
              show: Union[Model, bool] = True,
              bordered: bool = None,
              classes: ClassesType = None,
              styles: StylesType = None,
              props: PropsType = None,
              events: EventsType = None):
     """
     :menu_in_header: if used together with QLayout, it instructs to put a close menu into the header.
     """
     self.menu_in_header = menu_in_header
     children = children
     props = build_props({}, props, {
         'side': side,
         'bordered': bordered,
     })
     model = show if isinstance(show, Reactive) else Model(show)
     super().__init__(model=model,
                      children=children,
                      classes=classes,
                      styles=styles,
                      props=props,
                      events=events)
예제 #3
0
    def __init__(self,
                 renderer: PropValueType[str] = 'mpld3',
                 classes: ClassesType = None,
                 styles: StylesType = None):
        """
        :param renderer: valid values are 'png' and 'mpld3'.
        :param classes:
        :param styles:
        """
        self.renderer = Model(renderer) if isinstance(renderer,
                                                      str) else renderer
        self.renderer.add_callback(self.update)
        self._check_imports()

        self.fig = None
        self.html = {}
        self.img_base64 = Model('')
        self.last_renderer = None
        super().__init__(classes=classes, styles=styles)
        self.dependents.append(self.img_base64)
예제 #4
0
 def __init__(self,
              label: str = None,
              model: Model = None,
              appearance: str = 'checkbox',
              classes: ClassesType = None,
              styles: StylesType = None,
              props: PropsType = None,
              events: EventsType = None,
              children: List[Slot] = None):
     self.component = {
         'checkbox': 'q-checkbox',
         'toggle': 'q-toggle'
     }[appearance]
     model = model or Model(False)
     model.set_conversion(bool, bool)
     super().__init__(label=label,
                      model=model,
                      classes=classes,
                      styles=styles,
                      props=props,
                      events=events,
                      children=children)
예제 #5
0
 def __init__(self,
              label: str = None,
              model: Model = None,
              appearance: str = 'editor',
              classes: ClassesType = None,
              label_classes: ClassesType = None,
              styles: StylesType = None,
              props: PropsType = None,
              events: EventsType = None,
              children: List[Slot] = None):
     """
     :param label:
     :param model:
     :param appearance: 'editor' or 'textarea'
     :param classes:
     :param styles:
     :param props:
     :param events:
     :param children:
     """
     model = model or Model('')
     if appearance == 'editor':
         raise NotImplementedError(
             'Cannot use appearance == "editor" '
             'at the moment since it is not editable for some reason'
             'and we couldn\'t fix it.')
         self.component = 'div'
         children = [
             label,
             QEditor(model=model,
                     classes=classes,
                     styles=styles,
                     props=props,
                     events=events,
                     children=children)
         ]
         label_classes = merge_classes(self.defaults['label_classes'],
                                       label_classes)
         super().__init__(classes=label_classes, children=children)
     else:
         self.component = 'q-input'
         props = build_props({'type': 'textarea'}, props, {
             'label': label,
             'v-model': model
         })
         super().__init__(classes=classes,
                          styles=styles,
                          props=props,
                          events=events,
                          children=children)
예제 #6
0
    def __init__(
            self,
            children: ChildrenType = None,
            hide_on_scroll: bool = None,  # this is the reveal prop
            elevated: bool = None,
            bordered: bool = None,
            show: PropValueType[bool] = True,
            classes: ClassesType = None,
            styles: StylesType = None,
            props: PropsType = None):
        if 1 <= len(children) <= 2 and isinstance(children[-1], str):
            children = [QToolbar([QToolbarTitle(children)])]

        props = build_props({}, props, {
            'reveal': hide_on_scroll,
            'elevated': elevated,
            'bordered': bordered,
        })
        model = show if isinstance(show, Reactive) else Model(show)
        super().__init__(model=model,
                         children=children,
                         classes=classes,
                         styles=styles,
                         props=props)
예제 #7
0
class Plot(Component):
    """
    This component is not a quasar component.
    If interactive=False, it can be styled, it shows a png image.
    However, if interactive=True, it can *not* be styled as it shows an interactive svg,
    created by mpld3.

    "Different sizes can be created using ``plt.figure(figsize=(width,height))``
    where width and height are in inches."
    ref. https://stackoverflow.com/a/31843288/1031191

    TODO: Bokeh integration, probably via file_html
    ref. https://docs.bokeh.org/en/latest/docs/reference/embed.html#bokeh.embed.file_html
    otherwise a bokeh server needs to start in the background - which is also not impossible...
    """
    script_sources = ['mpld3-figure.js']
    defaults = {
        'render': 'png',  # other choice: 'mpld3'
    }
    renderers = {'png', 'mpld3'}

    def __init__(self,
                 renderer: PropValueType[str] = 'mpld3',
                 classes: ClassesType = None,
                 styles: StylesType = None):
        """
        :param renderer: valid values are 'png' and 'mpld3'.
        :param classes:
        :param styles:
        """
        self.renderer = Model(renderer) if isinstance(renderer,
                                                      str) else renderer
        self.renderer.add_callback(self.update)
        self._check_imports()

        self.fig = None
        self.html = {}
        self.img_base64 = Model('')
        self.last_renderer = None
        super().__init__(classes=classes, styles=styles)
        self.dependents.append(self.img_base64)

    def _check_imports(self):
        if self.renderer.value == 'mpld3':
            if not MPLD3:
                raise ImportError(
                    "Please install mpld3 package to use interactive plots")
        elif self.renderer.value == 'png':
            if not MATPLOTLIB:
                raise ImportError(
                    "Please install matplotlib package to use interactive plots"
                )
        else:
            raise AssertionError(
                'Wrong renderer. Renderer is set to "{wrong}", '
                'should be one of {should}'.format(wrong=self.renderer.value,
                                                   should=self.renderers))

    def update(self):
        self.set_figure(self.fig)

    def set_figure(self, fig: 'Figure'):
        self.fig = fig
        self._check_imports()
        if self.renderer.value == 'mpld3':
            raw_html = mpld3.fig_to_html(
                fig,
                d3_url='file://' + join(QUASAR_GUI_ASSETS_PATH, 'd3.v5.js'),
                mpld3_url='file://' +
                join(QUASAR_GUI_ASSETS_PATH, 'mpld3.v0.5.2.js'),
            )
            self.html['figId'] = str_between(raw_html, '<div id="', '"></div>')
            self.html['script'] = str_between(raw_html, "<script>",
                                              "</script>")
            self.html['style'] = str_between(raw_html, "<style>", "</style>")
        elif self.renderer.value == 'png':
            tmpfile = BytesIO()
            fig.savefig(tmpfile, format='png')
            encoded = base64.b64encode(tmpfile.getvalue()).decode('utf-8')
            self.img_base64.value = "data:image/png;base64,{}".format(encoded)
        if self.last_renderer != self.renderer.value or self.renderer.value != 'png':
            super().update()
        self.last_renderer = self.renderer.value

    @property
    def vue(self) -> dict:
        if self.renderer.value == 'mpld3':
            return self._merge_vue({
                'component': 'mpld3-figure',
                'props': {
                    'script': self.html['script'],
                    'style': self.html['style'],
                    'figId': self.html['figId']
                }
            })
        elif self.renderer.value == 'png':
            return self._merge_vue({
                'component': 'img',
                'props': {
                    'src': self.img_base64.render_as_data()
                }
            })
        else:
            return self._merge_vue({'component': 'div'})
예제 #8
0
 def _get_model(self, model):
     model = model or Model(None)
     model.set_conversion(self._to_python, self._from_python)
     return model
예제 #9
0
    def __init__(self,
                 label: str = None,
                 model: Model = None,
                 choices: Union[Renderable, list] = None,
                 multiple: bool = None,
                 appearance: str = 'auto',
                 item_props: PropsType = None,
                 label_props: PropsType = None,
                 props: PropsType = None,
                 classes: ClassesType = None,
                 styles: StylesType = None,
                 events: EventsType = None):
        """
        :param label:
        :param model:
            the value of the model depends on the choices parameter (and the item_props).
            List[str] choice format yields the displayed label as model value,
            List[dict] format yields the value of 'value' field as value, if dict has only 'label' and 'value' fields.
            Otherwise List[dict] format yields the whole dict of the selected item.
            This behavior can be overridden with item_props
            that is sent to QSelect ('select'), QOptionGroup ('radio') or QButtonToggle ('buttons') as props parameter.
        :param choices: format is ['choice 1', 'choice 2', ...] or [{'label':'Choice 1', 'value': 1}, ...].
        :param appearance:
            if multiple=False: 'auto', 'radio', 'buttons' or 'select'.
            'auto' means 'radio' for small lists, 'select' for large lists.
            if multiple=True: 'auto', 'checkboxes', 'toggles', 'select' or 'tags'
            'auto' means 'checkboxes' for small lists, 'select' for large lists, 'tags' if choices is None.
        :param item_props: The props for the items. (also if appearance=='select', props for the QSelect)
        :param classes:
        :param styles:
        :param label_props:
        :param events:
        """
        def is_lvc(choices_):
            """
            is_label_value_choice
            """
            # noinspection PyBroadException
            try:
                return set(choices_[0].keys()) == {'label', 'value'}
            except Exception:
                return False

        single_only_appearances = {'input', 'radio', 'buttons'}
        multiple_only_appearances = {'checkboxes', 'toggles', 'tags'}
        props = props or {}

        if multiple is None:
            multiple = appearance in multiple_only_appearances

        model = model or Model([] if multiple else '')
        self.dependents = [model]

        allowed_appearances = {
            'auto', 'radio', 'checkboxes', 'toggles', 'buttons', 'select',
            'tags'
        }
        if appearance not in allowed_appearances:
            raise AssertionError(
                'Wrong appearance {}. Must be one of {}'.format(
                    appearance, allowed_appearances))
        if appearance in single_only_appearances and multiple:
            raise AssertionError(
                'appearance=={} can be only used if multiple==False'.format(
                    appearance))
        elif appearance in multiple_only_appearances and not multiple:
            raise AssertionError(
                'appearance=={} can be only used if multiple==True'.format(
                    appearance))

        if appearance == 'auto':
            # auto is for providing the user a reasonable default.
            if isinstance(choices, list):
                n_choices = len(choices)
            elif isinstance(choices, Reactive):
                n_choices = len(choices.value)
            else:
                n_choices = 0
            if multiple:
                appearance = ('tags' if n_choices == 0 else
                              'checkboxes' if n_choices <= 10 else 'select')
            else:
                appearance = 'radio' if 0 < n_choices <= 5 else \
                             'input' if n_choices == 0 else \
                             'select'

        if appearance == 'input':
            self.component = 'q-input'
            children = []
        elif appearance in {'radio', 'buttons', 'checkboxes', 'toggles'}:
            if (isinstance(choices, list) and len(choices)
                    and isinstance(choices[0], str)):
                choices = [{
                    'label': choice,
                    'value': choice
                } for choice in choices]
            default_item_props = build_props(
                self.defaults['item_props'],
                {'type': 'radio'} if appearance == 'radio' else
                {'type': 'checkbox'} if appearance == 'checkboxes' else
                {'type': 'toggle'} if appearance == 'toggles' else {})
            item_props = build_props(default_item_props, item_props)
            children = [
                Div([label], props=label_props),
            ]
            if appearance in {'radio', 'checkboxes', 'toggles'}:
                del item_props['clearable']
                type_ = {
                    'radio': 'radio',
                    'checkboxes': 'checkbox',
                    'toggles': 'toggle',
                }[appearance]
                children += [
                    QOptionGroup(model=model,
                                 type=type_,
                                 options=choices,
                                 props=item_props)
                ]
            elif appearance == 'buttons':
                children += [
                    QButtonToggle(model=model,
                                  options=choices,
                                  props=item_props)
                ]
        elif appearance == 'select':
            if isinstance(choices, Reactive):
                is_label_value_choice = Computed(is_lvc, choices)
            else:
                is_label_value_choice = is_lvc(choices)
            default_props = {
                'emit-value': is_label_value_choice,
                'map-options': is_label_value_choice
            }
            default_props = build_props(default_props,
                                        self.defaults['item_props'])
            item_props = build_props(default_props, item_props, {
                'options': choices,
                'multiple': multiple,
                'use-chips': multiple
            })
            children = [QSelect(label=label, model=model, props=item_props)]
        elif appearance == 'tags':
            label_props = build_props({
                'hide-bottom-space': True,
            }, label_props)
            item_props = build_props(
                {
                    'placeholder': props.get('placeholder', ''),
                    'add-on-key': [13, ','],
                    # 'separators': [',']
                },
                item_props)
            children = [
                QField(label=label,
                       model=model,
                       props=label_props,
                       children=[
                           Slot('control',
                                [VueTagsInput(model, props=item_props)])
                       ]),
            ]
        else:
            raise NotImplementedError(
                'appearance=={} is not implemented.'.format(appearance))
        super().__init__(label=label,
                         model=model,
                         classes=classes,
                         styles=styles,
                         props=props,
                         events=events,
                         children=children)
예제 #10
0
    def __init__(self,
                 label: str = None,
                 model: Model = None,
                 appearance: str = None,
                 min: Union[int, float] = None,
                 max: Union[int, float] = None,
                 props: PropsType = None,
                 field_props: PropsType = None,
                 field_classes: ClassesType = None,
                 field_styles: StylesType = None,
                 children: List[Slot] = None,
                 classes: ClassesType = None,
                 styles: StylesType = None,
                 events: EventsType = None):
        appearance = appearance or 'input'
        self.component = {
            'input': 'q-input',
            'knob': 'q-field',
            'slider': 'q-field'
        }[appearance]
        model = model or Model(0, self._type)
        model.modifiers.add('number')
        model.set_conversion(self._type)
        special_props = {'min': min, 'max': max}

        if appearance in {'knob', 'slider'}:
            min = 0 if min is None else min
            max = 100 if max is None else max
            component_class = {'knob': QKnob, 'slider': QSlider}[appearance]

            control_props = build_props({'snap': self._type == int}, props)
            control_props = build_props(self.defaults['control_props'],
                                        control_props)
            if self._type == float:
                control_props = build_props({'step': (max - min) / 1000},
                                            control_props)
            control_props = build_props(
                {
                    'label-position':
                    'before' if appearance == 'knob' else 'top'
                }, control_props, special_props)
            control = component_class(
                model=model,
                props=control_props,
                children=children,
                classes=classes,
                styles=styles,
                events=events,
            )
            label_position = control_props['label-position']

            field_props = build_props(
                {
                    'borderless': True,
                    'stack-label': True,
                }, field_props,
                {'label': label if label_position == 'top' else None})
            label_slot = []
            if label and label_position != 'top':
                field_classes = merge_classes(self.defaults['field_classes'],
                                              field_classes or '')
                if isinstance(label, str):
                    label = Div([label], classes=field_classes)
                label_position = {
                    'left': 'before',
                    'right': 'after'
                }.get(label_position, label_position)
                label_slot = [Slot(label_position, children=[label])]
            super().__init__(model=model,
                             props=field_props,
                             children=[Slot('control', [control])] +
                             label_slot)
        else:
            props = build_props({'type': 'number'}, props, special_props)
            props = build_props(props, field_props, {'label': label})
            classes = merge_classes(classes or '', field_classes or '')
            styles = build_props(styles or {}, field_styles)
            self.component = 'q-input'
            super().__init__(model=model,
                             classes=classes,
                             styles=styles,
                             props=props,
                             events=events,
                             children=children)