Exemple #1
0
    def _collect_lockdown_tooltip_layers(self, df, layers, base, cursor):
        # Since it's difficult to support a condition of type 'mouseover OR checkbox'
        # (due to broken alt.condition not two non-constants for if_true and if_false
        # and due to completely broken checkboxes in Vega Lite), we'll add two layers
        # to accompish the same thing. The first layer will be active when 'mouseover
        # AND NOT checkbox' and the second layer will be active when just 'checkbox'.
        def _make_base(tooltip):
            ret = base.mark_text(
                align='left',
                dx=15,
                dy=0,
                font=self._font,
                fontWeight=600,
            ).encode(
                x=self._get_x(),
                y=self._get_y(),
                text=tooltip,
                color=alt.value('black')
            ).transform_calculate(
                # AGP        lockdown_tooltip_text=f'datum.{self._detailby} + " " + datum.lockdown_type+ " " +"("+ datum.lockdown_date + ")"'
                # lockdown_tooltip_text=f'datum.lockdown_type+ " " +"("+ datum.lockdown_date + ")"'
                lockdown_tooltip_text=
                'datum.lockdown_type + " " + "(" + datum.lockdown_date + ")"')
            if 'event_index' in df.columns:
                ret = ret.transform_filter('datum.event_index == 0')
            return ret

        lockdown_tooltip_text = 'lockdown_tooltip_text'
        empty_if_checkbox = 'empty_if_checkbox'
        hover_layer = _make_base(
            alt.condition(cursor, f'{empty_if_checkbox}:N', alt.value(' ')))
        # Checkbox to print event details
        event_select = None
        calculate_kwargs = {
            empty_if_checkbox: f'datum.{lockdown_tooltip_text}'
        }
        if self.get('event_select', False):
            event_checkbox = alt.binding_checkbox(
                name='Show all intervention details ')
            event_select = alt.selection_single(bind=event_checkbox,
                                                name='events',
                                                init={'values': False})
            calculate_kwargs[
                empty_if_checkbox] = f'{self._show_events()} ? " " : datum.{lockdown_tooltip_text}'
            hover_layer = hover_layer.add_selection(event_select)
        if 'Coverage' in df.columns:
            # TODO: put this in a better place
            # I'm just putting it here so that it appears earlier than the "show all events" checkbox for now
            regional_checkbox = alt.binding_checkbox(
                name='Hide regional intervention icons ')
            regional_select = alt.selection_single(bind=regional_checkbox,
                                                   name='hide_regional_icons',
                                                   init={'values': False})
            hover_layer = hover_layer.add_selection(regional_select)
        hover_layer = hover_layer.transform_calculate(**calculate_kwargs)
        layers['hover_layer'] = hover_layer
        if event_select is not None:
            layers['event_checkbox_layer'] = _make_base(
                f'{lockdown_tooltip_text}:N').transform_filter(
                    self._show_events())
filter_genres = base.add_selection(genre_select).transform_filter(
    genre_select).properties(title="Dropdown Filtering")

#color changing marks
rating_radio = alt.binding_radio(options=ratings)

rating_select = alt.selection_single(fields=['MPAA_Rating'],
                                     bind=rating_radio,
                                     name="Rating")
rating_color_condition = alt.condition(rating_select,
                                       alt.Color('MPAA_Rating:N', legend=None),
                                       alt.value('lightgray'))

highlight_ratings = base.add_selection(rating_select).encode(
    color=rating_color_condition).properties(title="Radio Button Highlighting")

# Boolean selection for format changes
input_checkbox = alt.binding_checkbox()
checkbox_selection = alt.selection_single(bind=input_checkbox,
                                          name="Big Budget Films")

size_checkbox_condition = alt.condition(
    checkbox_selection, alt.SizeValue(25),
    alt.Size('Hundred_Million_Production:Q'))

budget_sizing = base.add_selection(checkbox_selection).encode(
    size=size_checkbox_condition).properties(title="Checkbox Formatting")

(filter_year | filter_genres) & (highlight_ratings | budget_sizing).show()
Exemple #3
0
r = pdk.Deck(
    layers=[layer],
    initial_view_state=view_state,
    mapbox_key=
    "pk.eyJ1IjoieXVhbnl1YTQiLCJhIjoiY2tnaDN2ODNuMHFjdTM3cXQ1cjZ4ZjZ1bSJ9.7Rc5ptwp4PBKWFHC8iwPWg",
    map_style="mapbox://styles/mapbox/light-v9")
st.sidebar.write("## NYC map for reference")
st.sidebar.write(
    "If you find a location on the main plots that interest you, you can use the map below to dive in for more details."
)
st.sidebar.write(r)

with st.spinner(text="Loading..."):
    selector_pick = alt.selection_interval(empty='none', encodings=['x', 'y'])
    selector_drop = alt.selection_interval(empty='none', encodings=['x', 'y'])
    binding_weekend = alt.binding_checkbox(name="weekend")
    weekend = alt.selection_single(name=None,
                                   fields=['weekend'],
                                   bind=binding_weekend,
                                   init={'weekend': True})
    binding_weekday = alt.binding_checkbox(name="weekday")
    weekday = alt.selection_single(name=None,
                                   fields=['weekday'],
                                   bind=binding_weekday,
                                   init={'weekday': True})

    taxi_map_dropoff_chart = alt.Chart(
        taxi_map_pickup_dropoff,
        title="Taxi Dropoffs (selectable)").mark_square(size=5).encode(
            alt.Y('dropoff_latitude',
                  title='dropoff latitude',
df = df_raw
for variable in df_raw['variable'].unique():
    this_df = df_raw[df_raw['variable'] == variable].copy()
    this_df['value'] = list(np.diff(this_df['value']))+[0]
    this_df['operation'] = ['diff']*n_row
    df_raw = df_raw.append(this_df)
    this_df['value'] = np.cumsum(this_df['value'])
    this_df['operation'] = ['cumulative']*n_row
    df_raw = df_raw.append(this_df)

line = alt.Chart(df).mark_line().encode(
    x='sample',
    y=alt.Y('value')
).properties(title='time series plots').interactive()

op_selections = [alt.selection_single(bind=alt.binding_checkbox(),
                                      name=x, fields=['operation'])
                 for x in df_raw['operation'].unique()]
for op_selection in op_selections[::-1]:
    line = line.add_selection(op_selection).transform_filter(op_selection)

dropdown_box = alt.binding_select(options=dataset_names)
dropdown_selection = alt.selection_single(bind=dropdown_box, name='dataset', fields=['variable'])

line = line.add_selection(dropdown_selection).transform_filter(dropdown_selection)

alt.vconcat(line,
            data=df,
            title="Altair Example of time series"
            ).save('altair_example.html')
Exemple #5
0
    def compile(self, df):
        self.validate(df)
        self[self.TRANSIENT] = DotDict()
        try:
            self._populate_transient_props(df)
            base = alt.Chart(df, width=self._width, height=self._height)
            layers = {}

            extra_click_selection_kwargs = {}
            if not self._manual_legend:
                dropdown_options = [self.EMPTY_SELECTION]
                dropdown_name = " "
                if self.get('click_selection', False):
                    dropdown_options.extend(list(df[self._detailby].unique()))
                    dropdown_name = f'Select {self.get("readable_group_name", self.get("detailby", "group"))}: '
                dropdown = alt.binding_select(options=dropdown_options,
                                              name=dropdown_name)
                extra_click_selection_kwargs['bind'] = dropdown
            click_init = self.get('click_selection_init', None)
            if click_init is not None:
                click_init = {self._detailby: click_init}
                if self._manual_legend:
                    click_init = [click_init]
                extra_click_selection_kwargs['init'] = click_init
            if self._manual_legend:
                selection_type = getattr(alt, 'selection_multi')
            else:
                selection_type = getattr(alt, 'selection_single')
            click_selection = selection_type(fields=[self._detailby],
                                             on='click',
                                             name=self.click,
                                             empty='all',
                                             clear='dblclick',
                                             **extra_click_selection_kwargs)

            # put a fake layer in first with no click selection
            # since it has X and Y, it will help chart.interactive() to find x and y fields to bind to,
            # allowing us to pan up and down and zoom over both axes instead of just 1.
            layers['fake_interactive'] = base.mark_line().encode(
                x=self._get_x(), y=self._get_y()).transform_filter('false')

            # The first layer with a specified color channel is used to generate the legend.
            # as such, we need to make sure the marks in the first layer w/ specified color channel are not translucent,
            # otherwise we'll get a blank legend.
            # We put a fake layer in here before we add any other layers w/ color channel specified, and we
            # furthermore add the legend selection to it b/c it also seems like a multi-selection bound to the
            # legend needs to be added to the layer that generates the legend.
            if not self._manual_legend:
                legend_selection = alt.selection_multi(
                    fields=[self._colorby],
                    on='click',
                    name=self.legend,
                    empty='all',
                    bind='legend',
                    clear='dblclick',
                )
                layers['legend'] = base.mark_point(size=0).encode(
                    x=self._get_x(), y=self._get_y(),
                    color=self._alt_color).add_selection(legend_selection)

            extra_mouseover_kwargs = {}
            if self._manual_legend:
                # don't set clear for selection_single click --
                # it will disappear when mouse is over points
                extra_mouseover_kwargs['clear'] = 'mouseout'
            cursor = alt.selection_single(name=self.cursor,
                                          nearest=True,
                                          on='mouseover',
                                          fields=['x'],
                                          empty='none',
                                          **extra_mouseover_kwargs)

            # Next goes the mouseover interaction layer (needs to happen before click selection layer,
            # but only if click selection is "single" as opposed to "multi").
            # We are binding the hover interaction to the 'x' column in the dataframe, so any other layers
            # that make use of the hover interaction need to use this column for their x encoding in Altair.
            # This means that things like lockdown tooltips need to use 'x' and then apply a filter to filter
            # out non-lockdown days if they want work with the mouseover interaction.
            if not self._manual_legend:
                layers['selectors'] = base.mark_point(size=0).encode(
                    x=self._get_x()).add_selection(cursor)

            # Put a fake layer in first to attach the click selection to. We use a fake layer for a few reasons.
            # 1. It's not used as a base layer, so we won't get errors
            #    about the spec having the selection added multiple times.
            # 2. We need a layer that has nice fat points that are easy to click for adding the click_selection to.
            #    Since the layer has fat points, however, the points need to be translucent, and since they
            #    need to be translucent, this layer cannot be the first layer that specifies color channel
            #    and similarly cannot be the layer with the legend_selection added on (in the case of using
            #    the built-in legend from Altair, which is only true if `use_manual_legend` is False).
            layers['fake_points'] = self._make_point_layer(
                base, point_size=400,
                is_fake=True).add_selection(click_selection)

            # Mouseover interaction goes after click interaction layer for manual legend, since manual legend
            # uses `selection_multi` for the click layer which does not stick if going later (and does not appear
            # at all if it goes first).
            if self._manual_legend:
                layers['selectors'] = self._make_point_layer(
                    base, point_size=0, is_fake=True).add_selection(cursor)

            # now the meaty layers with actual content
            layers['lines'] = self._make_line_layer(base)
            layers['points'] = self._make_point_layer(
                base,
                point_size=self.get('point_size', self.DEFAULT_POINT_SIZE),
                is_fake=False)

            self._collect_tooltip_layers(df, layers, base, cursor)

            if self.get('lockdown_extrapolation', True):
                trend_checkbox = alt.binding_checkbox(
                    name='Show trend lines for selected ')
                trend_select = alt.selection_single(bind=trend_checkbox,
                                                    name='trends',
                                                    init={'values': False})

                layers[
                    'model_lines'] = self._make_lockdown_extrapolation_layer(
                        base)
                layers[
                    'model_tooltip'] = self._make_extrapolation_tooltip_layer(
                        layers['model_lines'], cursor, trend_select)

            if self.get('emoji_legend', False):
                self._collect_emoji_legend_layers(df, layers)

            layered = alt.layer(*layers.values())
            layered = self._maybe_add_facet(layered)
            if self.get('interactive', False):
                layered = layered.interactive(bind_x=True, bind_y=True)
            if self.get('title', False):
                layered.title = self.get('title')
            final_chart = layered
            if self._manual_legend:
                final_chart = alt.hconcat(final_chart,
                                          self._make_manual_legend(
                                              df, click_selection),
                                          spacing=0)
            final_chart = final_chart.configure(background=self.get(
                'background', self.DEFAULT_BACKGROUND_COLOR))
            final_chart = final_chart.configure_axis(titleFontSize=self.get(
                'axes_title_fontsize', self.DEFAULT_AXES_TITLE_FONTSIZE), )
            final_chart = final_chart.configure_title(font=self._font)
            if not self._manual_legend:
                final_chart = final_chart.configure_legend(
                    symbolType='diamond')
            alt.themes.register('customFont', _fontSettings(self._font))
            alt.themes.enable('customFont')
            return final_chart
        finally:
            del self[self.TRANSIENT]
Exemple #6
0
    def compile(self, df):
        self.validate(df)
        self[self.TRANSIENT] = DotDict()
        try:
            self._populate_transient_props(df)
            base = alt.Chart(df,
                             width=self.get('width', self.DEFAULT_WIDTH),
                             height=self.get('height', self.DEFAULT_HEIGHT))
            layers = {}

            dropdown_options = [self.EMPTY_SELECTION]
            dropdown_name = " "
            if self.get('click_selection', False):
                dropdown_options.extend(list(df[self._detailby].unique()))
                dropdown_name = f'Select {self.get("readable_group_name", self.detailby)}: '
            dropdown = alt.binding_select(options=dropdown_options,
                                          name=dropdown_name)
            extra_click_selection_kwargs = {}
            click_init = self.get('click_selection_init', None)
            if click_init is not None:
                extra_click_selection_kwargs['init'] = {
                    self._detailby: click_init
                }
            click_selection = alt.selection_single(
                fields=[self._detailby],
                on='click',
                name=self.click,
                empty='all',
                bind=dropdown,
                clear='dblclick',
                **extra_click_selection_kwargs)

            legend_selection = alt.selection_multi(
                fields=[self._colorby],
                on='click',
                name=self.legend,
                empty='all',
                bind='legend',
                clear='dblclick',
            )

            # put a fake layer in first with no click selection
            # since it has X and Y, it will help chart.interactive() to find x and y fields to bind to,
            # allowing us to pan up and down and zoom over both axes instead of just 1.
            layers['fake_interactive'] = base.mark_line().encode(
                x=self._get_x(), y=self._get_y()).transform_filter('false')

            # next goes the tooltip selector layer (needs to happen before click selection layer)
            cursor, selectors = self._make_cursor_selection(base)
            layers['selectors'] = selectors

            # The first layer with a specified color channel is used to generate the legend.
            # as such, we need to make sure the marks in the first layer w/ specified color channel are not translucent,
            # otherwise we'll get a blank legend.
            # We put a fake layer in here before we add any other layers w/ color channel specified, and we
            # furthermore add the legend selection to it b/c it also seems like a multi-selection bound to the
            # legend needs to be added to the layer that generates the legend.
            layers['legend'] = base.mark_point(size=0).encode(
                x=self._get_x(), y=self._get_y(),
                color=self._alt_color).add_selection(legend_selection)

            # Put a fake layer in first to attach the click selection to. We use a fake layer for this for a few reasons.
            # 1. It's not used as a base layer, so we won't get errors
            #    about the spec having the selection added multiple times.
            # 2. We need a layer that has nice fat points that are easy to click for adding the click_selection to.
            #    Since the layer has fat points, however, the points need to be translucent, and since they
            #    need to be translucent, this layer cannot be the first layer that specifies color channel
            #    and similarly cannot be the layer with the legend_selection added on.
            layers['fake_points'] = self._make_point_layer(
                base, point_size=400,
                is_fake=True).add_selection(click_selection)

            # now the meaty layers with actual content
            layers['lines'] = self._make_line_layer(base)
            layers['points'] = self._make_point_layer(
                base,
                point_size=self.get('point_size', self.DEFAULT_POINT_SIZE),
                is_fake=False)

            self._collect_tooltip_layers(layers, base, cursor)

            if self.get('lockdown_extrapolation', False):
                trend_checkbox = alt.binding_checkbox(
                    name='Show trend lines for selected ')
                trend_select = alt.selection_single(bind=trend_checkbox,
                                                    name='trends',
                                                    init={'values': True})
                layers[
                    'model_lines'] = self._make_lockdown_extrapolation_layer(
                        base, trend_select)
                layers[
                    'model_tooltip'] = self._make_extrapolation_tooltip_layer(
                        layers['model_lines'], cursor, trend_select)

            layered = alt.layer(*layers.values())
            layered = self._maybe_add_facet(layered)
            if self.get('interactive', False):
                layered = layered.interactive(bind_x=True, bind_y=True)
            if self.get('title', False):
                layered.title = self.get('title')
            layered = layered.configure(background=self.get(
                'background', self.DEFAULT_BACKGROUND_COLOR))
            layered = layered.configure_axis(titleFontSize=self.get(
                'axes_title_fontsize', self.DEFAULT_AXES_TITLE_FONTSIZE))
            layered = layered.configure_legend(symbolType='diamond')
            alt.themes.register('customFont', _fontSettings(self._font))
            alt.themes.enable('customFont')
            return layered
        finally:
            del self[self.TRANSIENT]
def rooflines(neural_network: str) -> alt.vegalite.v4.api.Chart:
    """
    This function creates an Altair line chart with checkboxes. Creates a lot of them and then sums them up.
    
    Note: Checkbox with default does not work after first click. Please keep track of when this issue is solved with this link: https://github.com/vega/vega-lite/issues/4870
    
    Parameters
    ----------
        data: pd.DataFrame
            Dataframe from which the plot will be created.       
        neural_network:str
            neural network that will also be plotted besides all hardware platforms.
            Eg.:'imagenet|mnist|cifar'
                'imagenet'
     Returns
    -------
        Line Chart with checkboxes, all charts are summed up.          
    """
    maxX = 160000
    width = 700
    height = 500

    nn_df, hw_df = clean_csv_rooflines(
        path_topologies='data/cnn_topologies_compute_memory_requirements.csv',
        path_hardware='data/peakPerfBandHardPlatf.csv')

    #select data to be plotted according to user input
    if neural_network in 'imagenet':
        nn_df = nn_df[nn_df['Name'].str.contains(
            "GoogLeNetv1|MobileNetv1|ResNet|EfficientNet")]
    elif neural_network in 'cifar':
        nn_df = nn_df[nn_df['Name'].str.contains("CNV")]
    elif neural_network in 'mnist':
        nn_df = nn_df[nn_df['Name'].str.contains("MLP")]
    elif neural_network != 'imagenet|mnist|cifar':
        return 'There were no results for the neural network asked. Please insert another network'

    #regex expression replace for all MLPs because they overlapp in the plot because they have the same value for MLP100%,MLP50%..
    nn_df = util.replace_data_df(nn_df, 'Name', [('MLP 100%', 'MLP*'),
                                                 ('MLP 50%', 'MLP*'),
                                                 ('MLP 25%', 'MLP*'),
                                                 ('MLP 12.5%', 'MLP*')])
    nn_df = nn_df.drop_duplicates()

    #---------------Next part is to create all plots binded to checkboes-------------

    #Selecting data for each checkbox, from dataset. Each checkbox will be tied to each one of these data
    FPGA_data = hw_df[hw_df['Name'].str.contains("Ultra96 DPU|ZCU")]
    NVIDIA_data = hw_df[hw_df['Name'].str.contains("TX2")]
    GOOGLE_data = hw_df[hw_df['Name'].str.contains("EdgeTPU")]
    INTEL_data = hw_df[hw_df['Name'].str.contains("NCS")]

    INT2_data = nn_df[nn_df['Name'].str.contains("INT2")]
    INT4_data = nn_df[nn_df['Name'].str.contains("INT4")]
    INT8_data = nn_df[nn_df['Name'].str.contains("INT8")]
    FP16_data = nn_df[nn_df['Name'].str.contains("FP16")]
    FP32_data = nn_df[nn_df['Name'].str.contains("FP32")]

    #Stating that the binding type will be a checkbox
    filter_checkbox = alt.binding_checkbox()

    #To create all checkboxes with the specifications info for each set
    FPGA_select = alt.selection_single(fields=["Hide"],
                                       bind=filter_checkbox,
                                       name="FPGAs  Ultra96  DPU  ZCU  ")
    NVIDIA_select = alt.selection_single(
        fields=["Hide"],
        bind=filter_checkbox,
        name="INVIDIA  TX2  maxn, maxp, maxq  ")
    GOOGLE_select = alt.selection_single(fields=["Hide"],
                                         bind=filter_checkbox,
                                         name="GOOGLE  EdgeTPU, fast, slow  ")
    INTEL_select = alt.selection_single(fields=["Hide"],
                                        bind=filter_checkbox,
                                        name="INTEL  NCS  ")

    INT2_select = alt.selection_single(fields=["Hide"],
                                       bind=filter_checkbox,
                                       name="INT2")
    INT4_select = alt.selection_single(fields=["Hide"],
                                       bind=filter_checkbox,
                                       name="INT4")
    INT8_select = alt.selection_single(fields=["Hide"],
                                       bind=filter_checkbox,
                                       name="INT8")
    FP16_select = alt.selection_single(fields=["Hide"],
                                       bind=filter_checkbox,
                                       name="FP16")
    FP32_select = alt.selection_single(fields=["Hide"],
                                       bind=filter_checkbox,
                                       name="FP32")

    #Color Conditions for each plot
    FPGA_cond = alt.condition(FPGA_select, alt.Color("Name:N"),
                              alt.value("lightgray"))
    NVIDIA_cond = alt.condition(NVIDIA_select, alt.Color("Name:N"),
                                alt.value("lightgray"))
    GOOGLE_cond = alt.condition(GOOGLE_select, alt.Color("Name:N"),
                                alt.value("lightgray"))
    INTEL_cond = alt.condition(INTEL_select, alt.Color("Name:N"),
                               alt.value("lightgray"))

    INT2_cond = alt.condition(INT2_select, alt.Color("Name:N"),
                              alt.value("lightgray"))
    INT4_cond = alt.condition(INT4_select, alt.Color("Name:N"),
                              alt.value("lightgray"))
    INT8_cond = alt.condition(INT8_select, alt.Color("Name:N"),
                              alt.value("lightgray"))
    FP16_cond = alt.condition(FP16_select, alt.Color("Name:N"),
                              alt.value("lightgray"))
    FP32_cond = alt.condition(FP32_select, alt.Color("Name:N"),
                              alt.value("lightgray"))

    #Creating all plots
    FPGA_chart = line_chart_w_checkbox(FPGA_data, FPGA_cond, FPGA_select)
    NVIDIA_chart = line_chart_w_checkbox(NVIDIA_data, NVIDIA_cond,
                                         NVIDIA_select)
    GOOGLE_chart = line_chart_w_checkbox(GOOGLE_data, GOOGLE_cond,
                                         GOOGLE_select)
    INTEL_chart = line_chart_w_checkbox(INTEL_data, INTEL_cond, INTEL_select)

    INT2_chart = line_chart_w_checkbox(INT2_data, INT2_cond, INT2_select)
    INT4_chart = line_chart_w_checkbox(INT4_data, INT4_cond, INT4_select)
    INT8_chart = line_chart_w_checkbox(INT8_data, INT8_cond, INT8_select)
    FP16_chart = line_chart_w_checkbox(FP16_data, FP16_cond, FP16_select)
    FP32_chart = line_chart_w_checkbox(FP32_data, FP32_cond, FP32_select)

    #--------------------------------------------------------------------------------------------------
    # Create line plot
    line_chart = alt.Chart().mark_line(clip=True).interactive().encode(
        alt.X('arith_intens:Q'), alt.Y('performance:Q'),
        alt.Color('Name:N', legend=alt.Legend(columns=2)))

    #Create the selection which chooses nearest point on mouse hoover
    selection = alt.selection(type='single',
                              nearest=True,
                              on='mouseover',
                              fields=['arith_intens'])
    #to leave suggestions on, just replace arith_intens wiith anything else

    #Create text plot to show the text values on mouse hoovering
    text = (line_chart).mark_text(align='left', dx=3, dy=-3, clip=True).encode(
        text=alt.condition(selection, 'Name:N', alt.value(' ')))

    #Creates the points plot for the NNs. The points will be invisible
    selectors = alt.Chart().add_selection(selection).mark_point(
        clip=True).encode(
            alt.X('arith_intens:Q'),
            alt.Y('performance:Q'),
            opacity=alt.value(0),
        )

    chart_all = (pd.Series(
        [INT2_chart, INT4_chart, INT8_chart, FP16_chart, FP32_chart],
        name="charts")).to_frame()

    Chart = alt.layer(chart_all.charts.sum(numeric_only=False) + FPGA_chart +
                      NVIDIA_chart + GOOGLE_chart + INTEL_chart,
                      selectors,
                      text,
                      data=pd.concat([nn_df, hw_df]),
                      width=700,
                      height=500)

    return Chart