Search code examples
pythongoogle-colaboratorypygal

Customize PyGal WorldMap chart's tooltip


I'm using pygal for generate a world map chart in Google Colab.

The problem I'm facing is with the tooltip. I want to show only in the tooltip the name of the country and the number of videos found.

The result so far I've managed to get is as follows:

Worldmap chart current output:

Worldmap chart with tooltip

You can see there that the tooltip is composed as follows:

Country name

Number of videos

Country name: 1

Example:

United States

73 videos

Unites States: 1


Using the sample shown in the screenshot and in the sample above, what I want to get is

Example:

United States

73 videos

OR:

Example:

Unites States: 73 videos

Here is the Google Colab notebook sample I've created, so anyone can reproduce this issue.

This is the Worldmap chart settings:

# Save chart as svg: 
worldmap_chart.render_to_file('worldmap_result.svg', 
                              show_legend=True, 
                              human_readable=True, 
                              fill=True, 
                              print_labels=True, 
                              no_data_text="No data available", 
                              legend_at_bottom=True, 
                              pretty_print=True,
                              x_title="Hover the cursor on the country's name bellow or the map above:",
                              print_values=True, 
                              force_uri_protocol='https')

I've readed the documentation and searched, but, I'm not been able to find the correct configuration (if possible) for generate the expected tooltip.

Does anyone knows what I'm missing?


Solution

  • After testing for a few more hours, I finally decided to follow these steps:

    • Generate/render the world chart in a file - in this case, a .svg file.
    • Read the generated file in the previous step, find and replace certain svg tags - those that contains the data I don't want in the final chart.
    • Download the modified file.

    The said svg tags are as follows:

    Example:

    <desc class="value">Russian Federation: 1</desc>
    

    Thanks to this answer, I was able to replace the svg tags and leave them empty. With that change, I was able to generate the world map chart as I required.

    This is the full, modified and working code:

    import types
    # Library import:
    from pygal_maps_world.maps import World
    from pygal.style import DefaultStyle
    
    worldmap_chart = World()
    worldmap_chart.title = 'Channels distribution per country'
    
    #list - source: https://stackoverflow.com/a/26716774/12511801
    # Excludes "N/A" values: 
    countriesData = df_countries.loc[df_countries['Country (channel)'] != "N/A"].to_dict('split')["data"]
    
    # Loop the "countriesData" and replace the name of the country 
    # with is ISO code - lowercase - in order to render the world map: 
    for x in countriesData: 
      countryName = x[0]
      countryName = [x["id"].lower() for x in all_countries if x["name"] == countryName][0]
      x[0] = countryName
    
    # Strings to replace:
    js_strings = []
    
    # Generate world map chart: 
    #worldmap_chart.add('Countries', dict(countriesData))
    for data in countriesData: 
      countryFound = [x["name"] for x in all_countries if x["id"].lower() == data[0]]
      if (len(countryFound) > 0): 
        countryFound = countryFound[0]
        worldmap_chart.add(countryFound, [{"value": data[0], "label" : (str(data[1]) + " video" + ("s" if data[1] != 1 else ""))}])
        js_strings.append('<desc class="value">{0}: 1</desc>'.format(countryFound))
    
    # Save chart as svg - comment this line for print the chart in this notebook: 
    worldmap_chart.render_to_file('chart_final_4.svg', 
                                  show_legend=True, 
                                  human_readable=True, 
                                  fill=True, 
                                  print_labels=True, 
                                  no_data_text="No data available", 
                                  legend_at_bottom=True, 
                                  pretty_print=True,
                                  x_title="Hover the cursor on the country's name bellow or the map above:",
                                  print_values=True)
    print("Chart saved in local storage - see file (chart_final_4.svg).")
    
    # Render the chart in the notebook:
    HTML_worldChart = str(worldmap_chart.render(show_legend=True, human_readable=True, 
                                            fill=True, print_labels=True, 
                                            no_data_text="No data available", 
                                            legend_at_bottom=True, 
                                            print_values=True, style=DefaultStyle(value_font_family='googlefont:Raleway',
                                                                                  value_font_size=30,
                                                                                  value_colors=('white',))))
    
    
    # Source: https://stackoverflow.com/a/62008698/12511801
    from pathlib import Path
    file = Path("chart_final_4.svg")
    
    # Replace specific, conflicting countries by name:
    file.write_text(file.read_text().replace('<desc class="value">Korea, Republic of: 1</desc>', '<desc class="value"></desc>'))
    file.write_text(file.read_text().replace('<desc class="value">Russian Federation: 1</desc>', '<desc class="value"></desc>'))
    file.write_text(file.read_text().replace('<desc class="value">Viet Nam: 1</desc>', '<desc class="value"></desc>'))
    
    ## This is due those countries are arranged as follows: 
    ##--country (<desc class="value">Russia: 1</desc>) no detected
    ##--country (<desc class="value">Vietnam: 1</desc>) no detected
    ##--country (<desc class="value">South Korea: 1</desc>) no detected
    
    # Loop the strings to replace: 
    for country in js_strings:
      file.write_text(file.read_text().replace(country, '<desc class="value"></desc>'))
    
    print("(chart_final_4.svg) has been modified.")
    

    Output: world map chart modified - I'm modified the screenshot for include two tooltips at the same time.

    Final world map chart modified


    Side note: it might not be the best way, but, for a lack of time and knowledge, I've decided to leave it as is. I'm open to any, better suggestions.