{"id":23478,"date":"2023-04-09T13:21:53","date_gmt":"2023-04-09T13:21:53","guid":{"rendered":"https:\/\/www.highcharts.com\/blog\/?p=23478"},"modified":"2026-01-13T11:30:12","modified_gmt":"2026-01-13T11:30:12","slug":"highcharts-python-pandas-pyspark","status":"publish","type":"post","link":"https:\/\/www.highcharts.com\/blog\/integration\/highcharts-python-pandas-pyspark\/","title":{"rendered":"Using Highcharts for Python with Pandas and PySpark"},"content":{"rendered":"<p><a href=\"https:\/\/www.highcharts.com\" target=\"_blank\" rel=\"noopener\">Highcharts Core<\/a>\u00a0is the gold standard in JavaScript data visualization, offering far more customizability and interactivity out-of-the-box than \u201cmere\u201d plotting libraries. And using the <a href=\"https:\/\/github.com\/highcharts-for-python\" target=\"_blank\" rel=\"noopener\">Highcharts for Python Toolkit<\/a>, you can now easily use it in your Python code (or even in your Jupyter notebook), and rapidly visualize data that you have loaded into a Pandas or PySpark <b>DataFrame<\/b>.<\/p>\n<p><i><b>Tip<\/b><br \/>\nThe Highcharts for Python capabilities are quite extensive, and this tutorial is meant to be a quick intro to using Highcharts for Python with Pandas and PySpark. But we definitely recommend that you review our other tutorials to see more detail on how you can enrich your data visualizations using Highcharts for Python and Highcharts Core.<\/i><\/p>\n<h2>Getting Started with Highcharts for Python<\/h2>\n<p>To use Highcharts for Python, like with any Python library, you first have to install it. That\u2019s super easy. Just open your project (in your virtual environment \u2013 you are using virtual environments, right?) and execute:<\/p>\n<pre>$ pip install highcharts-core<\/pre>\n<p>And that\u2019s it Highcharts for Python will now be\u00a0in stalled in\u00a0your\u00a0project and available for use. To use it in your\u00a0code, you just have to import it the way you would any other library.<\/p>\n<h2>Importing Highcharts for Python<\/h2>\n<p>The Highcharts for Python library is quite extensive. It\u2019s got a rich (read: complicated) API, with lots of different objects and modules. That\u2019s a reflection of the visualization power that Highcharts offers you, but it does make the decision of what to import and how to import it a little more complicated.<\/p>\n<p>Python\u2019s best practice is to import only what you need, which helps to maximize the performance of your Python code and prevents your application\u2019s namespace from getting cluttered with various things (and further reduces the memory footprint of your Python code, which is always good).<\/p>\n<p>You can either import specific things from their precise locations, or you can also just import the catch-all highcharts module, which flattens the entire API and exposes just about every class\/object in one location. We definitely recommend importing things from their precise location like so:<\/p>\n<pre># Import classes using precise module indications. For example:\r\nfrom highcharts_core.chart import Chart\r\nfrom highcharts_core.options import HighchartsOptions\r\nfrom highcharts_core.options.plot_options.scatter import ScatterOptions\r\nfrom highcharts_core.options.series.scatter import ScatterSeries<\/pre>\n<h2>A Super Simple Example<\/h2>\n<p>So, let\u2019s assume that you are merely analyzing a bunch of data. You have extracted it from the underlying data files or database, loaded it up into a Pandas or PySpark <b>DataFrame<\/b>, and performed whatever calculations you want to perform on your dataset. While Pandas and PySpark are two different libraries, the way that Highcharts for Python visualizes data from either is extremely similar.<\/p>\n<p>Let\u2019s assume you have your data stored in a DataFrame called <code>df<\/code> (creative, right?). And let\u2019s further assume that you have two columns with the data that you want to plot: one labeled <code>actual<\/code> and one labeled <code>forecast<\/code>. As you can probably guess, we want to plot the forecast against the actuals across the observations in our dataset to better evaluate fit.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-23564 aligncenter\" src=\"https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2023\/04\/04195433\/jupyter-notebook-screenshot-560x328.jpg\" alt=\"Image of a dataframe with the structure from a jupyter notebook\" width=\"560\" height=\"328\" srcset=\"https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2023\/04\/04195433\/jupyter-notebook-screenshot-560x328.jpg 560w, https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2023\/04\/04195433\/jupyter-notebook-screenshot-760x446.jpg 760w, https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2023\/04\/04195433\/jupyter-notebook-screenshot-768x450.jpg 768w, https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2023\/04\/04195433\/jupyter-notebook-screenshot.jpg 1160w\" sizes=\"auto, (max-width: 560px) 100vw, 560px\" \/><\/p>\n<p>The process of doing this is very simple:<\/p>\n<ol>\n<li>Import the <code>Chart<\/code> type from <code>highcharts_core.chart<\/code> and the <code>ScatterSeries<\/code> type from <code>highcharts_core.options.series.scatter<\/code>:\n<pre>from highcharts_core.chart import Chart\r\nfrom highcharts_core.options.series.scatter import ScatterSeries<\/pre>\n<\/li>\n<li>Create your two series \u2013 one for <code>actual<\/code> and one for <code>forecast<\/code> \u2013 using the <code>ScatterSeries.from_pandas()<\/code> or <code>ScatterSeries.from_pyspark()<\/code> class method, which will create new <code>ScatterSeries<\/code> instances:\n<pre>from highcharts_core.options.series.scatter\r\nimport ScatterSeries\r\n# Create a new ScatterSeries instance plotting df['actual']\r\nactual_series = ScatterSeries.from_pandas(df,\r\n  property_map = {\r\n    'x': 'idx',\r\n    'y': 'actual',\r\n    'id': 'actual',\r\n    'name': 'Observed Value for Metric'\r\n  },\r\n  series_type = 'scatter'\r\n)\r\n# Create a new ScatterSeries instance plotting df['forecast']\r\nactual_series = ScatterSeries.from_pandas(df,\r\n    property_map = {\r\n      'x': 'idx',\r\n      'y': 'forecast',\r\n      'id': 'forecast',\r\n      'name': 'Forecast Value for Metric'\r\n    }\r\n)<\/pre>\n<\/li>\n<li>Create a <code>Chart<\/code> instance and add your two series to it.\n<pre># Create a Chart and add your two series to the chart.\r\nmy_chart = Chart.from_series(actual_series, forecast_series)\r\n<\/pre>\n<\/li>\n<\/ol>\n<p>And that\u2019s it! Let\u2019s breakdown what\u2019s happening in the method calls above:<\/p>\n<p>First, you\u2019re telling the <code>ScatterSeries.from_pandas()<\/code> method which dataframe to use, in this case, <code>df.<\/code> That\u2019s pretty straightforward. But the magic really happens in the <code>property_map argument<\/code>, which tells the method which <code>DataFrame<\/code> columns correspond to which properties in the series\u2019 data points.<\/p>\n<p>And then, once your series are created, you create a chart that contains those two series by calling <code>Chart.from_series()<\/code>.<\/p>\n<h2>The property_map Argument<\/h2>\n<p>The <code>property_map<\/code> argument takes a <code>dict<\/code> whose keys correspond to the properties in the series type\u2019s <code>.data<\/code> property. That can seem a little complicated, but think of it this way:<br \/>\nThe Highcharts for Python toolkit supports over 70 different series types in its visualization. Different series types may have different properties for their data points. Some (like the <code>ScatterSeries<\/code> shown above) may be very simple: they get an <code>\u201cx\u201d<\/code> value for the <code>x-axis<\/code>, and a <code>\u201cy\u201d<\/code> value for the <code>y-axis<\/code>, and an <code>\u201cid\u201d<\/code> that uniquely identifies the data point.<br \/>\nThe keys in <code>property_map<\/code> are the data point properties that should be populated. In the example above:<\/p>\n<ol>\n<li>The <code>\u201cx\u201d<\/code> key corresponds to the data point\u2019s <code>.x<\/code> property \u2013 which in this case gets populated using the column labeled <code>'idx'<\/code> in the DataFrame<\/li>\n<li>The <code>\u201cy\u201d<\/code> key corresponds to the data point\u2019s <code>.y<\/code> property \u2013 which in this case gets populated using the column labeled <code>'actual'<\/code> for the actual series, and <code>'forecast'<\/code> for the forecast series.<\/li>\n<li>The <code>\u201cid\u201d<\/code> key corresponds to the data point\u2019s .id property, which in this case will be given the same <code>ID<\/code> as the original column label, and<br \/>\nThe <code>\u201cname\u201d<\/code> key corresponds to the data point\u2019s <code>.name<\/code> property, which in this case gives each series a label that will be shown in the visualization\u2019s legend.<\/li>\n<\/ol>\n<p>So the <code>property_map<\/code> argument tells Highcharts for Python which <code>DataFrame<\/code> column maps to which property. Pretty straightforward!<\/p>\n<p><i><b>Tip<\/b><br \/>\nIf you use convenience methods like <code>.from_pandas()<\/code> or <code>.from_pyspark()<\/code> make sure to review the series type\u2019s data points to map your data to the appropriate properties. You can do so in the extensive <a href=\"https:\/\/core-docs.highchartspython.com\/en\/latest\/api.html\" target=\"_blank\" rel=\"noopener\">API reference<\/a> for the series type you want to chart.<\/i><\/p>\n<h2>Tapping Into Richer Functionality<\/h2>\n<p>The <code>.from_pandas()<\/code> and <code>.from_pyspark()<\/code> methods also accept a <code>series_kwargs<\/code> argument, which expects a dict whose keys are keyword parameters that you can use when instantiating the series. Those parameters can be used to further customize how the series gets rendered, including indicating the axis it should be rendered on, adjusting its interactivity, or more. For more details, please see the extensive <a href=\"https:\/\/core-docs.highchartspython.com\/en\/latest\/api.html\" target=\"_blank\" rel=\"noopener\">API reference<\/a> documentation for the series types you wish to visualize.<\/p>\n<h2>Other Approaches<\/h2>\n<p>The example above focuses on using a <code>DataFrame<\/code>, but Highcharts for Python has you covered regardless of how you are managing your data. You have similar convenience functions for loading data:<\/p>\n<ul>\n<li>.from_csv() which loads data from a CSV file, and<\/li>\n<li>.from_array() which loads data from an iterable<\/li>\n<\/ul>\n<p>Every single series type available offers these convenience functions, but you can also call <code>.from_pandas()<\/code>, <code>.from_pyspark()<\/code>, and <code>.from_csv()<\/code> on the <code>Chart<\/code> class itself if you wish to just visualize one data series.<\/p>\n<p>And if you wish to add more series to an existing chart instance? You can do that easily by just submitting them to that chart instance\u2019s <code>.add_series()<\/code> method. You can also update existing series by calling the chart instance\u2019s <code>.update_series()<\/code> method.<\/p>\n<p><i><b>Tip<\/b><br \/>\nOur other tutorials show you in detail how to use these different convenience methods to rapidly build great visualizations \u2013 we recommend you check them out here: <b>Highcharts for Python Tutorials<\/b>.<\/i><\/p>\n<p>And that\u2019s it! You now have a fully-configured <code>Chart<\/code> instance containing the data from your <code>DataFrame<\/code>. We\u2019ll describe how to actually use this <code>Chart<\/code> instance down below.<\/p>\n<h2>Visualizing Your Chart<\/h2>\n<p>Now that we\u2019ve built a <code>Chart<\/code> instance and populated it with data, our next step is to visualize it. How you actually do this depends to some extent on how you are building your Python application. There are generally two ways to visualize your data:<\/p>\n<h3>In Jupyter Labs\/Notebook<\/h3>\n<p>If you are working in Jupyter Labs\/Notebook, there\u2019s nothing simpler. You can visualize your data by calling <code>my_chart.display()<\/code>. And that\u2019s it! When you run that notebook cell, your chart will get visualized.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-23565 aligncenter\" src=\"https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2023\/04\/04195716\/pandas-dataframe-screenshot-560x334.jpg\" alt=\"Screenshot of notebook\" width=\"560\" height=\"334\" srcset=\"https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2023\/04\/04195716\/pandas-dataframe-screenshot-560x334.jpg 560w, https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2023\/04\/04195716\/pandas-dataframe-screenshot.jpg 705w\" sizes=\"auto, (max-width: 560px) 100vw, 560px\" \/><\/p>\n<h3>In a Web Application<\/h3>\n<p>If you are building a web application, you may be using a web framework like Flask, Django, or FastAPI and relying on their templating engines for creating your views. Or maybe you are providing a Python backend API that delivers data to an entirely separate app via RESTful API calls. In either case, to visualize your new chart you need to somehow get its configuration to your web-based front-end. And that is super simple as well.<\/p>\n<p>Using the example above, you can generate the full set of HTML and JavaScript content to render your chart with one method call:<\/p>\n<pre>as_js_literal = my_chart.to_js_literal()\r\n# This will produce a string equivalent to:\r\n#\r\n# document.addEventListener('DOMContentLoaded', function() {\r\n#   const myChart = Highcharts.chart('target_div', {\r\n#      series: {\r\n#          type: 'scatter',\r\n#          data: [0, 5, 3, 5]\r\n#      }\r\n#   });\r\n# });<\/pre>\n<p>So what is this method call doing? It is taking the entire set of instructions included in your <code>my_chart<\/code> variable, creating a JavaScript literal string that represents them, and putting that string in the <code>as_js_literal<\/code> Python variable. This string can then be piped into your web front end using whatever templating engine you are using, or delivered to your front-end in an API response, and it will then render your chart as you configured it.<\/p>\n<p>In the example above, if you place the <code>as_js_literal<\/code> string in what gets rendered in your user\u2019s browser, your chart will be automatically rendered by Highcharts Core, placing the chart inside the div element in your content whose id is <code>\u201ctarget_div\u201d<\/code>.<\/p>\n<p>And that\u2019s it! You should now see a beautiful line chart in your web content.<\/p>\n<h3>Downloading Your Chart<\/h3>\n<p>Often when you\u2019ve created a visualization, you may want to download a static version of it as an image that can be embedded in other documents. With Highcharts for Python, that is a fairly trivial exercise. Given the example above, you can produce a PNG image very simply with one method call:<\/p>\n<pre># Download a PNG version of the chart in memory within your Python code.\r\nmy_png_image = my_chart.download_chart(format = 'png')\r\n# Download a PNG version of the chart and save it the file \"\/images\/my-chart-file.png\"\r\nmy_png_image = my_chart.download_chart(\r\n    format = 'png',\r\n    filename = '\/images\/my-chart-file.png'\r\n)<\/pre>\n<p>The two examples shown above both download a PNG of your chart:<br \/>\nThe first example keeps that PNG image in your Python code only, storing its binary data in the <code>my_png_image<\/code> variable. The second example not only stores its binary data in the <code>my_png_image<\/code> variable, but it also saves the PNG image to the file <code>\u201c\/images\/my-chart-file.png\u201d<\/code>.<\/p>\n<p>The <code>format<\/code> argument is really the one doing the heavy lifting above. In the example above, it tells the method to generate a PNG image, but you can also create <code>\u201cjpeg\u201d<\/code>, <code>\u201cpdf\u201d<\/code>, and <code>\u201csvg\u201d<\/code>.<\/p>\n<p>And that\u2019s it! You should know that the <code>.download_chart()<\/code> method defaults to using the Highcharts Export Server provided by Highsoft (creators of <a href=\"https:\/\/www.highcharts.com\" target=\"_blank\" rel=\"noopener\">Highcharts Core<\/a>), however you can configure the method to use your own custom <a href=\"https:\/\/www.highcharts.com\/docs\/export-module\/setting-up-the-server\" target=\"_blank\" rel=\"noopener\">Highcharts Export Server<\/a> if you choose. For more details on how to do this, please review our tutorial on <a href=\"https:\/\/www.highcharts.com\/blog\/tutorials\/exporting-static-charts-highcharts-python\" target=\"_blank\" rel=\"noopener\">Exporting Static Charts using Highcharts for Python<\/a>.<\/p>\n<h2>More Resources<\/h2>\n<p>The above tutorial is just a really simple example of how you can create rich visualizations with just a handful of method calls using Highcharts for Python. But the library offers so much more! We recommend you take a look at the following additional resources which you may find useful:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.highcharts.com\/blog\/tutorials\/using-highcharts-for-python-basic-tutorial\" target=\"_blank\" rel=\"noopener\">Highcharts for Python: Tutorials<\/a><\/li>\n<li><a href=\"https:\/\/www.highcharts.com\/blog\/tutorials\/exporting-static-charts-highcharts-python\" target=\"blank\" rel=\"noopener\">Exporting Static Charts Using Highcharts for Python<\/a><\/li>\n<li><a href=\"https:\/\/www.highcharts.com\/blog\/tutorials\/templating-and-shared-options-highcharts-python\" target=\"_blank\" rel=\"noopener\">Using Templating and Shared Options in Highcharts for Python <\/a><\/li>\n<li><a href=\"https:\/\/maps-docs.highchartspython.com\/en\/latest\/\" target=\"_blank\" rel=\"noopener\"> Highcharts for Python: API Reference Documentation<\/a><\/li>\n<\/ul>\n<h2><strong>Related posts<\/strong><\/h2>\n<ul>\n<li style=\"margin-left: 20px; margin-bottom: 20px;\"><a href=\"https:\/\/www.highcharts.com\/blog\/inspirations\/highcharts-dashboards-with-react\/\">Highcharts Dashboards with React<\/a><\/li>\n<li style=\"margin-left: 20px; margin-bottom: 20px;\"><a href=\"https:\/\/www.highcharts.com\/blog\/inspirations\/highcharts-dashboards-with-vue\/\">Highcharts Dashboards with Vue<\/a><\/li>\n<li style=\"margin-left: 20px; margin-bottom: 20px;\"><a href=\"https:\/\/www.highcharts.com\/blog\/inspirations\/highcharts-dashboards-with-angular\/\">Highcharts Dashboards with Angular<\/a><\/li>\n<li style=\"margin-left: 20px; margin-bottom: 20px;\"><a href=\"https:\/\/www.highcharts.com\/blog\/inspirations\/highcharts-dashboards-with-python\/\">Highcharts Dashboards with Python<\/a><\/li>\n<li style=\"margin-left: 20px; margin-bottom: 20px;\"><a href=\"https:\/\/www.highcharts.com\/blog\/dashboards\/dashboard-examples-using-highcharts-dashboards\/\">Dashboard examples using Highcharts\u00ae Dashboards<\/a><\/li>\n<li style=\"margin-left: 20px; margin-bottom: 20px;\"><a href=\"https:\/\/www.highcharts.com\/blog\/inspirations\/javascript-dashboards-with-highcharts\/\">JavaScript dashboards with Highcharts<\/a><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A step-by-step tutorial to learn how to use Highcharts for Python with Pandas and PySpark<\/p>\n","protected":false},"author":273,"featured_media":23721,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"meta_title":"","meta_description":"","hc_selected_options":[],"footnotes":""},"categories":[1105],"tags":[1094,885],"coauthors":[983],"class_list":["post-23478","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-integration","tag-highcharts-core","tag-python"],"_links":{"self":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/23478","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/users\/273"}],"replies":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/comments?post=23478"}],"version-history":[{"count":2,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/23478\/revisions"}],"predecessor-version":[{"id":26014,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/23478\/revisions\/26014"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/media\/23721"}],"wp:attachment":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/media?parent=23478"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/categories?post=23478"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/tags?post=23478"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/coauthors?post=23478"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}