示例#1
0
 def encode_color(self):
     AltairChart.encode_color(self)
     self.add_text()
     # Setting tooltip as non-null
     self.chart = self.chart.configure_mark(
         tooltip=alt.TooltipContent("encoding"))
     self.code += f"""chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding'))"""
示例#2
0
    def initialize_chart(self):
        x_attr = self.view.get_attr_by_channel("x")[0]
        y_attr = self.view.get_attr_by_channel("y")[0]
        x_min = self.view.x_min_max[x_attr.attribute][0]
        x_max = self.view.x_min_max[x_attr.attribute][1]

        y_min = self.view.y_min_max[y_attr.attribute][0]
        y_max = self.view.y_min_max[y_attr.attribute][1]

        chart = alt.Chart(self.data).mark_circle().encode(
            x=alt.X(x_attr.attribute,
                    scale=alt.Scale(domain=(x_min, x_max)),
                    type=x_attr.data_type),
            y=alt.Y(y_attr.attribute,
                    scale=alt.Scale(domain=(y_min, y_max)),
                    type=y_attr.data_type))
        chart = chart.configure_mark(tooltip=alt.TooltipContent(
            'encoding'))  # Setting tooltip as non-null
        chart = chart.interactive()  # Enable Zooming and Panning

        #####################################
        ## Constructing Altair Code String ##
        #####################################

        self.code += "import altair as alt\n"
        dfname = "df"  # TODO: Placeholder (need to read dynamically via locals())
        self.code += f'''
		chart = alt.Chart({dfname}).mark_circle().encode(
		    x=alt.X('{x_attr.attribute}',scale=alt.Scale(domain=({x_min}, {x_max})),type='{x_attr.data_type}'),
		    y=alt.Y('{y_attr.attribute}',scale=alt.Scale(domain=({y_min}, {y_max})),type='{y_attr.data_type}')
		)
		chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding')) # Setting tooltip as non-null
		chart = chart.interactive() # Enable Zooming and Panning
		'''
        return chart
示例#3
0
文件: Heatmap.py 项目: ccubc/lux
	def initialize_chart(self):
		# return NotImplemented
		x_attr = self.vis.get_attr_by_channel("x")[0]
		y_attr = self.vis.get_attr_by_channel("y")[0]

		chart = alt.Chart(self.data).mark_rect().encode(
			x=alt.X('xBinStart', type='quantitative', axis=alt.Axis(title=x_attr.attribute), bin = alt.BinParams(binned=True)),
			x2=alt.X2('xBinEnd'),
			y=alt.Y('yBinStart', type='quantitative', axis=alt.Axis(title=y_attr.attribute), bin = alt.BinParams(binned=True)),
			y2=alt.Y2('yBinEnd'),
			opacity = alt.Opacity('count',type='quantitative',scale=alt.Scale(type="log"),legend=None)
		)
		chart = chart.configure_scale(minOpacity=0.1,maxOpacity=1) 
		chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding')) # Setting tooltip as non-null
		chart = chart.interactive() # Enable Zooming and Panning

		####################################
		# Constructing Altair Code String ##
		####################################
		
		self.code += "import altair as alt\n"
		# self.code += f"visData = pd.DataFrame({str(self.data.to_dict(orient='records'))})\n"
		self.code += f"visData = pd.DataFrame({str(self.data.to_dict())})\n"
		self.code += f'''
		chart = alt.Chart(visData).mark_rect().encode(
			x=alt.X('xBinStart', type='quantitative', axis=alt.Axis(title='{x_attr.attribute}'), bin = alt.BinParams(binned=True)),
			x2=alt.X2('xBinEnd'),
			y=alt.Y('yBinStart', type='quantitative', axis=alt.Axis(title='{y_attr.attribute}'), bin = alt.BinParams(binned=True)),
			y2=alt.Y2('yBinEnd'),
			opacity = alt.Opacity('count',type='quantitative',scale=alt.Scale(type="log"),legend=None)
		)
		chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding')) # Setting tooltip as non-null
		'''
		return chart 
示例#4
0
文件: BarChart.py 项目: ccubc/lux
 def encode_color(
     self
 ):  # override encode_color in AltairChart to enforce add_text occurs afterwards
     AltairChart.encode_color(self)
     self.add_text()
     self.chart = self.chart.configure_mark(tooltip=alt.TooltipContent(
         'encoding'))  # Setting tooltip as non-null
     self.code += f'''chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding'))'''
示例#5
0
    def initialize_chart(self):
        x_attr = self.vis.get_attr_by_channel("x")[0]
        y_attr = self.vis.get_attr_by_channel("y")[0]

        x_attr_abv = x_attr.attribute
        y_attr_abv = y_attr.attribute

        if len(x_attr.attribute) > 25:
            x_attr_abv = x_attr.attribute[:15] + "..." + x_attr.attribute[-10:]
        if len(y_attr.attribute) > 25:
            y_attr_abv = y_attr.attribute[:15] + "..." + y_attr.attribute[-10:]

        x_min = self.vis.min_max[x_attr.attribute][0]
        x_max = self.vis.min_max[x_attr.attribute][1]

        y_min = self.vis.min_max[y_attr.attribute][0]
        y_max = self.vis.min_max[y_attr.attribute][1]

        x_attr.attribute = x_attr.attribute.replace(".", "")
        y_attr.attribute = y_attr.attribute.replace(".", "")

        chart = (
            alt.Chart(self.data)
            .mark_circle()
            .encode(
                x=alt.X(
                    x_attr.attribute,
                    scale=alt.Scale(domain=(x_min, x_max)),
                    type=x_attr.data_type,
                    axis=alt.Axis(title=x_attr_abv),
                ),
                y=alt.Y(
                    y_attr.attribute,
                    scale=alt.Scale(domain=(y_min, y_max)),
                    type=y_attr.data_type,
                    axis=alt.Axis(title=y_attr_abv),
                ),
            )
        )
        # Setting tooltip as non-null
        chart = chart.configure_mark(tooltip=alt.TooltipContent("encoding"))
        chart = chart.interactive()  # Enable Zooming and Panning

        #####################################
        ## Constructing Altair Code String ##
        #####################################

        self.code += "import altair as alt\n"
        dfname = "placeholder_variable"
        self.code += f"""
		chart = alt.Chart({dfname}).mark_circle().encode(
		    x=alt.X('{x_attr.attribute}',scale=alt.Scale(domain=({x_min}, {x_max})),type='{x_attr.data_type}', axis=alt.Axis(title='{x_attr_abv}')),
		    y=alt.Y('{y_attr.attribute}',scale=alt.Scale(domain=({y_min}, {y_max})),type='{y_attr.data_type}', axis=alt.Axis(title='{y_attr_abv}'))
		)
		chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding')) # Setting tooltip as non-null
		chart = chart.interactive() # Enable Zooming and Panning
		"""
        return chart
示例#6
0
文件: BarChart.py 项目: smritim/lux
    def initialize_chart(self):
        self.tooltip = False
        x_attr = self.view.get_attr_by_channel("x")[0]
        y_attr = self.view.get_attr_by_channel("y")[0]

        self.code += "import altair as alt\n"
        # self.code += f"visData = pd.DataFrame({str(self.data.to_dict(orient='records'))})\n"
        self.code += f"visData = pd.DataFrame({str(self.data.to_dict())})\n"

        if (x_attr.data_model == "measure"):
            agg_title = get_agg_title(x_attr)
            y_attr_field = alt.Y(y_attr.attribute,
                                 type=y_attr.data_type,
                                 axis=alt.Axis(labelOverlap=True))
            x_attr_field = alt.X(x_attr.attribute,
                                 type=x_attr.data_type,
                                 title=agg_title)
            y_attr_field_code = f"alt.Y('{y_attr.attribute}', type= '{y_attr.data_type}', axis=alt.Axis(labelOverlap=True))"
            x_attr_field_code = f"alt.X('{x_attr.attribute}', type= '{x_attr.data_type}', title='{agg_title}')"

            if (y_attr.sort == "ascending"):
                y_attr_field.sort = "-x"
                y_attr_field_code = f"alt.Y('{y_attr.attribute}', type= '{y_attr.data_type}', axis=alt.Axis(labelOverlap=True), sort ='-x')"
        else:
            agg_title = get_agg_title(y_attr)
            x_attr_field = alt.X(x_attr.attribute,
                                 type=x_attr.data_type,
                                 axis=alt.Axis(labelOverlap=True))
            y_attr_field = alt.Y(y_attr.attribute,
                                 type=y_attr.data_type,
                                 title=agg_title)
            x_attr_field_code = f"alt.X('{x_attr.attribute}', type= '{x_attr.data_type}', axis=alt.Axis(labelOverlap=True))"
            y_attr_field_code = f"alt.Y('{y_attr.attribute}', type= '{y_attr.data_type}', title='{agg_title}')"
            if (x_attr.sort == "ascending"):
                x_attr_field.sort = "-y"
                x_attr_field_code = f"alt.X('{x_attr.attribute}', type= '{x_attr.data_type}', axis=alt.Axis(labelOverlap=True),sort='-y')"

        chart = alt.Chart(self.data).mark_bar().encode(y=y_attr_field,
                                                       x=x_attr_field)
        # TODO: tooltip messes up the count() bar charts
        # Can not do interactive whenever you have default count measure otherwise output strange error (Javascript Error: Cannot read property 'length' of undefined)
        #chart = chart.interactive() # If you want to enable Zooming and Panning
        chart = chart.configure_mark(tooltip=alt.TooltipContent(
            'encoding'))  # Setting tooltip as non-null

        self.code += f'''
		chart = alt.Chart(visData).mark_bar().encode(
		    y = {y_attr_field_code},
		    x = {x_attr_field_code},
		)
		chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding')) # Setting tooltip as non-null
		'''
        return chart
示例#7
0
    def plotAltairLineChart(self):
        """ Function to output Altair line chart

            Returns
            -------
                Altair line chart
        """
        
        # Date that will be used to indicate "Data as of user chosen date"
        iso_date = self.covid19_date.strftime('%Y-%m-%d')
        # Altair charting API only charts dataframe columns, not index, so need to apply reset_index()
        alt_chart = alt.Chart(self.dfByState()[:iso_date]
                     .query("State_Province in(@self.state_province)")
                     .reset_index()
                     .rename(columns={'index': 'Date'})
                    ).mark_line().encode(
                     x=alt.X(title='Date', field='Date', type='temporal'),
                     y=alt.Y(title='# of ' + self.confirmed_deaths, field='Qty_Confirmed', 
                             type='quantitative', scale=alt.Scale(type=self.ylog)
                            ),
                     color=alt.Color(field='State_Province', type='nominal',
                                     legend=alt.Legend(title="State/Province")
                                    ),
                     tooltip=[alt.Tooltip(field='State_Province', type= 'nominal'),
                              alt.Tooltip(field='Qty_Confirmed', type= 'quantitative'),
                              alt.Tooltip(field='Date', type= 'temporal')
                             ]
                    )

        # To create filled circles in the legend per
        # https://github.com/altair-viz/altair/issues/1206
        points = alt.Chart(self.dfByState()[:iso_date]
                  .query("State_Province in(@self.state_province)")
                  .reset_index()
                  .rename(columns={'index': 'Date'})
                 ).mark_circle(size=0).encode(
                                       color='State_Province'
                                      )

        # To add hover tips, but make it less sensitive per
        # https://github.com/altair-viz/altair/issues/1812
        tooltips = alt_chart.mark_point(size=100, opacity=0,
                    tooltip=alt.TooltipContent("data")
                   )

        alt_chart = alt_chart + points + tooltips

        return alt_chart.properties(
                title='COVID-19 ' + self.confirmed_deaths,
                width='container',
                height=400
               )
示例#8
0
    def initializeChart(self):
        # UP TO HERE: Broken because self.expandUnderspecified() in dataObj does not run when there are multiple object, we should not rely on spec
        # measures = list(filter(lambda x: x.dataModel=="measure" if hasattr(x,"dataModel") else False,self.dobj.spec))
        xAttr = self.dobj.getObjFromChannel("x")[0].columnName
        yAttr = self.dobj.getObjFromChannel("y")[0].columnName
        chart = alt.Chart(self.dataURL).mark_circle().encode(
            x=alt.X(xAttr, scale=alt.Scale(zero=False)),
            y=alt.Y(yAttr, scale=alt.Scale(zero=False)))
        chart = chart.configure_mark(tooltip=alt.TooltipContent(
            'encoding'))  # Setting tooltip as non-null
        chart = chart.interactive(
        )  # If you want to enable Zooming and Panning

        return chart
示例#9
0
def covid19TimeSeriesByCountry(covid19_date: Date,
                               confirmed_deaths: str,
                               country: List[str] = ['US'],
                               ylog: bool = False) -> PanelRow:
    """Function that returns a Panel dashboard displaying confirmed COVID-19 cases
    It is using Panel's "Reactive functions" API: https://panel.holoviz.org/user_guide/APIs.html
    Parameters
    ----------
    covid19_date : Date
        End date of data you wish to obtain up to
    country : List[str]
        One or more countries for which you would like to obtain data for (default='US')
    confirmed_deaths : str
        Option to choose # of confirmed cases or # of deaths from Covid-19
    ylog: bool
        Whether or not to apply log scaling to y-axis.  Default is False
    Returns
    -------
    Panel object
    """

    iso_date: str = covid19_date.strftime('%Y-%m-%d')

    # Source of COVID-19 data
    if confirmed_deaths == 'Confirmed Cases':
        url: str = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv'
    else:
        url: str = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_global.csv'
    df: DataFrame = pd.read_csv(url)

    df_countries: DataFrame = (df.drop(
        columns=['Province/State', 'Lat', 'Long']).groupby(
            'Country/Region').agg('sum').sort_values(
                by=df.columns[-1],
                ascending=False).transpose().reset_index().melt(
                    id_vars='index', value_name='Qty').rename(
                        columns={
                            'index': 'Date',
                            'Country/Region': 'Country_Region'
                        }).set_index('Date'))

    df_countries.index: DateTimeIndex = [
        datetime.strptime(date, '%m/%d/%y') for date in df_countries.index
    ]

    # Convert data to "wide format" since hvplot does not work with "long format"
    df_countries_wide = df_countries.pivot(columns='Country_Region',
                                           values='Qty')

    alt_chart: Altair = alt.Chart(df_countries[:iso_date].query(
        "Country_Region in(@country)").reset_index().rename(
            columns={'index': 'Date'})).mark_line().encode(
                x=alt.X(title='Date', field='Date', type='temporal'),
                y=alt.Y(title='# of ' + confirmed_deaths,
                        field='Qty',
                        type='quantitative',
                        scale=alt.Scale(type=ylog)),
                color=alt.Color(field='Country_Region',
                                type='nominal',
                                legend=alt.Legend(title="Country/Region")),
                tooltip=[
                    alt.Tooltip(field='Country_Region', type='nominal'),
                    alt.Tooltip(field='Qty', type='quantitative'),
                    alt.Tooltip(field='Date', type='temporal')
                ])
    # https://github.com/altair-viz/altair/issues/1812
    alt_chart: Altair = alt_chart + alt_chart.mark_point(
        size=100, opacity=0, tooltip=alt.TooltipContent("data"))

    # If only one country is selected, then also provide a data table containing counts by date
    if len(country) == 1:
        panel_app: PanelRow = pn.Row(
            # Add Altair chart
            alt_chart.properties(
                title='COVID-19 ' + confirmed_deaths,
                width=
                'container',  # Have to use 'container' option, otherwise, layout is 
                height=400),
            # Add hvplot table using data in wide format
            df_countries_wide[:iso_date].loc[:, country].sort_values(
                by=df_countries_wide[:iso_date].loc[:, country].columns[0],
                ascending=False
            ).merge(df_countries_wide[:iso_date].loc[:, country].sort_values(
                by=df_countries_wide[:iso_date].loc[:, country].columns[0],
                ascending=False).diff(),
                    how='inner',
                    left_index=True,
                    right_index=True).reset_index().rename(
                        columns={
                            'index': 'Date',
                            f'{country[0]}_x': 'Cum. Qty',
                            f'{country[0]}_y': 'Difference'
                        }).hvplot.table(sortable=True,
                                        selectable=True,
                                        width=300,
                                        height=500))
    # Else provide just the Altair line chart
    else:
        panel_app: PanelRow = pn.Row(
            alt_chart.properties(title='COVID-19 ' + confirmed_deaths,
                                 width=700,
                                 height=400))

    return panel_app
示例#10
0
	def initialize_chart(self):
		self.tooltip = False
		x_attr = self.vis.get_attr_by_channel("x")[0]
		y_attr = self.vis.get_attr_by_channel("y")[0]
		
		if (x_attr.data_model == "measure"):
			agg_title = get_agg_title(x_attr)
			measure_attr = x_attr.attribute
			y_attr_field = alt.Y(y_attr.attribute, type= y_attr.data_type, axis=alt.Axis(labelOverlap=True))
			x_attr_field = alt.X(x_attr.attribute, type= x_attr.data_type, title=agg_title)
			y_attr_field_code = f"alt.Y('{y_attr.attribute}', type= '{y_attr.data_type}', axis=alt.Axis(labelOverlap=True))"
			x_attr_field_code = f"alt.X('{x_attr.attribute}', type= '{x_attr.data_type}', title='{agg_title}')"

			if (y_attr.sort=="ascending"):
				y_attr_field.sort="-x"
				y_attr_field_code = f"alt.Y('{y_attr.attribute}', type= '{y_attr.data_type}', axis=alt.Axis(labelOverlap=True), sort ='-x')"
		else:
			agg_title = get_agg_title(y_attr)
			measure_attr = y_attr.attribute
			x_attr_field = alt.X(x_attr.attribute, type = x_attr.data_type,axis=alt.Axis(labelOverlap=True))
			y_attr_field = alt.Y(y_attr.attribute,type=y_attr.data_type,title=agg_title)
			x_attr_field_code = f"alt.X('{x_attr.attribute}', type= '{x_attr.data_type}', axis=alt.Axis(labelOverlap=True))"
			y_attr_field_code = f"alt.Y('{y_attr.attribute}', type= '{y_attr.data_type}', title='{agg_title}')"
			if (x_attr.sort=="ascending"):
				x_attr_field.sort="-y"
				x_attr_field_code = f"alt.X('{x_attr.attribute}', type= '{x_attr.data_type}', axis=alt.Axis(labelOverlap=True),sort='-y')"
		
		k=10
		topK_code = ""
		if len(self.data)>k: # Truncating to only top k
			remaining_bars = len(self.data)-k
			self.data = self.data.nlargest(k,measure_attr)
			text = alt.Chart(self.data).mark_text(
				x=155, 
				y=142,
				align="right",
				color = "#ff8e04",
				fontSize = 11,
				text=f"+ {remaining_bars} more ..."
			)

			topK_code = f'''text = alt.Chart(visData).mark_text(
			x=155, 
			y=142,
			align="right",
			color = "#ff8e04",
			fontSize = 11,
			text=f"+ {remaining_bars} more ..."
		)
		chart = chart + text
			'''
		
		chart = alt.Chart(self.data).mark_bar().encode(
			    y = y_attr_field,
			    x = x_attr_field
			)
		if (topK_code!=""):
			chart = chart + text
		# TODO: tooltip messes up the count() bar charts		
		# Can not do interactive whenever you have default count measure otherwise output strange error (Javascript Error: Cannot read property 'length' of undefined)
		#chart = chart.interactive() # If you want to enable Zooming and Panning
		chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding')) # Setting tooltip as non-null

		self.code += "import altair as alt\n"
		# self.code += f"visData = pd.DataFrame({str(self.data.to_dict(orient='records'))})\n"
		self.code += f"visData = pd.DataFrame({str(self.data.to_dict())})\n"
		self.code += f'''
		chart = alt.Chart(visData).mark_bar().encode(
		    y = {y_attr_field_code},
		    x = {x_attr_field_code},
		)
		{topK_code}
		chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding')) # Setting tooltip as non-null
		'''
		return chart 
示例#11
0
    def initialize_chart(self):
        # return NotImplemented
        x_attr = self.vis.get_attr_by_channel("x")[0]
        y_attr = self.vis.get_attr_by_channel("y")[0]

        x_attr_abv = str(x_attr.attribute)
        y_attr_abv = str(y_attr.attribute)

        if len(x_attr_abv) > 25:
            x_attr_abv = x_attr.attribute[:15] + "..." + x_attr.attribute[-10:]
        if len(y_attr_abv) > 25:
            y_attr_abv = y_attr.attribute[:15] + "..." + y_attr.attribute[-10:]

        if isinstance(x_attr.attribute, str):
            x_attr.attribute = x_attr.attribute.replace(".", "")
        if isinstance(y_attr.attribute, str):
            y_attr.attribute = y_attr.attribute.replace(".", "")

        chart = (alt.Chart(self.data).mark_rect().encode(
            x=alt.X(
                "xBinStart",
                type="quantitative",
                axis=alt.Axis(title=x_attr_abv),
                bin=alt.BinParams(binned=True),
            ),
            x2=alt.X2("xBinEnd"),
            y=alt.Y(
                "yBinStart",
                type="quantitative",
                axis=alt.Axis(title=y_attr_abv),
                bin=alt.BinParams(binned=True),
            ),
            y2=alt.Y2("yBinEnd"),
            opacity=alt.Opacity(
                "count",
                type="quantitative",
                scale=alt.Scale(type="log"),
                legend=None,
            ),
        ))
        chart = chart.configure_scale(minOpacity=0.1, maxOpacity=1)
        # Setting tooltip as non-null
        chart = chart.configure_mark(tooltip=alt.TooltipContent("encoding"))
        chart = chart.interactive()  # Enable Zooming and Panning

        ####################################
        # Constructing Altair Code String ##
        ####################################

        self.code += "import altair as alt\n"
        # self.code += f"visData = pd.DataFrame({str(self.data.to_dict(orient='records'))})\n"
        self.code += f"visData = pd.DataFrame({str(self.data.to_dict())})\n"
        self.code += f"""
		chart = alt.Chart(visData).mark_rect().encode(
			x=alt.X('xBinStart', type='quantitative', axis=alt.Axis(title='{x_attr_abv}'), bin = alt.BinParams(binned=True)),
			x2=alt.X2('xBinEnd'),
			y=alt.Y('yBinStart', type='quantitative', axis=alt.Axis(title='{y_attr_abv}'), bin = alt.BinParams(binned=True)),
			y2=alt.Y2('yBinEnd'),
			opacity = alt.Opacity('count',type='quantitative',scale=alt.Scale(type="log"),legend=None)
		)
		chart = chart.configure_mark(tooltip=alt.TooltipContent('encoding')) # Setting tooltip as non-null
		"""
        return chart
def covid19TimeSeriesByState(covid19_date: Date,
                             state_province: List[str],
                             confirmed_deaths: List[str],
                             ylog: bool = False) -> PanelColumn:
    """Function that returns a Panel dashboard displaying confirmed COVID-19 cases
    It is using Panel's "Reactive functions" API: https://panel.holoviz.org/user_guide/APIs.html
    Parameters
    ----------
    covid19_date : Date
        End date of data you wish to obtain up to
    state_province : str
        State for which you would like to obtain data for (default='Ohio')
    confirmed_deaths : str
        Option to choose # of confirmed cases or deaths due to COVID-19
    ylog : bool
        To enable log scaling or not on y-axis.  Log scale can be useful to easily discern growth rate.
    Returns
    -------
    Panel object
    """

    # Panel's date widget returns date in ISO-8601 format
    iso_date: str = covid19_date.strftime('%Y-%m-%d')

    # Get geo json data at state county level based on FIPS
    with urlopen(
            'https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json'
    ) as response:
        geo_data: dict = json.load(response)

    # Source of COVID-19 data
    # To leverage Plotly's choropleth_mapbox function, need to have FIPS as fixed length(n=5) values consisting of leading zeros
    if confirmed_deaths == 'Confirmed Cases':
        url: str = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_US.csv'
    else:
        url: str = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_US.csv'
    df: DataFrame = pd.read_csv(url,
                                converters={
                                    'FIPS':
                                    lambda x: int(float(x)) if x != '' else x
                                }).query("FIPS != ''")
    df['FIPS']: Series = df['FIPS'].astype('str').str.zfill(5)
    if 'Population' in df.columns:
        df.drop(columns='Population', inplace=True)

    df_by_state: DataFrame = (df.drop(columns=[
        'UID', 'iso2', 'iso3', 'code3', 'FIPS', 'Admin2', 'Country_Region',
        'Lat', 'Long_', 'Combined_Key'
    ]).groupby('Province_State').agg('sum').transpose().reset_index().melt(
        id_vars='index', var_name='State_Province',
        value_name='Qty_Confirmed').rename(columns={
            'index': 'Date'
        }).set_index('Date'))
    df_by_state.index: DateTimeIndex = [
        datetime.strptime(date, '%m/%d/%y') for date in df_by_state.index
    ]

    # Prepare data for hvplot tables
    # https://stackoverflow.com/questions/53052914/selecting-non-adjacent-columns-by-column-number-pandas
    df_by_state_ts: DataFrame = df.iloc[:, np.r_[6, 11:df.shape[1]]].groupby(
        'Province_State').agg('sum').transpose()
    df_by_counties: DataFrame = df.query("not Lat==0").iloc[:, [6, 10, -1]]

    # Prepare data for Plotly choropleth map
    df_choropleth: DataFrame = df.iloc[:, np.r_[4, 5, 6, df.shape[1] - 1]]
    df_choropleth: DataFrame = df_choropleth.rename(columns={
        df_choropleth.columns[3]: 'Confirmed_Cases',
        'Admin2': 'County'
    })

    # Initialize plotly choropleth map
    plotly_chart: Plotly = px.choropleth_mapbox(
        df_choropleth.query("Province_State in@state_province"),
        geojson=geo_data,
        locations='FIPS',
        color='Confirmed_Cases',
        color_discrete_map="Viridis",
        mapbox_style="carto-positron",
        zoom=3.5,
        center={
            "lat": 37.0902,
            "lon": -95.7129
        },
        opacity=0.5,
        hover_name='County',
        width=1400,
        height=700)
    plotly_chart.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})

    # Initialize altair chart
    alt_chart: Altair = alt.Chart(df_by_state[:iso_date].query(
        "State_Province in(@state_province)").reset_index().rename(
            columns={'index': 'Date'})).mark_line().encode(
                x=alt.X(title='Date', field='Date', type='temporal'),
                y=alt.Y(title='# of ' + confirmed_deaths,
                        field='Qty_Confirmed',
                        type='quantitative',
                        scale=alt.Scale(type=ylog)),
                color=alt.Color(field='State_Province',
                                type='nominal',
                                legend=alt.Legend(title="State/Province")),
                tooltip=[
                    alt.Tooltip(field='State_Province', type='nominal'),
                    alt.Tooltip(field='Qty_Confirmed', type='quantitative'),
                    alt.Tooltip(field='Date', type='temporal')
                ])
    # https://github.com/altair-viz/altair/issues/1812
    alt_chart: Altair = alt_chart + alt_chart.mark_point(
        size=100, opacity=0, tooltip=alt.TooltipContent("data"))

    # If only one state is selected, then also provide data tables containing counts by counties, by date, and counties choropleth map
    if len(state_province) == 1:
        # Layout the panel app such that the column will consist of a row of line chart, data table by counties, and data table by state
        # then a plotly choropleth below them
        panel_app: PanelColumn = pn.Column(
            pn.Row(
                # Add Altair line chart of cum. covid19 cases or deaths
                alt_chart.properties(
                    title='COVID-19 ' + confirmed_deaths,
                    width=
                    'container',  # Have to use 'container' option, otherwise, layout is 
                    height=400),
                # A data table of counts by counties
                df_by_counties.query(
                    "Province_State == @state_province").sort_values(
                        by=df_by_counties.columns[2], ascending=False).drop(
                            columns='Province_State', axis='columns').rename(
                                columns={
                                    'Combined_Key':
                                    'County',
                                    df_by_counties.columns[2]:
                                    'Qty as of ' + df_by_counties.columns[2]
                                }).hvplot.table(sortable=True,
                                                selectable=True,
                                                width=250,
                                                height=500),
                # A data table of counts by state with difference between rows
                (df_by_state_ts.loc[:,
                                    state_province].sort_values(
                                        by=state_province,
                                        ascending=False).rename(
                                            columns={
                                                'index': 'Date',
                                                state_province[0]: 'Cum. Qty'
                                            })
                 ).merge(
                     (df_by_state_ts.loc[:, state_province].sort_values(
                         by=state_province, ascending=False).rename(
                             columns={
                                 'index': 'Date',
                                 state_province[0]: 'Cum. Qty'
                             })).diff(),
                     how='inner',
                     left_index=True,
                     right_index=True).rename(columns={
                         'Cum. Qty_x': 'Cum. Qty',
                         'Cum. Qty_y': 'Difference'
                     }).reset_index().rename(columns={
                         'index': 'Date'
                     }).hvplot.table(sortable=True,
                                     selectable=True,
                                     width=300,
                                     height=500),
                width=1200,
                sizing_mode='stretch_width'),
            # A plotly choropleth Figure
            plotly_chart)
    # if more than one state is chosen, just provide Altair line chart, as it would not be feasible
    # to try to provide data tables and choropleth maps for several states
    else:
        panel_app: PanelColumn = pn.Column(
            pn.Row(
                # Add Altair line chart of cum. covid19 cases
                alt_chart.properties(title='COVID-19 ' + confirmed_deaths,
                                     width=700,
                                     height=400)))

    return panel_app
示例#13
0
    def plotAltairLineChart(self):
        """ Returns an Altair line chart.

            Returns
            -------
                An Altair line chart.
        """

        df = self.getData(self.confirmed_deaths)

        iso_date: str = self.covid19_date.strftime('%Y-%m-%d')

        # Altair requires dataframe to be in "long format"
        df_countries = (df.drop(columns=['Province/State', 'Lat', 'Long'])
                          .groupby('Country/Region').agg('sum')
                          .sort_values(by=df.columns[-1], ascending=False)
                          .transpose()
                          .reset_index()
                          .melt(id_vars='index', value_name='Qty')
                          .rename(columns={'index': 'Date',
                                   'Country/Region': 'Country_Region'
                                  }
                          )
                          .set_index('Date')
                       )

        # Make index values actual datetime objects so that we can
        # leverage Panda's date filtering API
        df_countries.index = [datetime.strptime(day, '%m/%d/%y')
                              for day in df_countries.index
                             ]
    
        alt_chart = alt.Chart(df_countries[: iso_date]
                              .query("Country_Region in(@self.country)")
                              .reset_index()
                              .rename(columns={'index': 'Date'})
                             ).mark_line().encode(
                              x=alt.X(title='Date', field='Date', type='temporal'),
                              y=alt.Y(title='# of ' + self.confirmed_deaths, field='Qty',
                               type='quantitative', scale=alt.Scale(type=self.ylog)
                              ),
                              color=alt.Color(field='Country_Region', type='nominal',
                               legend=alt.Legend(title="Country/Region")
                              ),
                              tooltip=[alt.Tooltip(field='Country_Region', type= 'nominal'),
                                       alt.Tooltip(field='Qty', type= 'quantitative'),
                                       alt.Tooltip(field='Date', type= 'temporal')
                                      ]
                            )
        # To create filled circles in the legend per
        # https://github.com/altair-viz/altair/issues/1206
        points = alt.Chart(df_countries[: iso_date]
                  .query("Country_Region in(@self.country)")
                  .reset_index()
                  .rename(columns={'index': 'Date'})
                 ).mark_circle(size=0).encode(
                                       color='Country_Region'
                                      )

        # To add hover tips, but make it less sensitive per
        # https://github.com/altair-viz/altair/issues/1812
        tooltips = alt_chart.mark_point(size=100, opacity=0,
                    tooltip=alt.TooltipContent("data")
                   )

        alt_chart = alt_chart + points + tooltips

        return alt_chart.properties(
                title='COVID-19 ' + self.confirmed_deaths,
                width='container',
                height=400
               )
    columns={
        0: "correlation",
        "level_0": "first",
        "level_1": "second"
    })

correlation_data["correlation_label"] = correlation_data["correlation"].map(
    "{:.2f}".format)

base_correlation_plot = altair.Chart(correlation_data).encode(x="second:O",
                                                              y="first:O")

# Text layer with correlation labels
# Colors are for easier readability
correlation_plot_text = base_correlation_plot.mark_text(
    tooltip=altair.TooltipContent("encoding")).encode(
        text="correlation_label",
        color=altair.condition(altair.datum.correlation > 0.5,
                               altair.value("white"), altair.value("black")))

correlation_plot = base_correlation_plot.mark_rect(
    tooltip=altair.TooltipContent("encoding")).encode(color=altair.Color(
        "correlation:Q",
        scale=altair.Scale(domain=[-1, 0, 1],
                           range=["DarkBlue", "White", "DarkRed"],
                           type="linear")))

CORRELATION_MATRIX = correlation_plot + correlation_plot_text

(CORRELATION_MATRIX_COLUMN,
 CORRELATION_OBSERVATION_COLUMN) = streamlit.columns([2, 1])